Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Certificate to use AWS via MQTT #17

Closed
ghost opened this issue Sep 28, 2020 · 3 comments
Closed

Certificate to use AWS via MQTT #17

ghost opened this issue Sep 28, 2020 · 3 comments
Labels
question Further information is requested

Comments

@ghost
Copy link

ghost commented Sep 28, 2020

I'm using on ESP8266 a sketch like this one: https://github.com/Ameba8195/Arduino/blob/master/hardware_v2/libraries/MQTTClient/examples/amazon_awsiot_basic/amazon_awsiot_basic.ino, where the certificates are simply stored in flash as they are downloaded from the server:

char* rootCABuff = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB\n" \
"yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL\n" \
...

char* certificateBuff = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIDWTCCAkGgAwIBAgIUE1UsPqN2mfvCGh2DLX2HWs3NOIYwDQYJKoZIhvcNAQEL\n" \
"BQAwTTFLMEkGA1UECwxCQW1hem9uIFdlYiBTZXJ2aWNlcyBPPUFtYXpvbi5jb20g\n" \
...

char* privateKeyBuff = \
"-----BEGIN RSA PRIVATE KEY-----\n" \
"MIIEpAIBAAKCAQEA0zz9/MUl5mhLbIh/RjKx4WpSWfA3A2yDQbhT7eZQ+PjuiCze\n" \
"MsMUDbTw/zlLeqd8NpRjnnfBhjcFwiUHOmnLu+y2uBqlM7EfZz82uT9B8OqD+BQF\n" \
...

Now I need to port the code to an STM32 board (Nucleo-144 429ZI).
Because the STM32Ethernet library still does not support secure connections, they suggested me to use this library instead.
I read the documentation here: https://github.com/OPEnSLab-OSU/SSLClient/blob/master/TrustAnchors.md but my still limited knowledge about certificates doesn't allow me to fully understand how should I fill in the Trust Anchors from the above certificates.

@ghost ghost added the question Further information is requested label Sep 28, 2020
@prototypicalpro
Copy link
Member

Hello! A trust anchor is BearSSL's way of storing the root CA (rootCABuf) with the extra information removed. The documentation talks about them in more detail, but the gist is that trust anchors must be generated from the appropriate root CAs using an external tool and then copied into the project. In your case, you can use this python script included in SSLClient to convert the certificate in rootCABuf into a trust anchor. Simply find this script in your copy of SSLClient (under tools/pycert_bearssl/pycert_bearssl.py), follow the setup instructions at the top of the file, and run pycert_bearssl.py convert --no-search <certificate PEM file>. This command should create a certificates.h file containing the trust anchors (like so) which you can include in your project.

Sorry for the confusion, I need to revisit that documentation at some point.

@ghost
Copy link
Author

ghost commented Sep 29, 2020

No problem, thanks for the clarification. Instead, the other certificates (certificateBuff and privateKeyBuff in my example) can be the same as above, and I would use SSLClientParameters fromPEM(); to set them, as far as I understand.

UPDATE

It works!
The only problem is I get this kind of output:


Attempting MQTT connection...connected
(SSLClient)(SSL_WARN)(m_run_until): Discarded unread data to favor a write operation
(SSLClient)(SSL_WARN)(m_run_until): Discarded unread data to favor a write operation
(SSLClient)(SSL_WARN)(m_run_until): Discarded unread data to favor a write operation
(SSLClient)(SSL_WARN)(m_run_until): Discarded unread data to favor a write operation
(SSLClient)(SSL_WARN)(m_run_until): Discarded unread data to favor a write operation
Published [$aws/things/<thing>/shadow/update] {"state": {}}}
Message arrived [$aws/things/<thing>/shadow/update/accepted] {"state":{"desired":{blablabla}}

My test code is the following:

#include <LwIP.h>
#include <STM32Ethernet.h>
#include <SSLClient.h>
#include <PubSubClient.h>
#include "certificates.h"

#define THING_NAME "<thing>"
#define MQTT_PACKET_SIZE  1024

void MQTTPublish(const char *topic, char *payload);
void updateThing();

const char my_cert[] = "xxx";
const char my_key[] = "xx";

SSLClientParameters mTLS = SSLClientParameters::fromPEM(my_cert, sizeof my_cert, my_key, sizeof my_key);

const char* mqttServer = "<account>.iot.us-east-2.amazonaws.com";
const char mqttId[] = "<id>";
const char publishShadowUpdate[] = "$aws/things/" THING_NAME "/shadow/update";
char publishPayload[MQTT_PACKET_SIZE];
char *subscribeTopic[5] =
{
  "$aws/things/" THING_NAME "/shadow/update/accepted",
  "$aws/things/" THING_NAME "/shadow/update/rejected",
  "$aws/things/" THING_NAME "/shadow/update/delta",
  "$aws/things/" THING_NAME "/shadow/get/accepted",
  "$aws/things/" THING_NAME "/shadow/get/rejected"
};

void callback(char* topic, byte* payload, unsigned int length) 
{
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i=0;i<length;i++) 
  {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

EthernetClient ethClient;
SSLClient ethClientSSL(ethClient, TAs, (size_t)TAs_NUM, A5);
PubSubClient mqtt(mqttServer, 8883, callback, ethClientSSL);

void reconnect() 
{
  while (!mqtt.connected()) 
  {
    Serial.print("Attempting MQTT connection...");
    if (mqtt.connect("arduinoClient")) 
    {
      Serial.println("connected");
      for (int i = 0; i < 5; i++) 
      {
        mqtt.subscribe(subscribeTopic[i]);
        ethClientSSL.flush();
      }

        updateThing();
    } 
    else 
    {
      Serial.print("failed, rc=");
      Serial.print(mqtt.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void setup()
{
  Serial.begin(115200);
  while(!Serial);

  ethClientSSL.setMutualAuthParams(mTLS);
  mqtt.setBufferSize(MQTT_PACKET_SIZE);

  if (Ethernet.begin() == 0) 
  {
    Serial.println("Failed to configure Ethernet using DHCP");
    while (1) delay(1);
  } 
  else 
  {
    Serial.print("  DHCP assigned IP ");
    Serial.println(Ethernet.localIP());
  }
  delay(2000);
}

void loop()
{
  if (!mqtt.connected()) 
  {
    reconnect();
  }
  mqtt.loop();
}

void updateThing()
{
  strcpy(publishPayload, "{blablabla}}}");
  MQTTPublish(publishShadowUpdate, publishPayload);
}

void MQTTPublish(const char *topic, char *payload)
{
  mqtt.publish(topic, payload);
  ethClientSSL.flush();
  printf("Published [%s] %s\r\n", topic, payload);  
}

@prototypicalpro
Copy link
Member

Excellent! I'll go ahead and close this issue so we can continue the discussion in #18.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

1 participant