LabVIEW-Open-Source/MQTT-Client

Trouble connecting to Google IoT Core - Network connection refused by server

Hero-Engineering opened this issue · 5 comments

Hello! I'm trying to connect the published client to Google IoT Core and getting a TCP Open (Error 63) after Connect to Server (network connection refused by server, serial buffer overflow). I'm probably doing something wring in configuring the TCP.

Please see sample screenshot of VI attached. I've verified that my credentials (device private key, CA authority) work on a sample mqtt client provided by the Google IoT Core team.

For reference, I'm following this quick start guide from Google IoT Core: https://cloud.google.com/iot/docs/create-device-registry
It involves creating a device key pair (rsa_private.pem for the private key, rsa_cert.pem for public key), and downloading Google's CA (roots.pem). The public key information is shared with Google IoT Core, then we set up some topics such that commands can be sent. The sample mqtt client provided by Google can be found here: git clone https://github.com/googleapis/nodejs-iot.git

Here are potential areas of concern that might be causing the error

  1. In Secured TCP Client.vi, I'm unsure what to put for the input named "address", so I've left it blank. The hostname is: "mqtt.googleapis.com", the port is 8883, and the Server X.509 certificate is pointed towards roots.pem. Also, not sure what read mode to configure - or if this has any effect

  2. Do we need the "Configure Secured TCP Client Certificate and Key VI"? From the sample mqtt client provided by Google, the client authenticates with a username - "unused", and a JWT signed by the client private key. I submit this information in the "Connect To Server" VI.

  3. Do we need to establish the topic in the payload variable of "Connect To Server", or can we do it after the server has connected? I presume the latter.

Any help would be much appreciated! Thanks!

image

@Hero-Engineering

I think you are correct in your assessment that 1) is wrongly configured.

  • The address is where you connect to, so leaving it blank will call "localhost". For IoT services, the address is the target URI for the service (ex: google.com, etc.)
  • The hostname is generally the same as the address, unless specified to be somewhat shorter. The hostname is used to validate that the certificate is used to connect only to the server it was created for. i.e you cannot use a certificate for google.com if you connect to amazonaws.com
  • The ClientID depends on the service. For AWS, it is the "IoT Thing" identifier, which is given in the aws dashboard where I create the certificate/private key.

AWS does not require any username/password combo, but the way you specify it seems fine with respect to username/JWToken.

Here is a screenshot of the configuration used for AWS IoT Core:
image

You'll notice that the first configuration VI is for the Server config. That's where you set the URI, the root/server certificate along with one of the hostnames associated with this certificate (usually the same as the URI). You use this node to configure how the client authenticates the server.

The second configuration VI is for the client. This is needed ONLY if the server needs to authenticate the clients (and prevent any unauthorized client from connecting in the first place). To do that, you need the client's certificate (public key that the server uses to validate the signed request) and the client's private key which the client uses to encrypt message. It seems that Google IoT at least accepts that the user could supply a JSON Web token instead of authenticating with a private key. In this case, I don't think you would need the second config VI.

EDIT: For anyone reading this thread, the Secured TCP Connection library (LV2020+) is a pre-requisite extension to connect using LabVIEW's native TLS. https://github.com/LabVIEW-Open-Source/MQTT-Connection-SecuredTCP

If you are creating a certificate and private key for your IoT device, I would be surprised if you need a username/token... But I can be wrong. I have not gone through the doc you referenced for Google Cloud.

EDIT:

You already have those correctly setup, but for documentation purpose, here there are some more pointers.

  • Google Root Certificate is here: https://pki.goog/roots.pem

  • The clientID seems to be of this format (java example on the link you provided).
    image

Thanks francois! So I verified both of your points .... I've got the correct google root certificate, and the write clientID. When I try to emulate your block diagram, where the hostname is wired to the address as well (mqtt.googleapis.com), I get the following error. Perhaps I've got my configuration wrong? In the password input of the Secured TCP Client Certificate, I've put the signed token (which is signed by the device private key) .. same error. Even with password unwired.

Error -715050 occurred at Start TLS in Connection.TCP-TLS.lvclass:onConnection.vi:590001->Connection_GOSPL.lvlib:Connection.lvclass:Connect.vi:3060002->MQTT Client.lvlib:Client.lvclass:Connect to Server.vi:7180001->Test Google Cloud PubSub.vi

Possible reason(s):

LabVIEW: (Hex 0xFFF516D6) REMOTE HOST IDENTIFICATION HAS FAILED!
Certificate verification failed. The remote application could not prove its identity against our trusted certificate store. This error may appear during security attacks on your network, such as man-in-the-middle attacks. It also appears if the trusted certificate store is misconfigured, and in other mundane circumstances.

You're getting close because I remember getting a similar error and I was basically one parameter from getting it correct. One of the parameter is not quite right, but you are establishing a connection to a proper domain. The message seems to imply something with one of the certificates. Check that the root cert you have is for the googleapis.com and not the LTS root.

This reference might be of help: (https://cloud.google.com/iot/docs/how-tos/mqtt-bridge).
It seems the hostname is fine, but you can also use the long-time support domain.

At a glance, it looks like Google API needs the JWT in the password field. They recommend setting the hostname to ignore or unused, but it's really to fool the clients that will sometimes reject an empty username. Google API does not use the username at all.

Also, maybe specify the keep-alive to 60sec or more. It should be already set by default, but I've seen this be a concern with Mosquitto.

Thanks Francois! following the instructions in the Google API (using paho as the client), the JWT is set as the password parameter as you mentioned. I've tried wiring the JWT into the password input of Configure Secured TCP Client Certificate and Key VI, and in the payload settings of the Connect to Server VI, as well as both - no luck. I've also tried your other suggestions - no good.

I'll try and dig deeper .. maybe there's a typo or something.