Ugo RENNERJérôme BeclinHervé RocheLaurent MassonHenri-Michel Thébaud
Published © GPL3+

TLS for IoT devices connected to AWS using TO136 SE

From secure TLS device based on Trusted Objects-Avnet TO136 SE to AWS IoT, using NXP K64F board.

IntermediateProtip4 hours522
TLS for IoT devices connected to AWS using TO136 SE

Things used in this project

Hardware components

NXP FRDM-K66F
×1
Avnet & Trusted Objects - TO136
×1

Software apps and online services

Arm Mbed CLI
OpenSSL

Story

Read more

Code

main.cpp

C/C++
Demo program
#include "mbed.h"
#include "EthernetInterface.h"
#include "MQTTPacket.h"

#include "TO.h"
#include "TO_helper.h"

#define AWS_ENDPOINT "a1bcdefghijklm"
#define AWS_REGION "us-east-2"

#define HTTPS_SERVER_NAME (AWS_ENDPOINT ".iot." AWS_REGION ".amazonaws.com")
#define HTTPS_SERVER_PORT 8883

#define MQTT_BUFFER_SIZE 512
#define MQTT_CLIENT_ID   "mbed"
#define MQTT_TOPIC_DOWN  "topic/down"
#define MQTT_TOPIC_UP    "topic/up"

/**
 * \brief DemoAWS implements the logic for fetching a file from a webserver
 * using a TCP socket and parsing the result.
 */
class DemoAWS {
public:
    /**
     * DemoAWS Constructor
     * Initializes the TCP socket.
     */
    DemoAWS(const char * domain, const uint16_t port, NetworkInterface *net_iface) :
            _domain(domain), _port(port)
    {
        _socket = new TCPSocket(net_iface);
    }

