diff --git a/examples/aws_iot/Makefile b/examples/aws_iot/Makefile
new file mode 100644
index 0000000..677148a
--- /dev/null
+++ b/examples/aws_iot/Makefile
@@ -0,0 +1,3 @@
+PROGRAM=aws_iot
+EXTRA_COMPONENTS = extras/paho_mqtt_c extras/mbedtls
+include ../../common.mk
diff --git a/examples/aws_iot/README.md b/examples/aws_iot/README.md
new file mode 100644
index 0000000..daebef0
--- /dev/null
+++ b/examples/aws_iot/README.md
@@ -0,0 +1,60 @@
+Please follow the steps below to build and run the example on your ESP8266.
+
+1. Modify client_config.c to provide your own account-specific AWS IoT
+ endpoint, ECC-based client certificate, and private key.
+
+ Your endpoint is in the form of ```<prefix>.iot.<region>.amazonaws.com```.
+ It can be retrieved using the following command:
+
+ ```sh
+ $ aws iot describe-endpoint
+ ```
+
+ Your ECC-based certificate and private key can be generated by using 
+ the following commands:
+
+ ```sh
+ $ openssl ecparam -out ecckey.key -name prime256v1 -genkey
+ $ openssl req -new -sha256 -key ecckey.key -nodes -out eccCsr.csr
+ $ aws iot create-certificate-from-csr --certificate-signing-request file://eccCsr.csr --certificate-pem-outfile eccCert.crt --set-as-active
+ ```
+
+ To convert the certificate or key file into C string, you could try
+ the following example:
+
+ ```sh
+ $ cat ecckey.key | sed -e 's/^/"/g' | sed -e 's/$/\\r\\n"/g'
+ ```
+
+ *Note, more information about using ECC-based certificate with AWS IoT
+ can be found in the following blog*
+
+ https://aws.amazon.com/blogs/iot/elliptic-curve-cryptography-and-forward-secrecy-support-in-aws-iot-3/
+
+2. Create and attach AWS IoT access policy to the certificate
+
+ ```sh
+ $ aws iot create-policy --policy-name test-thing-policy --policy-document '{ "Version": "2012-10-17", "Statement": [{"Action": ["iot:*"], "Resource": ["*"], "Effect": "Allow" }] }'
+ $ aws iot attach-principal-policy --policy-name test-thing-policy --principal "arn:aws:iot:eu-west-1:892804553548:cert/2d9c2da32a95b5e95a277c3b8f7af40869727f5259dc2e907fc8aba916c857e"
+ ```
+
+ *Note, the 'principal' argument is the certificate ARN generated from the
+ pervious command 'aws iot create-certificate-from-csr'.*
+
+3. Modify include/ssid_config.h with your Wifi access Id and credential.
+
+4. Build and flash the example firmware to the device using the command
+ below:
+
+ ```sh
+ $ make flash -C examples/aws_iot ESPPORT=/dev/ttyUSB0
+ ```
+
+ *Note, it assumes your ESP8266 is connected through USB and exposed under
+ your Linux host as /dev/ttyUSB0.*
+
+5. Once the ESP8266 is connected to AWS IoT, you can use the MQTT client
+ on the AWS IoT console to receive the messages published by the ESP8266
+ to topic 'esp8266/status'. You could also publish 'on' or 'off' message
+ to topic 'esp8266/control' to toggle the GPIO/LED (GPIO2 is used by the
+ example).
diff --git a/examples/aws_iot/aws_iot.c b/examples/aws_iot/aws_iot.c
new file mode 100644
index 0000000..01ce9a1
--- /dev/null
+++ b/examples/aws_iot/aws_iot.c
@@ -0,0 +1,280 @@
+/*
+ * Derived from examples/mqtt_client/mqtt_client.c - added TLS1.2 support and some minor modifications.
+ */
+#include "espressif/esp_common.h"
+#include "esp/uart.h"
+
+#include <string.h>
+
+#include <FreeRTOS.h>
+#include <task.h>
+#include <queue.h>
+#include <ssid_config.h>
+
+#include <espressif/esp_sta.h>
+#include <espressif/esp_wifi.h>
+
+#include <paho_mqtt_c/MQTTESP8266.h>
+#include <paho_mqtt_c/MQTTClient.h>
+
+// this must be ahead of any mbedtls header files so the local mbedtls/config.h can be properly referenced
+#include "ssl_connection.h"
+
+#define MQTT_PUB_TOPIC "esp8266/status"
+#define MQTT_SUB_TOPIC "esp8266/control"
+#define GPIO_LED 2
+#define MQTT_PORT 8883
+
+/* certs, key, and endpoint */
+extern char *ca_cert, *client_endpoint, *client_cert, *client_key;
+
+static int wifi_alive = 0;
+static int ssl_reset;
+static SSLConnection *ssl_conn;
+static xQueueHandle publish_queue;
+
+static void beat_task(void *pvParameters) {
+    char msg[16];
+    int count = 0;
+
+    while (1) {
+        if (!wifi_alive) {
+            vTaskDelay(1000 / portTICK_RATE_MS);
+            continue;
+        }
+
+        printf("Schedule to publish\r\n");
+
+        snprintf(msg, sizeof(msg), "%d", count);
+        if (xQueueSend(publish_queue, (void *) msg, 0) == pdFALSE) {
+            printf("Publish queue overflow\r\n");
+        }
+
+        vTaskDelay(10000 / portTICK_RATE_MS);
+    }
+}
+
+static void topic_received(MessageData *md) {
+    MQTTMessage *message = md->message;
+    int i;
+
+    printf("Received: ");
+    for (i = 0; i < md->topic->lenstring.len; ++i)
+        printf("%c", md->topic->lenstring.data[i]);
+
+    printf(" = ");
+    for (i = 0; i < (int) message->payloadlen; ++i)
+        printf("%c", ((char *) (message->payload))[i]);
+    printf("\r\n");
+
+    if (!strncmp(message->payload, "on", 2)) {
+        printf("Turning on LED\r\n");
+        gpio_write(GPIO_LED, 0);
+    } else if (!strncmp(message->payload, "off", 3)) {
+        printf("Turning off LED\r\n");
+        gpio_write(GPIO_LED, 1);
+    }
+}
+
+static const char *get_my_id(void) {
+    // Use MAC address for Station as unique ID
+    static char my_id[13];
+    static bool my_id_done = false;
+    int8_t i;
+    uint8_t x;
+    if (my_id_done)
+        return my_id;
+    if (!sdk_wifi_get_macaddr(STATION_IF, (uint8_t *) my_id))
+        return NULL;
+    for (i = 5; i >= 0; --i) {
+        x = my_id[i] & 0x0F;
+        if (x > 9)
+            x += 7;
+        my_id[i * 2 + 1] = x + '0';
+        x = my_id[i] >> 4;
+        if (x > 9)
+            x += 7;
+        my_id[i * 2] = x + '0';
+    }
+    my_id[12] = '\0';
+    my_id_done = true;
+    return my_id;
+}
+
+static int mqtt_ssl_read(Network* n, unsigned char* buffer, int len,
+        int timeout_ms) {
+    int r = ssl_read(ssl_conn, buffer, len, timeout_ms);
+    if (r <= 0
+            && (r != MBEDTLS_ERR_SSL_WANT_READ
+                    && r != MBEDTLS_ERR_SSL_WANT_WRITE
+                    && r != MBEDTLS_ERR_SSL_TIMEOUT)) {
+        printf("%s: TLS read error (%d), resetting\n\r", __func__, r);
+        ssl_reset = 1;
+    };
+    return r;
+}
+
+static int mqtt_ssl_write(Network* n, unsigned char* buffer, int len,
+        int timeout_ms) {
+    int r = ssl_write(ssl_conn, buffer, len, timeout_ms);
+    if (r <= 0
+            && (r != MBEDTLS_ERR_SSL_WANT_READ
+                    && r != MBEDTLS_ERR_SSL_WANT_WRITE)) {
+        printf("%s: TLS write error (%d), resetting\n\r", __func__, r);
+        ssl_reset = 1;
+    }
+    return r;
+}
+
+static void mqtt_task(void *pvParameters) {
+    int ret = 0;
+    struct Network network;
+    MQTTClient client = DefaultClient;
+    char mqtt_client_id[20];
+    uint8_t mqtt_buf[100];
+    uint8_t mqtt_readbuf[100];
+    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+
+    memset(mqtt_client_id, 0, sizeof(mqtt_client_id));
+    strcpy(mqtt_client_id, "ESP-");
+    strcat(mqtt_client_id, get_my_id());
+
+    ssl_conn = (SSLConnection *) malloc(sizeof(SSLConnection));
+    while (1) {
+        if (!wifi_alive) {
+            vTaskDelay(1000 / portTICK_RATE_MS);
+            continue;
+        }
+
+        printf("%s: started\n\r", __func__);
+        ssl_reset = 0;
+        ssl_init(ssl_conn);
+        ssl_conn->ca_cert_str = ca_cert;
+        ssl_conn->client_cert_str = client_cert;
+        ssl_conn->client_key_str = client_key;
+
+        NewNetwork(&network);
+        network.mqttread = mqtt_ssl_read;
+        network.mqttwrite = mqtt_ssl_write;
+
+        printf("%s: connecting to MQTT server %s ... ", __func__,
+                client_endpoint);
+        ret = ssl_connect(ssl_conn, client_endpoint, MQTT_PORT);
+
+        if (ret) {
+            printf("error: %d\n\r", ret);
+            ssl_destroy(ssl_conn);
+            continue;
+        }
+        printf("done\n\r");
+        NewMQTTClient(&client, &network, 5000, mqtt_buf, 100, mqtt_readbuf,
+                100);
+
+        data.willFlag = 0;
+        data.MQTTVersion = 4;
+        data.cleansession = 1;
+        data.clientID.cstring = mqtt_client_id;
+        data.username.cstring = NULL;
+        data.password.cstring = NULL;
+        data.keepAliveInterval = 1000;
+        printf("Send MQTT connect ... ");
+        ret = MQTTConnect(&client, &data);
+        if (ret) {
+            printf("error: %d\n\r", ret);
+            ssl_destroy(ssl_conn);
+            continue;
+        }
+        printf("done\r\n");
+        MQTTSubscribe(&client, MQTT_SUB_TOPIC, QOS1, topic_received);
+        xQueueReset(publish_queue);
+
+        while (wifi_alive && !ssl_reset) {
+            char msg[64];
+            while (xQueueReceive(publish_queue, (void *) msg, 0) == pdTRUE) {
+                portTickType task_tick = xTaskGetTickCount();
+                uint32_t free_heap = xPortGetFreeHeapSize();
+                uint32_t free_stack = uxTaskGetStackHighWaterMark(NULL);
+                snprintf(msg, sizeof(msg), "%u: free heap %u, free stack %u",
+                        task_tick, free_heap, free_stack * 4);
+                printf("Publishing: %s\r\n", msg);
+
+                MQTTMessage message;
+                message.payload = msg;
+                message.payloadlen = strlen(msg);
+                message.dup = 0;
+                message.qos = QOS1;
+                message.retained = 0;
+                ret = MQTTPublish(&client, MQTT_PUB_TOPIC, &message);
+                if (ret != SUCCESS) {
+                    printf("error while publishing message: %d\n", ret);
+                    break;
+                }
+            }
+
+            ret = MQTTYield(&client, 1000);
+            if (ret == DISCONNECTED)
+                break;
+        }
+        printf("Connection dropped, request restart\n\r");
+        ssl_destroy(ssl_conn);
+    }
+}
+
+static void wifi_task(void *pvParameters) {
+    uint8_t status = 0;
+    uint8_t retries = 30;
+    struct sdk_station_config config = { .ssid = WIFI_SSID, .password =
+            WIFI_PASS, };
+
+    printf("%s: Connecting to WiFi\n\r", __func__);
+    sdk_wifi_set_opmode (STATION_MODE);
+    sdk_wifi_station_set_config(&config);
+
+    while (1) {
+        wifi_alive = 0;
+
+        while ((status != STATION_GOT_IP) && (retries)) {
+            status = sdk_wifi_station_get_connect_status();
+            printf("%s: status = %d\n\r", __func__, status);
+            if (status == STATION_WRONG_PASSWORD) {
+                printf("WiFi: wrong password\n\r");
+                break;
+            } else if (status == STATION_NO_AP_FOUND) {
+                printf("WiFi: AP not found\n\r");
+                break;
+            } else if (status == STATION_CONNECT_FAIL) {
+                printf("WiFi: connection failed\r\n");
+                break;
+            }
+            vTaskDelay(1000 / portTICK_RATE_MS);
+            --retries;
+        }
+
+        while ((status = sdk_wifi_station_get_connect_status())
+                == STATION_GOT_IP) {
+            if (wifi_alive == 0) {
+                printf("WiFi: Connected\n\r");
+                wifi_alive = 1;
+            }
+            vTaskDelay(500 / portTICK_RATE_MS);
+        }
+
+        wifi_alive = 0;
+        printf("WiFi: disconnected\n\r");
+        vTaskDelay(1000 / portTICK_RATE_MS);
+    }
+}
+
+void user_init(void) {
+    uart_set_baud(0, 115200);
+    printf("SDK version: %s, free heap %u\n", sdk_system_get_sdk_version(),
+            xPortGetFreeHeapSize());
+
+    gpio_enable(GPIO_LED, GPIO_OUTPUT);
+    gpio_write(GPIO_LED, 1);
+
+    publish_queue = xQueueCreate(3, 16);
+    xTaskCreate(&wifi_task, (int8_t *) "wifi_task", 256, NULL, 2, NULL);
+    xTaskCreate(&beat_task, (int8_t *) "beat_task", 256, NULL, 2, NULL);
+    xTaskCreate(&mqtt_task, (int8_t *) "mqtt_task", 2048, NULL, 2, NULL);
+}
diff --git a/examples/aws_iot/ca_cert.c b/examples/aws_iot/ca_cert.c
new file mode 100644
index 0000000..b2db9fb
--- /dev/null
+++ b/examples/aws_iot/ca_cert.c
@@ -0,0 +1,29 @@
+// trusted root CA certificate - https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem
+const char *ca_cert = "-----BEGIN CERTIFICATE-----\r\n"
+        "MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB\r\n"
+        "yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL\r\n"
+        "ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp\r\n"
+        "U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW\r\n"
+        "ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0\r\n"
+        "aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL\r\n"
+        "MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW\r\n"
+        "ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln\r\n"
+        "biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp\r\n"
+        "U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\r\n"
+        "aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1\r\n"
+        "nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex\r\n"
+        "t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz\r\n"
+        "SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG\r\n"
+        "BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+\r\n"
+        "rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/\r\n"
+        "NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E\r\n"
+        "BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH\r\n"
+        "BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy\r\n"
+        "aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv\r\n"
+        "MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE\r\n"
+        "p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y\r\n"
+        "5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK\r\n"
+        "WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ\r\n"
+        "4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N\r\n"
+        "hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq\r\n"
+        "-----END CERTIFICATE-----\r\n";
diff --git a/examples/aws_iot/client_config.c b/examples/aws_iot/client_config.c
new file mode 100644
index 0000000..8b587c2
--- /dev/null
+++ b/examples/aws_iot/client_config.c
@@ -0,0 +1,17 @@
+// AWS IoT client endpoint
+const char *client_endpoint = "<your-prefix>.iot.<aws-region>.amazonaws.com";
+
+// AWS IoT device certificate (ECC)
+const char *client_cert =
+"-----BEGIN CERTIFICATE-----\r\n"
+"------------------ <your client certificate> -------------------\r\n"
+"-----END CERTIFICATE-----\r\n";
+
+// AWS IoT device private key (ECC)
+const char *client_key = 
+"-----BEGIN EC PARAMETERS-----\r\n"
+"BggqhkjOPQMBBw==\r\n"
+"-----END EC PARAMETERS-----\r\n"
+"-----BEGIN EC PRIVATE KEY-----\r\n"
+"------------------ <your client private key> -------------------\r\n"
+"-----END EC PRIVATE KEY-----\r\n";
diff --git a/examples/aws_iot/mbedtls/config.h b/examples/aws_iot/mbedtls/config.h
new file mode 100644
index 0000000..f3b4411
--- /dev/null
+++ b/examples/aws_iot/mbedtls/config.h
@@ -0,0 +1,119 @@
+/**
+ * \file config.h
+ *
+ * \brief Configuration options (set of defines)
+ *
+ *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+/*
+ * This set of compile-time options may be used to enable
+ * or disable features selectively, and reduce the global
+ * memory footprint.
+ */
+#ifndef MBEDTLS_CONFIG_H
+#define MBEDTLS_CONFIG_H
+
+/* System support */
+#define MBEDTLS_HAVE_ASM
+#define MBEDTLS_DEPRECATED_WARNING
+#define MBEDTLS_ENTROPY_HARDWARE_ALT
+#define MBEDTLS_NO_PLATFORM_ENTROPY
+
+/* mbed TLS feature support */
+#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
+#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
+#define MBEDTLS_SSL_PROTO_TLS1_2
+
+/* Debug support (optional) */
+// #define MBEDTLS_ERROR_C
+// #define MBEDTLS_DEBUG_C
+
+/* mbed TLS modules */
+#define MBEDTLS_AES_C
+#define MBEDTLS_ASN1_PARSE_C
+#define MBEDTLS_ASN1_WRITE_C
+#define MBEDTLS_BIGNUM_C
+#define MBEDTLS_CIPHER_C
+#define MBEDTLS_CTR_DRBG_C
+#define MBEDTLS_ECDH_C
+#define MBEDTLS_ECDSA_C
+#define MBEDTLS_ECP_C
+#define MBEDTLS_ENTROPY_C
+#define MBEDTLS_GCM_C
+#define MBEDTLS_MD_C
+#define MBEDTLS_NET_C
+#define MBEDTLS_OID_C
+#define MBEDTLS_PK_C
+#define MBEDTLS_PK_PARSE_C
+#define MBEDTLS_SHA256_C
+#define MBEDTLS_SHA512_C
+#define MBEDTLS_SSL_CLI_C
+#define MBEDTLS_SSL_SRV_C
+#define MBEDTLS_SSL_TLS_C
+#define MBEDTLS_X509_CRT_PARSE_C
+#define MBEDTLS_X509_USE_C
+
+/* For verify RSA based root CA certificate (optional if root CA cert is signed using ECC) */
+#define MBEDTLS_RSA_C
+#define MBEDTLS_SHA1_C
+#define MBEDTLS_PKCS1_V15
+#define MBEDTLS_PKCS1_V21
+
+/* For test certificates */
+#define MBEDTLS_BASE64_C
+#define MBEDTLS_CERTS_C
+#define MBEDTLS_PEM_PARSE_C
+
+/* Save RAM at the expense of ROM */
+#define MBEDTLS_AES_ROM_TABLES
+
+/* Save RAM by adjusting to our exact needs */
+#define MBEDTLS_ECP_MAX_BITS   384
+#define MBEDTLS_MPI_MAX_SIZE   256 // 2048 bits
+
+/* Save RAM at the expense of speed, see ecp.h */
+#define MBEDTLS_ECP_WINDOW_SIZE        2
+#define MBEDTLS_ECP_FIXED_POINT_OPTIM  0
+
+/* Significant speed benefit at the expense of some ROM */
+#define MBEDTLS_ECP_NIST_OPTIM
+
+/*
+ * You should adjust this to the exact number of sources you're using: default
+ * is the "mbedtls_platform_entropy_poll" source, but you may want to add other ones.
+ * Minimum is 2 for the entropy test suite.
+ */
+#define MBEDTLS_ENTROPY_MAX_SOURCES 2
+
+/* Save ROM and a few bytes of RAM by specifying our own ciphersuite list */
+#define MBEDTLS_SSL_CIPHERSUITES                        \
+    MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+
+/*
+ * Save RAM at the expense of interoperability: do this only if you control
+ * both ends of the connection!  (See coments in "mbedtls/ssl.h".)
+ * The minimum size here depends on the certificate chain used as well as the
+ * typical size of records.
+ */
+#define MBEDTLS_SSL_MAX_CONTENT_LEN             4096
+
+#include "mbedtls/check_config.h"
+
+#endif /* MBEDTLS_CONFIG_H */
diff --git a/examples/aws_iot/ssl_connection.c b/examples/aws_iot/ssl_connection.c
new file mode 100644
index 0000000..be5bb23
--- /dev/null
+++ b/examples/aws_iot/ssl_connection.c
@@ -0,0 +1,170 @@
+#include <espressif/esp_common.h>
+#include <lwip/sockets.h>
+#include <lwip/inet.h>
+#include <lwip/netdb.h>
+#include <lwip/sys.h>
+#include <string.h>
+
+// this must be ahead of any mbedtls header files so the local mbedtls/config.h can be properly referenced
+#include "ssl_connection.h"
+
+#define SSL_READ_TIMEOUT_MS           2000
+
+const char *pers = "esp-tls";
+
+static int handle_error(int err) {
+
+#ifdef MBEDTLS_ERROR_C
+    char error_buf[100];
+
+    mbedtls_strerror(err, error_buf, 100);
+    printf("%s\n", error_buf);
+#endif
+    printf("Error: %d\n", err);
+    return err;
+}
+
+#ifdef MBEDTLS_DEBUG_C
+static void my_debug(void *ctx, int level, const char *file, int line,
+        const char *str) {
+    ((void) level);
+    fprintf((FILE *) ctx, "%s:%04d: %s", file, line, str);
+    fflush((FILE *) ctx);
+}
+#endif
+
+void ssl_init(SSLConnection* conn) {
+    /*
+     * Initialize the RNG and the session data
+     */
+    mbedtls_net_init(&conn->net_ctx);
+    mbedtls_ssl_init(&conn->ssl_ctx);
+    mbedtls_ssl_config_init(&conn->ssl_conf);
+
+    mbedtls_x509_crt_init(&conn->ca_cert);
+    mbedtls_x509_crt_init(&conn->client_cert);
+    mbedtls_pk_init(&conn->client_key);
+
+    mbedtls_ctr_drbg_init(&conn->drbg_ctx);
+    mbedtls_entropy_init(&conn->entropy_ctx);
+
+}
+
+int ssl_connect(SSLConnection* conn, const char* host, int port) {
+    int ret;
+    char buffer[8];
+
+    ret = mbedtls_ctr_drbg_seed(&conn->drbg_ctx, mbedtls_entropy_func,
+            &conn->entropy_ctx, (const unsigned char *) pers, strlen(pers));
+    if (ret < 0) {
+        return -1;
+    }
+
+    ret = mbedtls_x509_crt_parse(&conn->ca_cert,
+            (const unsigned char *) conn->ca_cert_str,
+            strlen(conn->ca_cert_str) + 1);
+    if (ret < 0) {
+        return handle_error(ret);
+    }
+
+    ret = mbedtls_x509_crt_parse(&conn->client_cert,
+            (const unsigned char *) conn->client_cert_str,
+            strlen(conn->client_cert_str) + 1);
+    if (ret < 0) {
+        return handle_error(ret);
+    }
+
+    ret = mbedtls_pk_parse_key(&conn->client_key,
+            (const unsigned char *) conn->client_key_str,
+            strlen(conn->client_key_str) + 1, NULL, 0);
+    if (ret != 0) {
+        return handle_error(ret);
+    }
+
+    snprintf(buffer, sizeof(buffer), "%d", port);
+    ret = mbedtls_net_connect(&conn->net_ctx, host, buffer,
+            MBEDTLS_NET_PROTO_TCP);
+    if (ret != 0) {
+        return handle_error(ret);
+    }
+
+    ret = mbedtls_ssl_config_defaults(&conn->ssl_conf, MBEDTLS_SSL_IS_CLIENT,
+            MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
+    if (ret != 0) {
+        return handle_error(ret);
+    }
+
+#ifdef MBEDTLS_DEBUG_C
+    mbedtls_ssl_conf_dbg(&conn->ssl_conf, my_debug, stdout);
+    mbedtls_debug_set_threshold(5);
+#endif
+
+    mbedtls_ssl_conf_authmode(&conn->ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
+    mbedtls_ssl_conf_rng(&conn->ssl_conf, mbedtls_ctr_drbg_random,
+            &conn->drbg_ctx);
+    mbedtls_ssl_conf_read_timeout(&conn->ssl_conf, SSL_READ_TIMEOUT_MS);
+    mbedtls_ssl_conf_ca_chain(&conn->ssl_conf, &conn->ca_cert, NULL);
+
+    ret = mbedtls_ssl_conf_own_cert(&conn->ssl_conf, &conn->client_cert,
+            &conn->client_key);
+    if (ret != 0) {
+        return handle_error(ret);
+    }
+
+    ret = mbedtls_ssl_setup(&conn->ssl_ctx, &conn->ssl_conf);
+    if (ret != 0) {
+        return handle_error(ret);
+    }
+
+    ret = mbedtls_ssl_set_hostname(&conn->ssl_ctx, host);
+    if (ret != 0) {
+        return handle_error(ret);
+    }
+
+    mbedtls_ssl_set_bio(&conn->ssl_ctx, &conn->net_ctx, mbedtls_net_send, NULL,
+            mbedtls_net_recv_timeout);
+
+    while ((ret = mbedtls_ssl_handshake(&conn->ssl_ctx)) != 0) {
+        if (ret != MBEDTLS_ERR_SSL_WANT_READ
+                && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+            if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
+                return handle_error(ret);
+            }
+        }
+        handle_error(ret);
+
+        vTaskDelay(5000 / portTICK_RATE_MS);
+    }
+
+    mbedtls_ssl_get_record_expansion(&conn->ssl_ctx);
+    ret = mbedtls_ssl_get_verify_result(&conn->ssl_ctx);
+    if (ret != 0) {
+        return handle_error(ret);
+    }
+
+    return ret;
+}
+
+int ssl_destroy(SSLConnection* conn) {
+    mbedtls_net_free(&conn->net_ctx);
+    mbedtls_ssl_free(&conn->ssl_ctx);
+    mbedtls_ssl_config_free(&conn->ssl_conf);
+    mbedtls_ctr_drbg_free(&conn->drbg_ctx);
+    mbedtls_entropy_free(&conn->entropy_ctx);
+    mbedtls_x509_crt_free(&conn->ca_cert);
+    mbedtls_x509_crt_free(&conn->client_cert);
+    mbedtls_pk_free(&conn->client_key);
+
+    return 0;
+}
+
+int ssl_read(SSLConnection* n, unsigned char* buffer, int len, int timeout_ms) {
+    // NB: timeout_ms is ignored, so blocking read will timeout after SSL_READ_TIMEOUT_MS
+    return mbedtls_ssl_read(&n->ssl_ctx, buffer, len);
+}
+
+int ssl_write(SSLConnection* n, unsigned char* buffer, int len,
+        int timeout_ms) {
+    // NB: timeout_ms is ignored, so write is always block write
+    return mbedtls_ssl_write(&n->ssl_ctx, buffer, len);
+}
diff --git a/examples/aws_iot/ssl_connection.h b/examples/aws_iot/ssl_connection.h
new file mode 100644
index 0000000..b8d1bf1
--- /dev/null
+++ b/examples/aws_iot/ssl_connection.h
@@ -0,0 +1,40 @@
+#ifndef _SSL_CONNECTION_H_
+#define _SSL_CONNECTION_H_
+
+// this must be ahead of any mbedtls header files so the local mbedtls/config.h can be properly referenced
+#include "mbedtls/config.h"
+
+#include "mbedtls/net.h"
+#include "mbedtls/debug.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/error.h"
+#include "mbedtls/certs.h"
+
+typedef struct SSLConnection {
+    mbedtls_net_context net_ctx;
+    mbedtls_ssl_context ssl_ctx;
+    mbedtls_ssl_config ssl_conf;
+
+    mbedtls_ctr_drbg_context drbg_ctx;
+    mbedtls_entropy_context entropy_ctx;
+
+    mbedtls_x509_crt ca_cert;
+    mbedtls_x509_crt client_cert;
+    mbedtls_pk_context client_key;
+
+    char *ca_cert_str;
+    char *client_cert_str;
+    char *client_key_str;
+} SSLConnection;
+
+extern void ssl_init(SSLConnection* n);
+extern int ssl_connect(SSLConnection* n, const char* host, int port);
+extern int ssl_destroy(SSLConnection* n);
+extern int ssl_read(SSLConnection* n, unsigned char* buffer, int len,
+        int timeout_ms);
+extern int ssl_write(SSLConnection* n, unsigned char* buffer, int len,
+        int timeout_ms);
+
+#endif /* _SSL_CONNECTION_H_ */
diff --git a/extras/paho_mqtt_c/MQTTClient.c b/extras/paho_mqtt_c/MQTTClient.c
index 4df3d8e..9651ca7 100644
--- a/extras/paho_mqtt_c/MQTTClient.c
+++ b/extras/paho_mqtt_c/MQTTClient.c
@@ -94,8 +94,13 @@ int  readPacket(MQTTClient* c, Timer* timer)
         goto exit;
     len = 1;
     /* 2. read the remaining length.  This is variable in itself */
-    decodePacket(c, &rem_len, left_ms(timer));
-    len += MQTTPacket_encode(c->readbuf + 1, rem_len); /* put the original remaining length back into the buffer */
+    len += decodePacket(c, &rem_len, left_ms(timer));
+    if (len <= 1 || len + rem_len > c->readbuf_size) /* if packet is too big to fit in our readbuf, abort */
+    {
+        rc = READ_ERROR;
+        goto exit;
+    }
+    MQTTPacket_encode(c->readbuf + 1, rem_len); /* put the original remaining length back into the buffer */
     /* 3. read the rest of the buffer using a callback to supply the rest of the data */
     if (rem_len > 0 && (c->ipstack->mqttread(c->ipstack, c->readbuf + len, rem_len, left_ms(timer)) != rem_len))
     {