1

How do you connect to AWS IoT and pub/sub MQTT messages using Toit?

I was able to follow the MQTT tutorial on the Toit Docs site (https://docs.toit.io/tutorials/mqtt/#tls), which worked great for non-TLS between my ESP32 running Toit and a Raspberry Pi running mosquitto.

However, I am now trying to to pub/sub messages with AWS IoT Core. As instructed in the TLS section of the Toit MQTT tutorial I have installed the Toit root certs package:

jag pkg install github.com/toitware/toit-cert-roots@v1

I changed --root_certificates=[certificate_roots.ISRG_ROOT_X1] to --root_certificates=[certificate_roots.AMAZON_ROOT_CA_1] when creating the transport. However, it is not clear how or where to specify the device certificate and the private key.

In the Toit MQTT Library documentation (https://pkg.toit.io/github.com/toitware/mqtt@2.2.0/docs/mqtt/class-TcpTransport), it shows how you can specify a parameter called --certificate of type Certificate.

tls network/Interface --host/string --port/int= --root_certificates/List= --server_name/string= --certificate/Certificate= -> TcpTransport
  • Is this where you specify the device cert and private key?
    • If so, how do you create a Certificate object?
  • Do you specify --certificate two times?
A. Saunders
  • 815
  • 1
  • 6
  • 19

1 Answers1

1

You should have a client certificate and a client key. These are typically given by Amazon as "device_name.cert.pem", and "device-name.private.key"

The certificate starts with -----BEGIN CERTIFICATE----- and the key with -----BEGIN RSA PRIVATE KEY-----.

Let's assume that the certificate string is in variable CLIENT_CERTIFICATE_DER and the key in variable CLIENT_KEY_DER. The "DER" stands for the "distinguished encoding rules".

You can then create a transport for AWS as follows:

import certificate_roots
import net
import net.x509
import mqtt
import mqtt.transport as mqtt
import tls

HOST ::= "<YOUR AMAZON HOST>"
PORT ::= 8883
ROOT_CERTIFICATE ::= certificate_roots.AMAZON_ROOT_CA_1

CLIENT_CERTIFICATE_DER ::= """
-----BEGIN CERTIFICATE-----
<YOUR CERTIFICATE>
-----END CERTIFICATE-----
"""

CLIENT_KEY_DER ::= """
-----BEGIN RSA PRIVATE KEY-----
<YOUR KEY>
-----END RSA PRIVATE KEY-----
"""

create_aws_transport network/net.Interface -> mqtt.Transport:
  parsed := x509.Certificate.parse CLIENT_CERTIFICATE_DER
  client_certificate := tls.Certificate parsed CLIENT_KEY_DER
  return mqtt.TcpTransport.tls network
      --host=HOST
      --port=PORT
      --root_certificates=[ROOT_CERTIFICATE]
      --certificate=client_certificate

You can then connect to the broker as follows:

main:
  network := net.open
  transport := create_aws_transport network
  client := mqtt.Client --transport=transport
  options := mqtt.SessionOptions
      --client_id="<YOUR CLIENT ID>"
  client.start --options=options
  client.publish "YOUR_TOPIC" "hello".to_byte_array
  client.close
  network.close

Remember that AWS has policies for each device that restrict the allowed client ids and the allowed topics.

If you get an "invalid packet kind: 0", then you are using a client_id that isn't allowed by your policy.

Florian Loitsch
  • 7,698
  • 25
  • 30
  • Florian, thank you for your quick response. I think I'm close now, but I am getting an error in the `create_aws_transport` function. when trying to create the `client_certificate`. The error is `Running 'main.toit' on 'mqtt' ... main.toit:71:25: error: Unresolved identifier: 'tls' client_certificate := tls.Certificate parsed CLIENT_KEY_DER ^~~ Compilation failed.` – A. Saunders Jul 17 '23 at 20:28
  • Hopefully this gives you more context. `$ jag version Version: v1.7.1 SDK version: v2.0.0-alpha.33 Build date: 2022-10-15T18:12:13Z` – A. Saunders Jul 17 '23 at 20:30
  • I forgot an `import tls` at the top. Will fix the code tomorrow. – Florian Loitsch Jul 18 '23 at 01:28
  • I have updated the code as shown in the answer, I have now added the `import tls` statement and now it will run, but on `client.publish` I am getting `DEBUG: Connected to broker DEBUG: Attempting to (re)connect` on repeat. I have verified that the certificates and client_id are correct. Any idea what is going on? – A. Saunders Jul 18 '23 at 05:44
  • Make sure you are publishing to a topic that the policy allows you to publish to. – Florian Loitsch Jul 18 '23 at 08:22
  • I have it working now, there is still a quirk with the client id, but it is on the AWS side. Thank you! – A. Saunders Jul 18 '23 at 15:39