Device won't handshake with nerves-hub using nerves_hub_link

SSL is passed down to Erlang and handled there as part of the connection attempts. If you want more logging, pass log_level: :debug to the SSL options. Either in your configurator or config like:

config :nerves_hub_link, ssl: [log_level: :debug]

This is also one of the crux that makes debugging SSL so hard. NervesHubLink just has no way to know why SSL is failing. It just fails, and minimal logs are put out (or I don’t know how to get more info here)

Application.get_env(:nerves_hub_link, :ca_certs) is definitely the issue here. It being empty will cause the server to reject any requests. You need all the NervesHub intermediate CA’s plus your signer CA. Also, using this Application config is sort of my convention because I do a lot of SSL cert swapping/testing locally, but its sort of a poor example. For you, I would recommend removing an ca_certs values from your configs. Then change your configurator line to reference already included CA certs:

- [signer_der | cacerts()]
+ [signer_der | NervesHubLink.Certificate.ca_certs()]

I’ve also updated the docs for this

You don’t need to do this. On first successful connect, the device cert will be added to the device in NervesHub. This is part of the pattern of client-side SSL.

NervesHub uses both Server side SSL and Client side SSL. In a typical server setup, the client requests data from a Server and the client decides if it trusts the server by referencing the CAs/intermediates given from the server with what the client trusts.

For client side, flip that around. You device is attempting the connection and is saying the Server must verify the device connection as well. So in this flip, the server needs to decide if it trusts this incoming device by checking its CA against what it allows (which is why you must register the device signer CA). But you also still need all the intermediates from NervesHub for the typical server->client connection checks as well.

Here’s a little visual breakdown of what is needed in the cacerts of the request:

[
  device_signer_ca, # For Client -> Server (client-side SSL)
  NervesHub-root-ca, # For Server -> Client  (server-side SSL)
  NervesHub-server-ca, # For Server -> Client  (server-side SSL)
  NervesHub-device-ca, # For Server -> Client  (server-side SSL)
]