    /**
     * Start the demo.
     */
    void start(void) {

        /*
         * Initialize TLS-related stuf.
         */
        int ret;
		TO_helper_tls_ctx_t *to_ctx;

        /* Connect to the server */
        printf("Connecting with %s:%d\n", _domain, _port);
        ret = _socket->connect(_domain, _port);
        if (ret != NSAPI_ERROR_OK) {
            printf("Failed to connect with error 0x%04X\n", ret);
            return;
        }

		ret = TO_helper_tls_init(&to_ctx,
				static_cast<void *>(_socket),
                libTO_send, libTO_recv);
        if (ret != TO_OK) {
            printf("TO_helper_tls_init failed\n");
            return;
        }
				
		ret = TO_helper_tls_do_handshake(to_ctx);
        if (ret != TO_OK) {
            printf("TO_helper_tls_do_handshake failed\n");
            return;
        }
		
        /* It also means the handshake is done, time to print info */
        printf("TLS connection to %s established\n", HTTPS_SERVER_NAME);

        /**
          * Communication with  AWS MQTT broker
          */

        unsigned char buffer[MQTT_BUFFER_SIZE];
        uint32_t bpos;
        int qos = 1;
        int _qos;
        MQTTString topic;
        unsigned short packetid = 0;
        unsigned short _packetid;
        unsigned char _dup;
        unsigned char retained;
        unsigned char *_payload;
        int _payload_len;
        unsigned char _packettype;
        int value;

        /**
         * Send MQTT connect
         */

        printf("Sending MQTT CONNECT\n");

        MQTTPacket_connectData connect_opts = MQTTPacket_connectData_initializer;
        connect_opts.clientID.cstring = (char*)MQTT_CLIENT_ID;

        if ((ret = MQTTSerialize_connect(buffer, sizeof(buffer), &connect_opts)) < 0) {
            printf("MQTTSerialize_connect failed with code %d\n", ret);
            return;
        }

        bpos = ret;

        if (send_message(_socket, buffer, bpos) < 0) {
            return;
        }

        printf("Waiting MQTT CONNACK\n");

        /**
         * Receive MQTT connect ACK
         */

        unsigned char sessionPresent;
        unsigned char connack_rc;

        if (receive_message(_socket, buffer, sizeof(buffer), &bpos) < 0) {
            return;
        }

        if ((ret = MQTTDeserialize_connack(&sessionPresent, &connack_rc, buffer, bpos)) != 1) {
            printf("MQTTDeserialize_connack failed with code %d\n", ret);
            return;
        }

        if (connack_rc != MQTT_CONNECTION_ACCEPTED) {
            printf("MQTT connect failed with code %d\n", connack_rc);
            return;
        }

        /**
         * Subscribe MQTT topic
         */

        printf("Sending MQTT SUBSCRIBE with topic '%s'\n", MQTT_TOPIC_DOWN);

        topic = (MQTTString)MQTTString_initializer;
        topic.cstring = (char*)MQTT_TOPIC_DOWN;

        if ((ret = MQTTSerialize_subscribe(buffer, sizeof(buffer), 0, packetid, 1, &topic, &qos)) < 0) {
            printf("MQTTSerialize_subscribe failed with code %d\n", ret);
            return;
        }

        bpos = ret;

        if (send_message(_socket, buffer, bpos) < 0) {
            return;
        }

        /**
         * Receive MQTT subscribe ACK
         */

        printf("Waiting MQTT SUBACK\n");

        if (receive_message(_socket, buffer, sizeof(buffer), &bpos) < 0) {
            return;
        }

        if ((ret = MQTTDeserialize_ack(&_packettype, &_dup, &_packetid, buffer, bpos)) != 1) {
            printf("MQTTDeserialize_ack failed with code %d\n", ret);
            return;
        }

        if (_packettype != SUBACK) {
            printf("Bad packet type %d, expected %d\n", _packettype, SUBACK);
            return;
        }

        if (_packetid != packetid) {
            printf("Bad packet ID %d, expected %d\n", _packetid, packetid);
            return;
        }

        ++packetid;

        do {
            /**
             * Receive MQTT publish
             */

            printf("Waiting MQTT PUBLISH with topic '%s'\n", MQTT_TOPIC_DOWN);

            if (receive_message(_socket, buffer, sizeof(buffer), &bpos) < 0) {
                return;
            }

            if ((ret = MQTTDeserialize_publish(&_dup, &_qos, &retained, &_packetid, &topic, &_payload, &_payload_len, buffer, bpos)) != 1) {
                printf("MQTTDeserialize_publish failed with code %d\n", ret);
                return;
            }

            if (MQTTPacket_equals(&topic, (char*)MQTT_TOPIC_DOWN) != 1) {
                printf("Bad packet topic, expected %s, received %s\n", MQTT_TOPIC_DOWN, topic.cstring);
                return;
            }

            _payload[_payload_len++] = '\0';

            printf("Receive payload:\n");
            printf("%s\n", _payload);

            if (_qos > 0) {

                /**
                 * Receive MQTT publish ACK
                 */

                printf("Sending MQTT PUBACK\n");

                if ((ret = MQTTSerialize_ack(buffer, sizeof(buffer), PUBACK, 0, _packetid)) < 0) {
                    printf("MQTTSerialize_ack failed with code %d\n", ret);
                    return;
                }

                bpos = ret;

                if (send_message(_socket, buffer, bpos) < 0) {
                    return;
                }
            }

            value = atoi((char*)_payload);

            /**
             * Publish MQTT message
             */

            printf("Sending MQTT PUBLISH with topic '%s'\n", MQTT_TOPIC_UP);

            itoa(value + 1, (char*)_payload, 10);
            topic = (MQTTString)MQTTString_initializer;
            topic.cstring = (char*)MQTT_TOPIC_UP;

            if ((ret = MQTTSerialize_publish(buffer, sizeof(buffer), 0, qos, 0, packetid, topic, _payload, strlen((char*)_payload))) < 0) {
                printf("MQTTSerialize_publish failed with code %d\n", ret);
                return;
            }

            bpos = ret;

            if (send_message(_socket, buffer, bpos) < 0) {
                return;
            }

            /**
             * Receive MQTT publish ACK
             */

            printf("Waiting MQTT PUBACK\n");

            if (receive_message(_socket, buffer, sizeof(buffer), &bpos) < 0) {
                return;
            }

            if ((ret = MQTTDeserialize_ack(&_packettype, &_dup, &_packetid, buffer, bpos)) != 1) {
                printf("MQTTDeserialize_ack failed with code %d\n", ret);
                return;
            }

            if (_packettype != PUBACK) {
                printf("Bad packet type %d, expected %d\n", _packettype, PUBACK);
                return;
            }

            if (_packetid != packetid) {
                printf("Bad packet ID %d, expected %d\n", _packetid, packetid);
                return;
            }

            ++packetid;
        } while (1);

        /**
         * Send MQTT disconnect
         */

        printf("Sending MQTT DISCONNECT\n");

        if ((ret = MQTTSerialize_disconnect(buffer, sizeof(buffer))) < 0) {
            printf("MQTTSerialize_disconnect failed with code %d\n", ret);
            return;
        }

        bpos = ret;

        if (send_message(_socket, buffer, bpos) < 0) {
            return;
        }

        _socket->close();
    }

protected:

