0

I am trying to connect to Google's MQTT server but I am getting errors I created all the certificates and registered my device (Adafruit huzzah32)

and the documentation says you connect to mqtt.googleapis.com:8883

So I do

WiFiClientSecure wifi;
MQTTClient client;
client.begin("mqtt.googleapis.com", 8883, wifi);

When I try to connect I use the device path

const char* jwt = "{json web token}";
const char* device = "projects/{project-id}/locations/{cloud-region}/registries/{registry-id}/devices/{device-id}";

Serial.print("Connecting to mqtt");
while (!client.connect(device,"unused",jwt)) {
    Serial.print(".");
    delay(1000);
}

Serial.println();
Serial.println("Connected to mqtt");

but it never connects

I verified the google certificate by calling openssl s_client -showcerts -connect mqtt.googleapis.com:8883 and I put in my RSA Private key and certificate key that was made

wifi.setCACert(googleCertificate2);
wifi.setCertificate(myCertificate);
wifi.setPrivateKey(privateCert);

What am I doing wrong?

Here is the connection documentation https://cloud.google.com/iot/docs/how-tos/mqtt-bridge

Update

I made a quick java example to see if I can connect going off the example they have for connecting and I get a MqttException saying Bad user name or password (4)

Here is the code for that

private void doStuff(){
        String clientId = String.format("ssl://%s:%s", "mqtt.googleapis.com", 8883);
        String mqttClientId = String.format("projects/%s/locations/%s/registries/%s/devices/%s","{project_id}", "us-central1", "{register}", "{device}");
        MqttConnectOptions connectOptions = new MqttConnectOptions();
        connectOptions.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);

        Properties sslProps = new Properties();
        sslProps.setProperty("com.ibm.ssl.protocol", "TLSv1.2");
        connectOptions.setSSLProperties(sslProps);

        connectOptions.setUserName("unused");


        try{
            String jwt = createJwtRsa("{project-id}");
            connectOptions.setPassword(jwt.toCharArray());
            MqttClient client = new MqttClient(clientId, mqttClientId, new MemoryPersistence());

            while(!client.isConnected()){
                try{
                    client.connect(connectOptions);
                }catch (MqttException e) {
                    e.printStackTrace();
                }
            }
            Log.d("","");
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    private String createJwtRsa(String projectId) throws Exception {
        DateTime now = new DateTime();
        JwtBuilder jwtBuilder =
                Jwts.builder().setIssuedAt(now.toDate()).setExpiration(now.plusDays(1000000).toDate()).setAudience(projectId);

        byte[] keyBytes = readBytes(getAssets().open("rsa_private_pkcs8"));
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");

        PrivateKey k = kf.generatePrivate(spec);

        return jwtBuilder.signWith(SignatureAlgorithm.RS256, k).compact();
    }

As you can see here I have the IoT service acount added to IAM enter image description here

Does that mean my keys that I generated with openssl are incorrect?

tyczj
  • 71,600
  • 54
  • 194
  • 296

2 Answers2

1

My problem ended up being that I was trying to set a really large expiration date on my Json Web Token (on purpose so I didnt have to keep generating new ones since I have not found a way to do that in arduino) and it looks like that google's mqtt server does not accept anything over a day so the keys will have to be updated daily.

Also inorder to connect to the MQTT server I had to change the buffer size of the MqttClient on the arduino to have a buffer size of 1024 bytes.

MQTTClient client(1024);

anything less I would get an error saying buffer isnt big enough.

tyczj
  • 71,600
  • 54
  • 194
  • 296
  • found another client for Arduino https://pubsubclient.knolleary.net/index.html - that "buffer" might be either the `MQTT_MAX_PACKET_SIZE` or the `MQTT_MAX_TRANSFER_SIZE`. – Martin Zeitler Mar 04 '18 at 07:45
  • Hello! I'm also trying to connect my Arduino board with Google IoT Core but I don't how to generate the JWT token. How was your approach to generate the token? – Marlon Mar 07 '18 at 18:43
  • @Marlon I created an AppEngine endpoint that I call on arduino to get a token and just used the java example they have for the IoT documentation. Though if your board does not support SSL/TLS this wont work – tyczj Mar 07 '18 at 19:06
  • Another solution I was working with is I use a Raspberry Pi3 running Android Things to create the key and send it to the board over bluetooth – tyczj Mar 07 '18 at 19:09
  • Thanks @tyczj! I've been thinking about a solution like yours but in my case, I thought that maybe I could have a gateway that is responsible for redirecting all messages from devices to IoT Core. This gateway, in this case, will be responsible for generating the JWT token for each device and send the message to Google. The drawback of this solution is that I'll need to store the private keys in this gateway and map each device to its private key. – Marlon Mar 07 '18 at 21:57
0

here the IAM roles are being explained ...the paragraph here sounds alike what you describe:

On the IAM page in Google Cloud Platform Console, verify that the role Cloud IoT Core Service Agent appears in the Members list for the relevant project service account. (Look for the project service account that ends in @gcp-sa-cloudiot.iam.gserviceaccount.com.)

If the Cloud IoT Core Service Agent role does not appear in the Members list, use gcloud to add the cloudiot.serviceAgent role to the relevant project service account. This role includes permission to publish to Pub/Sub topics.

if not yet having installed it, the Cloud SDK is required for all those gcloud CLI commands, which can be used to list & edit the configurations (of which all can be done through the console, as well)... it's maybe easier, because all of the examples there use it, too.

update ...

concerning JWT refresh tokens, see this article or have some Q & A or the specification: JSON Web Token (JWT), JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants. here's another relevant article: https://medium.com/google-cloud/refreshing-json-web-tokens-jwts-for-google-cloud-iot-core-897318df3836

Community
  • 1
  • 1
Martin Zeitler
  • 1
  • 19
  • 155
  • 216
  • all those things check out (IAM service agent and gcloud commands find devices) – tyczj Mar 02 '18 at 17:58
  • Ok so just an update now, The problem with the java example I think was that I needed to update the gradle dependencies to the latest version, I did that and I was able to connect so what am I missing in the c++ arduino code then? – tyczj Mar 03 '18 at 15:23