    static int receive_message(void *ctx, const unsigned char *buf, const uint32_t buf_len, uint32_t *len)
    {
        int ret;
		ret = TO_helper_tls_receive((TO_helper_tls_ctx_t *)ctx, (uint8_t*)buf, buf_len, len, -1);
        if (ret != TO_OK) {
            printf("TO_helper_tls_receive_message failed\n");
            return -1;
        }
        return 0;
    }

    static int send_message(void *ctx, const unsigned char *buf, uint32_t len)
    {
        int ret;
		ret = TO_helper_tls_send((TO_helper_tls_ctx_t *)ctx, (uint8_t*)buf, len);
        if (ret != TO_OK) {
            printf("TO_helper_tls_send_message failed\n");
            return -1;
        }
        return 0;
    }

    /**
     * Receive callback for mbed TLS
     */
    static int ssl_recv(void *ctx, unsigned char *buf, uint32_t len) {
        int recv = -1;
        TCPSocket *_socket = static_cast<TCPSocket*>(ctx);
        recv = _socket->recv(buf, len);
        if(recv < 0){
            return -1;
        }else{
            return recv;
        }
   }

    /**
     * Receive callback for mbed TLS
     */
    static int ssl_recv_no_timeout(void *ctx, unsigned char *buf, uint32_t len) {
        TCPSocket *_socket = static_cast<TCPSocket*>(ctx);
        _socket->set_blocking(false);
        return ssl_recv(ctx, buf, len);
   }

    /**
     * Receive callback for mbed TLS
     */
    static int ssl_recv_timeout(void *ctx, unsigned char *buf, uint32_t len, uint32_t timeout) {
        TCPSocket *_socket = static_cast<TCPSocket*>(ctx);
        _socket->set_blocking(true);
        _socket->set_timeout(timeout ? timeout : -1);
        return ssl_recv(ctx, buf, len);
   }

    /**
     * Send callback for mbed TLS
     */
    static int ssl_send(void *ctx, const unsigned char *buf, uint32_t len) {
        int size = -1;
        TCPSocket *_socket = static_cast<TCPSocket*>(ctx);
        size = _socket->send(buf, len);

        if(size < 0){
            return -1;
        }else{
            return size;
        }
    }

    /**
     * Receive callback for libTO
     */
    static int libTO_recv(void *ctx, uint8_t *data, const uint32_t len, uint32_t *read_len, int32_t timeout) {
        int recv = ssl_recv_timeout(ctx, data, len, timeout);
        if (recv < 0) {
            return TO_ERROR;
        }
        *read_len = (uint32_t)recv;
        return TO_OK;
   }

    /**
     * Send callback for libTO
     */
    static int libTO_send(void *ctx, const uint8_t *data, const uint32_t len) {
        int size = ssl_send(ctx, data, len);
        if (size != (int)len) {
            return TO_ERROR;
        }
        return TO_OK;
    }

protected:
    TCPSocket* _socket;

    const char *_domain;
    const uint16_t _port;
};

int main() {
    unsigned char ret;
    unsigned char to_buf[TO_SN_SIZE];

    printf("TLS Client demo started!\n");

    /* Inititalise with DHCP, connect, and start up the stack */
    EthernetInterface eth_iface;

    printf("Trying to get IP address with DHCP...\n");
    eth_iface.connect();

    const char *ip_addr = eth_iface.get_ip_address();
    if (!ip_addr) {
        printf("No Client IP Address\n");
        return -1;
    }

    printf("Client IP Address is %s\n", ip_addr);

    printf("Initialize TO\n");
    ret = TO_init();
    if (ret != TO_OK) {
        printf("TO_init failed with code %04X\n", ret);
        return -1;
    }

    printf("TO: Get serial number...\n");
    ret = TO_get_serial_number(to_buf);
    if (ret != TORSP_SUCCESS) {
        printf("TO_get_serial_number failed with code %04X", ret);
        return -1;
    }

    uint16_t i;
    printf("TO serial number:\n");
    for(i = 0; i < TO_SN_SIZE; i++) {
        printf("%02x", to_buf[i]);
    }
    printf("\n");

    DemoAWS *demo = new DemoAWS(HTTPS_SERVER_NAME, HTTPS_SERVER_PORT, &eth_iface);

    printf("--- Start demo now!---\n");

    demo->start();
    delete demo;
}

Credits

Ugo RENNER

Ugo RENNER

2 projects • 3 followers
Security Software R&D Engineer
Jérôme Beclin

Jérôme Beclin

2 projects • 1 follower
Sales engineer, Trusted Objects
Hervé Roche

Hervé Roche

2 projects • 3 followers
Marketing & Business Development
Laurent Masson

Laurent Masson

2 projects • 3 followers
Henri-Michel Thébaud

Henri-Michel Thébaud

0 projects • 0 followers

Comments