test

Dependencies:   MQTT

Files at this revision

API Documentation at this revision

Comitter:
kernel2418
Date:
Wed Mar 14 03:03:16 2018 +0000
Commit message:
test

Changed in this revision

.gitignore Show annotated file Show diff for this revision Revisions of this file
.hgignore Show annotated file Show diff for this revision Revisions of this file
.mbedignore Show annotated file Show diff for this revision Revisions of this file
MQTT.lib Show annotated file Show diff for this revision Revisions of this file
README.md Show annotated file Show diff for this revision Revisions of this file
TLSSocket.h Show annotated file Show diff for this revision Revisions of this file
easy-connect.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-os.lib Show annotated file Show diff for this revision Revisions of this file
mbed_app.json Show annotated file Show diff for this revision Revisions of this file
mbedtls_user_config.h Show annotated file Show diff for this revision Revisions of this file
mbedtls_utils.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.gitignore	Wed Mar 14 03:03:16 2018 +0000
@@ -0,0 +1,6 @@
+.mbed
+.build/
+BUILD/
+easy-connect/
+mbed-os/
+MQTT/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Wed Mar 14 03:03:16 2018 +0000
@@ -0,0 +1,9 @@
+# Use Python/Perl regexp
+syntax: regexp
+
+^\.mbed$
+\.build/
+BUILD/
+easy-connect/
+mbed-os/
+MQTT/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.mbedignore	Wed Mar 14 03:03:16 2018 +0000
@@ -0,0 +1,6 @@
+easy-connect/atmel-rf-driver/*
+easy-connect/mcr20a-rf-driver/*
+easy-connect/stm-spirit1-rf-driver/*
+easy-connect/wifi-x-nucleo-idw01m1/*
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MQTT.lib	Wed Mar 14 03:03:16 2018 +0000
@@ -0,0 +1,1 @@
+https://mbed.org/teams/mqtt/code/MQTT/#9cff7b6bbd01
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README.md	Wed Mar 14 03:03:16 2018 +0000
@@ -0,0 +1,334 @@
+# Example for Connection with AWS IoT thru MQTT/HTTPS on Mbed OS
+
+This is an example to demonstrate connection with [AWS IoT](https://aws.amazon.com/iot)
+on Nuvoton Mbed-enabled boards.
+
+## Supported platforms
+On Mbed OS, connection with AWS IoT requires Mbed TLS. It requires more than 64 KB RAM.
+Currently, the following Nuvoton Mbed-enalbed boards can afford such memory footprint:
+- [NuMaker-PFM-NUC472](https://developer.mbed.org/platforms/Nuvoton-NUC472/)
+- [NuMaker-PFM-M487](https://developer.mbed.org/platforms/NUMAKER-PFM-M487/)
+
+## Access and manage AWS IoT Service
+To run the example, you need to register one [AWS account](https://aws.amazon.com/)
+to access and manage AWS IoT Service for your device to connect with.
+This [link](https://docs.aws.amazon.com/iot/latest/developerguide/what-is-aws-iot.html) gives detailed
+information about it.
+
+1. Sign in to [AWS Management Console](https://aws.amazon.com/console/).
+1. Enter AWS IoT Service.
+1. In AWS IoT Service, create a thing.
+The Console may prompt you to also create a certificate and a policy. Skip for creating them later.
+1. In AWS IoT Service, create a policy. A workable example would be below.
+Note that you need to replace **REGION** and **ACCOUNT** to match your case.
+
+    <pre>
+    {
+        "Version": "2012-10-17",
+        "Statement": [
+            {
+                "Effect": "Allow",
+                "Action": "iot:Connect",
+                "Resource": "arn:aws:iot:<b>REGION</b>:<b>ACCOUNT</b>:client/*"
+            },
+            {
+                "Effect": "Allow",
+                "Action": "iot:Subscribe",
+                "Resource": ["arn:aws:iot:<b>REGION</b>:<b>ACCOUNT</b>:topicfilter/*"]
+            },
+            {
+                "Effect": "Allow",
+                "Action": ["iot:Publish", "iot:Receive"],
+                "Resource": "arn:aws:iot:<b>REGION</b>:<b>ACCOUNT</b>:topic/*"
+            },
+            {
+                "Effect": "Allow",
+                "Action": ["iot:UpdateThingShadow", "iot:GetThingShadow", "iot:DeleteThingShadow"],
+                "Resource": "arn:aws:iot:<b>REGION</b>:<b>ACCOUNT</b>:thing/*"
+            }
+        ]
+    }
+    </pre>
+
+1. In AWS IoT Service, create a certificate. You would get 4 security credential files from it.
+   Download them for later use.
+   - AWS IoT's CA certificate
+   - User certificate
+   - User private key
+   - User public key
+   
+   After creating the certificate, do:
+   1. Activate the certificate
+   1. Attach the thing created above to the certificate
+   1. Attach the policy created above to the certificate
+
+## Configure your device with AWS IoT
+Before connecting your device with AWS IoT, you need to configure security credential and
+protocol dependent parameters into your device. These configurations are all centralized in `main.cpp`.
+
+### Configure certificate into your device
+From above, you've got 4 security credential files: CA certificate and user certificate/private key/public key.
+Configure CA certificate, user certificate, and user private key into your device.
+User public key has been included in user certificate and is not used here.
+1. Replace CA certificate with downloaded from the Console.
+    ```
+    const char SSL_CA_CERT_PEM[] = "-----BEGIN CERTIFICATE-----\n"
+        "MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB\n"
+        "yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL\n"
+    ```
+
+1. Replace user certificate with downloaded from the Console.
+    ```
+    const char SSL_USER_CERT_PEM[] = "-----BEGIN CERTIFICATE-----\n"
+        "MIIDWjCCAkKgAwIBAgIVALN/H7tr8cgpl2zwg0JjEE106XilMA0GCSqGSIb3DQEB\n"
+        "CwUAME0xSzBJBgNVBAsMQkFtYXpvbiBXZWIgU2VydmljZXMgTz1BbWF6b24uY29t\n"
+    ```
+
+1. Replace user private key with downloaded from the Console.
+    ```
+    const char SSL_USER_PRIV_KEY_PEM[] = "-----BEGIN RSA PRIVATE KEY-----\n"
+    ```
+
+**NOTE:** The credential hard-coded in source code is deactivated or deleted.
+          Use your own credential for connection with AWS IoT.
+
+### Connect through MQTT
+To connect your device with AWS IoT through MQTT, you need to configure the following parameters.
+
+1. Enable connection through MQTT.
+    ```
+    #define AWS_IOT_MQTT_TEST       1
+    ```
+
+1. Replace server name (endpoint). **Endpoint** has the following format and you just 
+   need to modify **IDENTIFIER** and **REGION** to match your case.
+    <pre>
+    #define AWS_IOT_MQTT_SERVER_NAME                "<b>IDENTIFIER</b>.iot.<b>REGION</b>.amazonaws.com"
+    </pre>
+   
+1. Server port number is fixed. Don't change it.
+    ```
+    #define AWS_IOT_MQTT_SERVER_PORT                8883
+    ```
+    
+1. Replace **THINGNAME** to match your case. The **THINGNAME** is just the name of the thing you've created above.
+    <pre>
+    #define AWS_IOT_MQTT_THINGNAME                  "<b>THINGNAME</b>"
+    </pre>
+    
+1. Replace **CLIENTNAME** to match your case. If you adopt the example policy above,
+   you can modify it arbitrarily because the policy permits any client name bound to your account.
+    <pre>
+    #define AWS_IOT_MQTT_CLIENTNAME                 "<b>CLIENTNAME</b>"
+    </pre>
+
+AWS IoT MQTT protocol supports topic subscribe/publish. The example demonstrates:
+- Subscribe/publish with user topic
+- Subscribe/publish with reserved topic (starting with $) to:
+    - Update thing shadow
+    - Get thing shadow
+    - Delete thing shadow
+
+### Connect through HTTPS
+To connect your device with AWS IoT through HTTPS, you need to configure the following parameters.
+
+1. Enable connection through HTTPS.
+    ```
+    #define AWS_IOT_HTTPS_TEST      1
+    ```
+
+1. Replace server name (endpoint). **Endpoint** has the following format and you just 
+   need to modify **IDENTIFIER** and **REGION** to match your case.
+    <pre>
+    #define AWS_IOT_HTTPS_SERVER_NAME               "<b>IDENTIFIER</b>.iot.<b>REGION</b>.amazonaws.com"
+    </pre>
+   
+1. Server port number is fixed. Don't change it.
+    ```
+    #define AWS_IOT_HTTPS_SERVER_PORT               8443
+    ```
+    
+1. Replace **THINGNAME** to match your case. The **THINGNAME** is just the name of the thing you've created above.
+    <pre>
+    #define AWS_IOT_HTTPS_THINGNAME                 "<b>THINGNAME</b>"
+    </pre>
+
+AWS IoT HTTPS protocol supports topic publish-only and RESTful API. The example demonstrates:
+- Publish to user topic
+- Publish to reserved topic (starting with $) to:
+    - Update thing shadow
+    - Get thing shadow
+    - Delete thing shadow
+- RESTful API to:
+    - Update thing shadow RESTfully through HTTPS/POST method
+    - Get thing shadow RESTfully through HTTPS/GET method
+    - Delete thing shadow RESTfully through HTTPS/DELETE method
+
+## Patch MQTT library
+Currently, MQTT library has one issue with unsubscribe from topic multiple times. Fix it:
+
+In `MQTT/MQTTClient.h` > `MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, b>::cycle`,
+<pre>
+switch (packet_type)
+    {
+        default:
+            // no more data to read, unrecoverable. Or read packet fails due to unexpected network error
+            rc = packet_type;
+            goto exit;
+        case 0: // timed out reading packet
+            break;
+        case CONNACK:
+        case PUBACK:
+        case SUBACK:
+        <b>
+        case UNSUBACK:
+        </b>
+            break;
+        case PUBLISH:
+        {
+</pre>
+
+## Monitor the application
+If you configure your terminal program with **9600/8-N-1**, you would see output similar to:
+
+**NOTE:** Make sure that the network is functional before running the application.
+
+<pre>
+Starting AWS IoT test
+Using Mbed OS 5.7.1
+[EasyConnect] IPv4 mode
+Connecting with a1fbcwaqfqeozo.iot.us-east-1.amazonaws.com:8883
+Connecting to a1fbcwaqfqeozo.iot.us-east-1.amazonaws.com:8883
+</pre>
+
+If you get here successfully, it means configurations with security credential are correct.
+<pre>
+Starting the TLS handshake...
+TLS connection to a1fbcwaqfqeozo.iot.us-east-1.amazonaws.com:8883 established
+Server certificate:
+    cert. version     : 3
+    serial number     : 3C:AC:B3:D3:3E:D8:6A:C9:2B:EF:D2:C5:B1:DC:BF:66
+    issuer name       : C=US, O=Symantec Corporation, OU=Symantec Trust Network, CN=Symantec Class 3 ECC 256 bit SSL CA - G2
+    subject name      : C=US, ST=Washington, L=Seattle, O=Amazon.com, Inc., CN=*.iot.us-east-1.amazonaws.com
+    issued  on        : 2017-03-07 00:00:00
+    expires on        : 2018-03-08 23:59:59
+    signed using      : ECDSA with SHA256
+    EC key size       : 256 bits
+    basic constraints : CA=false
+    subject alt name  : iot.us-east-1.amazonaws.com, *.iot.us-east-1.amazonaws.com
+    key usage         : Digital Signature
+    ext key usage     : TLS Web Server Authentication, TLS Web Client Authentication
+Certificate verification passed
+
+Connects with a1fbcwaqfqeozo.iot.us-east-1.amazonaws.com:8883 OK
+</pre>
+
+MQTT handshake goes:
+<pre>
+MQTT connects OK
+
+Subscribing/publishing user topic
+MQTT subscribes to Nuvoton/Mbed/+ OK
+Message to publish:
+{ "message": "Hello from Nuvoton Mbed device" }
+MQTT publishes message to Nuvoton/Mbed/D001 OK
+Message arrived: qos 1, retained 0, dup 0, packetid 1
+Payload:
+{ "message": "Hello from Nuvoton Mbed device" }
+
+MQTT unsubscribes from Nuvoton/Mbed/+ OK
+Subscribes/publishes user topic OK
+
+Subscribing/publishing UpdateThingShadow topic
+MQTT subscribes to $aws/things/Nuvoton-Mbed-D001/shadow/update/accepted OK
+MQTT subscribes to $aws/things/Nuvoton-Mbed-D001/shadow/update/rejected OK
+Message to publish:
+{ "state": { "reported": { "attribute1": 3, "attribute2": "1" } } }
+MQTT publishes message to $aws/things/Nuvoton-Mbed-D001/shadow/update OK
+Message arrived: qos 1, retained 0, dup 0, packetid 1
+Payload:
+{"state":{"reported":{"attribute1":3,"attribute2":"1"}},"metadata":{"reported":{"attribute1":{"timestamp":1514962195},"attribute2":{"timestamp":1514962195}}},"version":77,"timestamp":1514962195}
+
+MQTT unsubscribes from $aws/things/Nuvoton-Mbed-D001/shadow/update/accepted OK
+MQTT unsubscribes from $aws/things/Nuvoton-Mbed-D001/shadow/update/rejected OK
+Subscribes/publishes UpdateThingShadow topic OK
+
+Subscribing/publishing GetThingShadow topic
+MQTT subscribes to $aws/things/Nuvoton-Mbed-D001/shadow/get/accepted OK
+MQTT subscribes to $aws/things/Nuvoton-Mbed-D001/shadow/get/rejected OK
+Message to publish:
+
+MQTT publishes message to $aws/things/Nuvoton-Mbed-D001/shadow/get OK
+Message arrived: qos 1, retained 0, dup 0, packetid 1
+Payload:
+{"state":{"reported":{"attribute1":3,"attribute2":"1"}},"metadata":{"reported":{"attribute1":{"timestamp":1514962195},"attribute2":{"timestamp":1514962195}}},"version":77,"timestamp":1514962198}
+
+MQTT unsubscribes from $aws/things/Nuvoton-Mbed-D001/shadow/get/accepted OK
+MQTT unsubscribes from $aws/things/Nuvoton-Mbed-D001/shadow/get/rejected OK
+Subscribes/publishes GetThingShadow topic OK
+
+Subscribing/publishing DeleteThingShadow topic
+MQTT subscribes to $aws/things/Nuvoton-Mbed-D001/shadow/delete/accepted OK
+MQTT subscribes to $aws/things/Nuvoton-Mbed-D001/shadow/delete/rejected OK
+Message to publish:
+
+MQTT publishes message to $aws/things/Nuvoton-Mbed-D001/shadow/delete OK
+Message arrived: qos 1, retained 0, dup 0, packetid 1
+Payload:
+{"version":77,"timestamp":1514962202}
+
+MQTT unsubscribes from $aws/things/Nuvoton-Mbed-D001/shadow/delete/accepted OK
+MQTT unsubscribes from $aws/things/Nuvoton-Mbed-D001/shadow/delete/rejected OK
+Subscribes/publishes DeleteThingShadow topic OK
+
+MQTT disconnects OK
+</pre>
+
+Dynamic memory footprint (heap) is output below.
+Static memory footprint (global/stack) could be obtained by inspecting MAP file.
+You could get total memory footprint by adding these two together.
+<pre>
+Current heap size: 1351
+Max heap size: 63022
+</pre>
+
+## Trouble-shooting
+- Over ESP8266 WiFi,
+  if you make a loop test like below (`main.cpp`), you may always meet errors in the following loops
+  after some network error has happened in the previous one.
+    <pre>
+    <b>while (true) {</b>
+        #if AWS_IOT_MQTT_TEST
+            AWS_IoT_MQTT_Test *mqtt_test = new AWS_IoT_MQTT_Test(AWS_IOT_MQTT_SERVER_NAME, AWS_IOT_MQTT_SERVER_PORT, network);
+            mqtt_test->start_test();
+            delete mqtt_test;
+        #endif  // End of AWS_IOT_MQTT_TEST
+    
+        #if AWS_IOT_HTTPS_TEST
+            AWS_IoT_HTTPS_Test *https_test = new AWS_IoT_HTTPS_Test(AWS_IOT_HTTPS_SERVER_NAME, AWS_IOT_HTTPS_SERVER_PORT, network);
+            https_test->start_test();
+            delete https_test;
+        #endif  // End of AWS_IOT_HTTPS_TEST
+    <b>}</b>
+    </pre>
+    This issue would be caused by failure of ESP8266 AT commands **CLOSE**/**DISCONNECT**
+    because ESP8266 F/W is still busy in handling previous unfinished network transfer
+    due to bad network status and fails these commands.
+    These commands must be OK for ESP8266 F/W to reset connection state correctly.
+    If that happens, try enlarging [ESP8266 driver's](https://github.com/ARMmbed/esp8266-driver) timeout configuration.
+    For example, enlarge `ESP8266_SEND_TIMEOUT`/`ESP8266_RECV_TIMEOUT`/`ESP8266_MISC_TIMEOUT` (defined in
+    [ESP8266Interface.cpp](https://github.com/ARMmbed/esp8266-driver/blob/master/ESP8266Interface.cpp))
+    to 5000/5000/5000 ms respectively (through `mbed_app.json`).
+    <pre>
+    {
+        "macros": [
+            "MBED_CONF_APP_MAIN_STACK_SIZE=4096",
+            "MBEDTLS_USER_CONFIG_FILE=\"mbedtls_user_config.h\"",
+            "MBED_HEAP_STATS_ENABLED=1",
+            "MBED_MEM_TRACING_ENABLED=1",
+            <b>"ESP8266_SEND_TIMEOUT=5000",</b>
+            <b>"ESP8266_RECV_TIMEOUT=5000",</b>
+            <b>"ESP8266_MISC_TIMEOUT=5000"</b>
+        ],
+        "config": {
+    </pre>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TLSSocket.h	Wed Mar 14 03:03:16 2018 +0000
@@ -0,0 +1,420 @@
+#ifndef _TLS_SOCKET_H_
+#define _TLS_SOCKET_H_
+
+/* Change to a number between 1 and 4 to debug the TLS connection */
+#define DEBUG_LEVEL 0
+
+#include "mbedtls/platform.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/error.h"
+
+#if DEBUG_LEVEL > 0
+#include "mbedtls/debug.h"
+#endif
+
+#include "mbedtls_utils.h"
+    
+/**
+ * \brief TLSSocket a wrapper around TCPSocket for interacting with TLS servers
+ */
+class TLSSocket {
+public:
+    TLSSocket(NetworkInterface* net_iface, const char* ssl_ca_pem, const char* ssl_owncert_pem, const char* ssl_own_priv_key_pem) {
+        _tcpsocket = new TCPSocket(net_iface);
+        _ssl_ca_pem = ssl_ca_pem;
+        _ssl_owncert_pem = ssl_owncert_pem;
+        _ssl_own_priv_key_pem = ssl_own_priv_key_pem;
+        _is_connected = false;
+        _debug = false;
+        _hostname = NULL;
+        _port = 0;
+        _error = 0;
+
+        DRBG_PERS = "mbed TLS helloword client";
+
+        mbedtls_entropy_init(&_entropy);
+        mbedtls_ctr_drbg_init(&_ctr_drbg);
+        mbedtls_x509_crt_init(&_cacert);
+        mbedtls_x509_crt_init(&_owncert);
+        mbedtls_pk_init(&_own_priv_key);
+        mbedtls_ssl_init(&_ssl);
+        mbedtls_ssl_config_init(&_ssl_conf);
+    }
+
+    ~TLSSocket() {
+        mbedtls_entropy_free(&_entropy);
+        mbedtls_ctr_drbg_free(&_ctr_drbg);
+        mbedtls_x509_crt_free(&_cacert);
+        mbedtls_x509_crt_free(&_owncert);
+        mbedtls_pk_free(&_own_priv_key);
+        mbedtls_ssl_free(&_ssl);
+        mbedtls_ssl_config_free(&_ssl_conf);
+
+        if (_tcpsocket) {
+            _tcpsocket->close();
+            delete _tcpsocket;
+        }
+
+        // @todo: free DRBG_PERS ?
+    }
+
+    /** Close the socket
+     *
+     *  Closes any open connection and deallocates any memory associated
+     *  with the socket. Called from destructor if socket is not closed.
+     *
+     *  @return         0 on success, negative error code on failure
+     */
+    nsapi_error_t close() {
+        return _tcpsocket->close();
+    }
+    
+    nsapi_error_t connect(const char *hostname, uint16_t port) {
+        _hostname = hostname;
+        _port = port;
+        
+        /* Initialize the flags */
+        /*
+         * Initialize TLS-related stuf.
+         */
+        int ret;
+        if ((ret = mbedtls_ctr_drbg_seed(&_ctr_drbg, mbedtls_entropy_func, &_entropy,
+                          (const unsigned char *) DRBG_PERS,
+                          sizeof (DRBG_PERS))) != 0) {
+            print_mbedtls_error("mbedtls_crt_drbg_init", ret);
+            _error = ret;
+            return _error;
+        }
+
+        if ((ret = mbedtls_x509_crt_parse(&_cacert, (const unsigned char *)_ssl_ca_pem,
+                           strlen(_ssl_ca_pem) + 1)) != 0) {
+            print_mbedtls_error("mbedtls_x509_crt_parse", ret);
+            _error = ret;
+            return _error;
+        }
+
+        if ((ret = mbedtls_x509_crt_parse(&_owncert, (const unsigned char *) _ssl_owncert_pem,
+                           strlen(_ssl_owncert_pem) + 1)) != 0) {
+            print_mbedtls_error("mbedtls_x509_crt_parse", ret);
+            _error = ret;
+            return _error;
+        }
+        
+        if ((ret = mbedtls_pk_parse_key(&_own_priv_key, (const unsigned char *) _ssl_own_priv_key_pem,
+                           strlen(_ssl_own_priv_key_pem) + 1, NULL, 0)) != 0) {
+            print_mbedtls_error("mbedtls_pk_parse_key", ret);
+            _error = ret;
+            return _error;
+        }
+        
+        if ((ret = mbedtls_ssl_config_defaults(&_ssl_conf,
+                        MBEDTLS_SSL_IS_CLIENT,
+                        MBEDTLS_SSL_TRANSPORT_STREAM,
+                        MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
+            print_mbedtls_error("mbedtls_ssl_config_defaults", ret);
+            _error = ret;
+            return _error;
+        }
+
+        mbedtls_ssl_conf_ca_chain(&_ssl_conf, &_cacert, NULL);
+        mbedtls_ssl_conf_own_cert(&_ssl_conf, &_owncert, &_own_priv_key);
+        mbedtls_ssl_conf_rng(&_ssl_conf, mbedtls_ctr_drbg_random, &_ctr_drbg);
+
+        /* It is possible to disable authentication by passing
+         * MBEDTLS_SSL_VERIFY_NONE in the call to mbedtls_ssl_conf_authmode()
+         */
+        mbedtls_ssl_conf_authmode(&_ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
+
+#if DEBUG_LEVEL > 0
+        mbedtls_ssl_conf_verify(&_ssl_conf, my_verify, NULL);
+        mbedtls_ssl_conf_dbg(&_ssl_conf, my_debug, NULL);
+        mbedtls_debug_set_threshold(DEBUG_LEVEL);
+#endif
+
+        if ((ret = mbedtls_ssl_setup(&_ssl, &_ssl_conf)) != 0) {
+            print_mbedtls_error("mbedtls_ssl_setup", ret);
+            _error = ret;
+            return _error;
+        }
+
+        mbedtls_ssl_set_hostname(&_ssl, _hostname);
+
+        mbedtls_ssl_set_bio(&_ssl, static_cast<void *>(_tcpsocket),
+                                   ssl_send, ssl_recv, NULL );
+
+        /* Connect to the server */
+        if (_debug) mbedtls_printf("Connecting to %s:%d\r\n", _hostname, _port);
+        ret = _tcpsocket->connect(_hostname, _port);
+        if (ret != NSAPI_ERROR_OK) {
+            if (_debug) mbedtls_printf("Failed to connect\r\n");
+            onError(_tcpsocket, -1);
+            return _error;
+        }
+
+       /* Start the handshake, the rest will be done in onReceive() */
+        if (_debug) mbedtls_printf("Starting the TLS handshake...\r\n");
+        do {
+            ret = mbedtls_ssl_handshake(&_ssl);
+        } while (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+        if (ret < 0) {
+            print_mbedtls_error("mbedtls_ssl_handshake", ret);
+            onError(_tcpsocket, ret);
+            return ret;
+        }
+            
+        /* It also means the handshake is done, time to print info */
+        if (_debug) mbedtls_printf("TLS connection to %s:%d established\r\n", _hostname, _port);
+
+        const uint32_t buf_size = 1024;
+        char *buf = new char[buf_size];
+        mbedtls_x509_crt_info(buf, buf_size, "\r    ",
+                        mbedtls_ssl_get_peer_cert(&_ssl));
+        if (_debug) mbedtls_printf("Server certificate:\r\n%s\r", buf);
+
+        uint32_t flags = mbedtls_ssl_get_verify_result(&_ssl);
+        if( flags != 0 )
+        {
+            mbedtls_x509_crt_verify_info(buf, buf_size, "\r  ! ", flags);
+            if (_debug) mbedtls_printf("Certificate verification failed:\r\n%s\r\r\n", buf);
+        }
+        else {
+            if (_debug) mbedtls_printf("Certificate verification passed\r\n\r\n");
+        }
+        delete [] buf;
+        buf = NULL;
+
+        _is_connected = true;
+
+        return 0;
+    }
+
+    /** Send data over a TCP socket
+     *
+     *  The socket must be connected to a remote host. Returns the number of
+     *  bytes sent from the buffer.
+     *
+     *  By default, send blocks until all data is sent. If socket is set to
+     *  non-blocking or times out, a partial amount can be written.
+     *  NSAPI_ERROR_WOULD_BLOCK is returned if no data was written.
+     *
+     *  @param data     Buffer of data to send to the host
+     *  @param size     Size of the buffer in bytes
+     *  @return         Number of sent bytes on success, negative error
+     *                  code on failure
+     */
+    nsapi_size_or_error_t send(const void *data, nsapi_size_t size) {
+        return mbedtls_ssl_write(&_ssl, (const uint8_t *) data, size);
+    }
+    
+    /** Receive data over a TCP socket
+     *
+     *  The socket must be connected to a remote host. Returns the number of
+     *  bytes received into the buffer.
+     *
+     *  By default, recv blocks until some data is received. If socket is set to
+     *  non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK can be returned to
+     *  indicate no data.
+     *
+     *  @param data     Destination buffer for data received from the host
+     *  @param size     Size of the buffer in bytes
+     *  @return         Number of received bytes on success, negative error
+     *                  code on failure
+     */
+    nsapi_size_or_error_t recv(void *data, nsapi_size_t size) {
+        return mbedtls_ssl_read(&_ssl, (uint8_t *) data, size);
+    }
+    
+    /** Set blocking or non-blocking mode of the socket
+     *
+     *  Initially all sockets are in blocking mode. In non-blocking mode
+     *  blocking operations such as send/recv/accept return
+     *  NSAPI_ERROR_WOULD_BLOCK if they can not continue.
+     *
+     *  set_blocking(false) is equivalent to set_timeout(-1)
+     *  set_blocking(true) is equivalent to set_timeout(0)
+     *
+     *  @param blocking true for blocking mode, false for non-blocking mode.
+     */
+    void set_blocking(bool blocking) {
+        _tcpsocket->set_blocking(blocking);
+    }
+    
+    /** Set timeout on blocking socket operations
+     *
+     *  Initially all sockets have unbounded timeouts. NSAPI_ERROR_WOULD_BLOCK
+     *  is returned if a blocking operation takes longer than the specified
+     *  timeout. A timeout of 0 removes the timeout from the socket. A negative
+     *  value give the socket an unbounded timeout.
+     *
+     *  set_timeout(0) is equivalent to set_blocking(false)
+     *  set_timeout(-1) is equivalent to set_blocking(true)
+     *
+     *  @param timeout  Timeout in milliseconds
+     */
+    void set_timeout(int timeout) {
+        _tcpsocket->set_timeout(timeout);
+    }
+    
+    bool connected() {
+        return _is_connected;
+    }
+
+    nsapi_error_t error() {
+        return _error;
+    }
+
+    TCPSocket* get_tcp_socket() {
+        return _tcpsocket;
+    }
+
+    mbedtls_ssl_context* get_ssl_context() {
+        return &_ssl;
+    }
+
+    /**
+     * Set the debug flag.
+     *
+     * If this flag is set, debug information from mbed TLS will be logged to stdout.
+     */
+    void set_debug(bool debug) {
+        _debug = debug;
+    }
+    
+    /**
+     * Timed recv for MQTT lib
+     */
+    int read(unsigned char* buffer, int len, int timeout) {
+        set_timeout(timeout);
+        return recv(buffer, len);
+    }
+
+    /**
+     * Timed send for MQTT lib
+     */
+    int write(unsigned char* buffer, int len, int timeout) {
+        set_timeout(timeout);
+        return send(buffer, len);
+    }
+    
+protected:
+
+#if DEBUG_LEVEL > 0
+    /**
+     * Debug callback for mbed TLS
+     * Just prints on the USB serial port
+     */
+    static void my_debug(void *ctx, int level, const char *file, int line,
+                         const char *str)
+    {
+        const char *p, *basename;
+        (void) ctx;
+
+        /* Extract basename from file */
+        for(p = basename = file; *p != '\0'; p++) {
+            if(*p == '/' || *p == '\\') {
+                basename = p + 1;
+            }
+        }
+
+        if (_debug) {
+            mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str);
+        }
+    }
+
+    /**
+     * Certificate verification callback for mbed TLS
+     * Here we only use it to display information on each cert in the chain
+     */
+    static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
+    {
+        const uint32_t buf_size = 1024;
+        char *buf = new char[buf_size];
+        (void) data;
+
+        if (_debug) mbedtls_printf("\nVerifying certificate at depth %d:\n", depth);
+        mbedtls_x509_crt_info(buf, buf_size - 1, "  ", crt);
+        if (_debug) mbedtls_printf("%s", buf);
+
+        if (*flags == 0)
+            if (_debug) mbedtls_printf("No verification issue for this certificate\n");
+        else
+        {
+            mbedtls_x509_crt_verify_info(buf, buf_size, "  ! ", *flags);
+            if (_debug) mbedtls_printf("%s\n", buf);
+        }
+
+        delete[] buf;
+        return 0;
+    }
+#endif
+
+    /**
+     * Receive callback for mbed TLS
+     */
+    static int ssl_recv(void *ctx, unsigned char *buf, size_t len) {
+        int recv = -1;
+        TCPSocket *socket = static_cast<TCPSocket *>(ctx);
+        recv = socket->recv(buf, len);
+
+        if (NSAPI_ERROR_WOULD_BLOCK == recv) {
+            return MBEDTLS_ERR_SSL_WANT_READ;
+        }
+        else if (recv < 0) {
+            return -1;
+        }
+        else {
+            return recv;
+        }
+   }
+
+    /**
+     * Send callback for mbed TLS
+     */
+    static int ssl_send(void *ctx, const unsigned char *buf, size_t len) {
+       int size = -1;
+        TCPSocket *socket = static_cast<TCPSocket *>(ctx);
+        size = socket->send(buf, len);
+
+        if(NSAPI_ERROR_WOULD_BLOCK == size) {
+            return MBEDTLS_ERR_SSL_WANT_WRITE;
+        }
+        else if (size < 0){
+            return -1;
+        }
+        else {
+            return size;
+        }
+    }
+
+private:
+    void onError(TCPSocket *s, int error) {
+        s->close();
+        _error = error;
+    }
+
+    TCPSocket* _tcpsocket;
+
+    const char* DRBG_PERS;
+    const char* _ssl_ca_pem;
+    const char* _ssl_owncert_pem;
+    const char* _ssl_own_priv_key_pem;
+    const char* _hostname;
+    uint16_t _port;
+
+    bool _debug;
+    bool _is_connected;
+
+    nsapi_error_t _error;
+
+    mbedtls_entropy_context _entropy;
+    mbedtls_ctr_drbg_context _ctr_drbg;
+    mbedtls_x509_crt _cacert;
+    mbedtls_x509_crt _owncert;
+    mbedtls_pk_context _own_priv_key;
+    mbedtls_ssl_context _ssl;
+    mbedtls_ssl_config _ssl_conf;
+};
+
+#endif // _TLS_SOCKET_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easy-connect.lib	Wed Mar 14 03:03:16 2018 +0000
@@ -0,0 +1,1 @@
+https://github.com/ARMmbed/easy-connect/#1d9be07aa4c8a8fcf8fc482116f2a8b1f60a2957
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Mar 14 03:03:16 2018 +0000
@@ -0,0 +1,739 @@
+/* This example demonstrates connection with AWS IoT through MQTT/HTTPS protocol. 
+ *
+ * AWS IoT: Thing Shadow MQTT Topics 
+ * http://docs.aws.amazon.com/iot/latest/developerguide/thing-shadow-mqtt.html
+ *
+ * AWS IoT: Publish to a topic through HTTPS/POST method:
+ * http://docs.aws.amazon.com/iot/latest/developerguide/protocols.html
+ *
+ * AWS IoT: Thing Shadow RESTful API:
+ * http://docs.aws.amazon.com/iot/latest/developerguide/thing-shadow-rest-api.html
+ */
+
+#define AWS_IOT_MQTT_TEST       1
+#define AWS_IOT_HTTPS_TEST      0
+
+#include "mbed.h"
+#include "easy-connect.h"
+
+/* TLSSocket = Mbed TLS over TCPSocket */
+#include "TLSSocket.h"
+
+/* Measure memory footprint */
+#include "mbed_stats.h"
+
+#if AWS_IOT_MQTT_TEST
+/* MQTT-specific header files */
+#include "MQTTmbed.h"
+#include "MQTTClient.h"
+#endif  // End of AWS_IOT_MQTT_TEST
+
+
+namespace {
+
+/* List of trusted root CA certificates
+ * currently only GlobalSign, the CA for os.mbed.com
+ *
+ * To add more than one root, just concatenate them.
+ */
+const char SSL_CA_CERT_PEM[] = "-----BEGIN CERTIFICATE-----\n"
+    "MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB\n"
+    "yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL\n"
+    "ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp\n"
+    "U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW\n"
+    "ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0\n"
+    "aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL\n"
+    "MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW\n"
+    "ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln\n"
+    "biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp\n"
+    "U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\n"
+    "aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1\n"
+    "nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex\n"
+    "t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz\n"
+    "SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG\n"
+    "BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+\n"
+    "rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/\n"
+    "NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E\n"
+    "BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH\n"
+    "BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy\n"
+    "aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv\n"
+    "MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE\n"
+    "p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y\n"
+    "5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK\n"
+    "WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ\n"
+    "4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N\n"
+    "hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq\n"
+    "-----END CERTIFICATE-----\n";
+
+/* User certificate which has been activated and attached with specific thing and policy */
+const char SSL_USER_CERT_PEM[] = "-----BEGIN CERTIFICATE-----\n"
+    "MIIDWjCCAkKgAwIBAgIVALN/H7tr8cgpl2zwg0JjEE106XilMA0GCSqGSIb3DQEB\n"
+    "CwUAME0xSzBJBgNVBAsMQkFtYXpvbiBXZWIgU2VydmljZXMgTz1BbWF6b24uY29t\n"
+    "IEluYy4gTD1TZWF0dGxlIFNUPVdhc2hpbmd0b24gQz1VUzAeFw0xNzEyMTQwOTE3\n"
+    "MjdaFw00OTEyMzEyMzU5NTlaMB4xHDAaBgNVBAMME0FXUyBJb1QgQ2VydGlmaWNh\n"
+    "dGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDM/Ebg1vx305GeuQk8\n"
+    "UeYr+5IGBEoF6QwY9wjjliQMZKoIQk8eLYZxyjq/i0WRoXy+4l2IOZC0621bahHS\n"
+    "2iPC07Uxj1BXBW+f+V0pBnUnnGK0tT3uGOFVOoPUBoiYU9mB/Anv4wXRdqrUNAMW\n"
+    "Mq/lAzOvgfyFXnTu0AtvWwISNiAk3ly2E+3PC/Ma9RyMOAjsRUbQo66f2ERmd8yZ\n"
+    "PgCXlb/x2kCnjnkau6MS0tg83Ro+QvyQGqBRf3fbYIS8Hz6mIKGffguuelEEoMqP\n"
+    "H0beG0GO/T73uUAscbrOWzoVlNmFVt6Ly53s1tm9j/Spldl4EKmMD3vNetkInYDo\n"
+    "O55zAgMBAAGjYDBeMB8GA1UdIwQYMBaAFE17U+bgCNXEKf4sP134dtHLiNtcMB0G\n"
+    "A1UdDgQWBBSP7arfS0NaGmkNFBTg7SakJy0qEDAMBgNVHRMBAf8EAjAAMA4GA1Ud\n"
+    "DwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAW5RDTsZjhlkThMOrrP2XH1Cr\n"
+    "9rcoXGqo+jOq5a/yX/LVIM2W/9bIIaOEDScP2haJWceq0C1O6t2JGL0UtNGFyjYS\n"
+    "0Z3bCv77MNLhWc8GeIRHWAd65dlEspKO8P7UHNppHhh4/oKYpP2Nu/pvguofgIw6\n"
+    "XbKk9PYz4n/ebdhWi6nTBi6Yc3d9aczMh227HcUz7RFoBEhKhOi7IDWzS9X+sqfD\n"
+    "fg5NV+A4w6GMTAmLVU8ryodohSTaz34+bElnCdrAnMeSpR8BElTmojSdrA5eY5qZ\n"
+    "ib7kkPRPyM3QuqTiMPMyxdVDxkoNtRrJ8zw+l443oKvVsUvDZJbHURUt2d4htA==\n"
+    "-----END CERTIFICATE-----\n";
+
+/* User private key paired with above */
+const char SSL_USER_PRIV_KEY_PEM[] = "-----BEGIN RSA PRIVATE KEY-----\n"
+    "MIIEowIBAAKCAQEAzPxG4Nb8d9ORnrkJPFHmK/uSBgRKBekMGPcI45YkDGSqCEJP\n"
+    "Hi2Gcco6v4tFkaF8vuJdiDmQtOttW2oR0tojwtO1MY9QVwVvn/ldKQZ1J5xitLU9\n"
+    "7hjhVTqD1AaImFPZgfwJ7+MF0Xaq1DQDFjKv5QMzr4H8hV507tALb1sCEjYgJN5c\n"
+    "thPtzwvzGvUcjDgI7EVG0KOun9hEZnfMmT4Al5W/8dpAp455GrujEtLYPN0aPkL8\n"
+    "kBqgUX9322CEvB8+piChn34LrnpRBKDKjx9G3htBjv0+97lALHG6zls6FZTZhVbe\n"
+    "i8ud7NbZvY/0qZXZeBCpjA97zXrZCJ2A6DuecwIDAQABAoIBAEbY7rppM6tKoWrl\n"
+    "cy6487/B3E9eDiOKz5aVUyoty1nJNQdTu7qna29KwRFQ1oOl99KVtFQP6VbOg+Zz\n"
+    "e6OPp4p/14FAkjjxdQoqiqtSQw2kvGzOs4/mY4MsjUGr3GwhluyZKuoRYgJqbFKZ\n"
+    "g3OZozeY6rU/TQLfibS8jSc4ojeehQx3cesJmnYA16iFjN8K/D2Tw+aJiKx+0D8k\n"
+    "nbpy19/2MzBW+UhunMpCtfDNx/HLQAYtzxbxczw7yUiQnmyf+0t0/+xm0m04eic1\n"
+    "GRHHInZSKzMfGtzyJXliFP5o92dspCm5vsiyXMcPzqcX192IZSixbG8etrJk8jXy\n"
+    "bTi85VkCgYEA6hOkrSZjbZvsgtjJCIbjMmn9rpBrG0Bv+V1gJ/dH3hZjo2qUnVB0\n"
+    "8PfBZ+oOoNjEWJlS38zf4pwHSBR6WzvH/o35EHvXNCcdKA82jmv0lbbdH2a4y19n\n"
+    "lnlyEocsFmPtyuSp+TwIxKI1d+mk9q9D6FgWyLHSddn/qY56txOx7M8CgYEA4C8f\n"
+    "6bz4a64KBnIZ7yWwwNkZ3Jn8wI62NiZpPpY5PfKtdYCdBHyuCWApE0e8pZy6fTTN\n"
+    "VVH9RJEq3UHxvEPzNOOhlAoRKT3BakmQ+Yw9Dg+xk6XiiCQuJcEnWG+IUFIjsxEK\n"
+    "SgSfzrVHtF3udlbP58b3gOSZvxBt8a3qBFPARR0CgYEA08hIAz0rUn1zxIMdiHB6\n"
+    "WR+anXke3v4zEVwRZreNt3tsVOtWYOrtkyOmQj17VL4rD7pRSBmWKvJeiDG27pqs\n"
+    "/Tw4r1hMwmvtLlRtWPiFx3s2n3WSFrdQAs4IjojsM6nf+OVggBZ4HGhilga38VVr\n"
+    "zGj+3EA/Gc/OR/uYPdI89fMCgYAHOz3qSkAxKQIFxzRy9GJJNjeRWB5BD9ls0bxf\n"
+    "WnUqPGPAAJAQDv2GK+XnS08YgH+7fjKJaAWlapFZZcEoc4Cq2hTiM5juHaHZjdnx\n"
+    "Usa9Z2AxBQ7TmWcrrJlaTu60uJGSOyB71r5Y6pwPg2AnzRETxuVA8R7MfPku7I85\n"
+    "6IGxOQKBgHyvFe38EHJndwgTZYK0fWWghRb6XmdH4MxZip2W6yO2Kzav6JuWamV6\n"
+    "0x80T4RWTpWFXVb288EkSEambrKX8Y0ihn7bFK/cAxD4j7oAGJCgW85mbMAZsj4b\n"
+    "OAvPvajSMJKyKrgIX/wMfTQlTqAvcsEA2FbrgX67BEBw9HUP2Mm6\n"
+    "-----END RSA PRIVATE KEY-----\n";
+
+#if AWS_IOT_MQTT_TEST
+
+#define AWS_IOT_MQTT_SERVER_NAME                "a1fbcwaqfqeozo.iot.us-east-1.amazonaws.com"
+#define AWS_IOT_MQTT_SERVER_PORT                8883
+
+#define AWS_IOT_MQTT_THINGNAME                  "Nuvoton-Mbed-D001"
+#define AWS_IOT_MQTT_CLIENTNAME                 "Nuvoton Client"
+
+/* User self-test topic */
+const char USER_MQTT_TOPIC[] = "Nuvoton/Mbed/D001";
+const char *USER_MQTT_TOPIC_FILTERS[] = {
+    "Nuvoton/Mbed/+"
+};
+const char USER_MQTT_TOPIC_PUBLISH_MESSAGE[] = "{ \"message\": \"Hello from Nuvoton Mbed device\" }";
+
+/* Update thing shadow */
+const char UPDATETHINGSHADOW_MQTT_TOPIC[] = "$aws/things/" AWS_IOT_MQTT_THINGNAME "/shadow/update";
+const char *UPDATETHINGSHADOW_MQTT_TOPIC_FILTERS[] = {
+    "$aws/things/" AWS_IOT_MQTT_THINGNAME "/shadow/update/accepted",
+    "$aws/things/" AWS_IOT_MQTT_THINGNAME "/shadow/update/rejected"
+};
+const char UPDATETHINGSHADOW_MQTT_TOPIC_PUBLISH_MESSAGE[] = "{ \"state\": { \"reported\": { \"attribute1\": 3, \"attribute2\": \"1\" } } }";
+
+/* Get thing shadow */
+const char GETTHINGSHADOW_MQTT_TOPIC[] = "$aws/things/" AWS_IOT_MQTT_THINGNAME "/shadow/get";
+const char *GETTHINGSHADOW_MQTT_TOPIC_FILTERS[] = {
+    "$aws/things/" AWS_IOT_MQTT_THINGNAME "/shadow/get/accepted",
+    "$aws/things/" AWS_IOT_MQTT_THINGNAME "/shadow/get/rejected"
+};
+const char GETTHINGSHADOW_MQTT_TOPIC_PUBLISH_MESSAGE[] = "";
+
+/* Delete thing shadow */
+const char DELETETHINGSHADOW_MQTT_TOPIC[] = "$aws/things/" AWS_IOT_MQTT_THINGNAME "/shadow/delete";
+const char *DELETETHINGSHADOW_MQTT_TOPIC_FILTERS[] = {
+    "$aws/things/" AWS_IOT_MQTT_THINGNAME "/shadow/delete/accepted",
+    "$aws/things/" AWS_IOT_MQTT_THINGNAME "/shadow/delete/rejected"
+};
+const char DELETETHINGSHADOW_MQTT_TOPIC_PUBLISH_MESSAGE[] = "";
+
+/* MQTT user buffer size */
+const int MQTT_USER_BUFFER_SIZE = 600;
+
+/* Configure MAX_MQTT_PACKET_SIZE to meet your application.
+ * We may meet unknown MQTT error with MAX_MQTT_PACKET_SIZE too small, but 
+ * MQTT lib doesn't tell enough error message. Try to enlarge it. */
+const int MAX_MQTT_PACKET_SIZE = 1000;
+
+#endif  // End of AWS_IOT_MQTT_TEST
+
+#if AWS_IOT_HTTPS_TEST
+
+#define AWS_IOT_HTTPS_SERVER_NAME               "a1fbcwaqfqeozo.iot.us-east-1.amazonaws.com"
+#define AWS_IOT_HTTPS_SERVER_PORT               8443
+
+#define AWS_IOT_HTTPS_THINGNAME                 "Nuvoton-Mbed-D001"
+
+/* Publish to user topic through HTTPS/POST 
+ * HTTP POST https://"endpoint"/topics/"yourTopicHierarchy" */
+const char USER_TOPIC_HTTPS_PATH[] = "/topics/Nuvoton/Mbed/D001?qos=1";
+const char USER_TOPIC_HTTPS_REQUEST_METHOD[] = "POST";
+const char USER_TOPIC_HTTPS_REQUEST_MESSAGE_BODY[] = "{ \"message\": \"Hello from Nuvoton Mbed device\" }";
+
+/* Update thing shadow by publishing to UpdateThingShadow topic through HTTPS/POST
+ * HTTP POST https://"endpoint"/topics/$aws/things/"thingName"/shadow/update */
+const char UPDATETHINGSHADOW_TOPIC_HTTPS_PATH[] = "/topics/$aws/things/" AWS_IOT_HTTPS_THINGNAME "/shadow/update?qos=1";
+const char UPDATETHINGSHADOW_TOPIC_HTTPS_REQUEST_METHOD[] = "POST";
+const char UPDATETHINGSHADOW_TOPIC_HTTPS_REQUEST_MESSAGE_BODY[] = "{ \"state\": { \"reported\": { \"attribute1\": 3, \"attribute2\": \"1\" } } }";
+
+/* Get thing shadow by publishing to GetThingShadow topic through HTTPS/POST
+ * HTTP POST https://"endpoint"/topics/$aws/things/"thingName"/shadow/get */
+const char GETTHINGSHADOW_TOPIC_HTTPS_PATH[] = "/topics/$aws/things/" AWS_IOT_HTTPS_THINGNAME "/shadow/get?qos=1";
+const char GETTHINGSHADOW_TOPIC_HTTPS_REQUEST_METHOD[] = "POST";
+const char GETTHINGSHADOW_TOPIC_HTTPS_REQUEST_MESSAGE_BODY[] = "";
+
+/* Delete thing shadow by publishing to DeleteThingShadow topic through HTTPS/POST
+ * HTTP POST https://"endpoint"/topics/$aws/things/"thingName"/shadow/delete */
+const char DELETETHINGSHADOW_TOPIC_HTTPS_PATH[] = "/topics/$aws/things/" AWS_IOT_HTTPS_THINGNAME "/shadow/delete?qos=1";
+const char DELETETHINGSHADOW_TOPIC_HTTPS_REQUEST_METHOD[] = "POST";
+const char DELETETHINGSHADOW_TOPIC_HTTPS_REQUEST_MESSAGE_BODY[] = "";
+
+/* Update thing shadow RESTfully through HTTPS/POST
+ * HTTP POST https://endpoint/things/thingName/shadow */
+const char UPDATETHINGSHADOW_THING_HTTPS_PATH[] = "/things/" AWS_IOT_HTTPS_THINGNAME "/shadow";
+const char UPDATETHINGSHADOW_THING_HTTPS_REQUEST_METHOD[] = "POST";
+const char UPDATETHINGSHADOW_THING_HTTPS_REQUEST_MESSAGE_BODY[] = "{ \"state\": { \"desired\": { \"attribute1\": 1, \"attribute2\": \"2\" }, \"reported\": { \"attribute1\": 2, \"attribute2\": \"1\" } } }";
+
+/* Get thing shadow RESTfully through HTTPS/GET
+ * HTTP GET https://"endpoint"/things/"thingName"/shadow */
+const char GETTHINGSHADOW_THING_HTTPS_PATH[] = "/things/" AWS_IOT_HTTPS_THINGNAME "/shadow";
+const char GETTHINGSHADOW_THING_HTTPS_REQUEST_METHOD[] = "GET";
+const char GETTHINGSHADOW_THING_HTTPS_REQUEST_MESSAGE_BODY[] = "";
+
+/* Delete thing shadow RESTfully through HTTPS/DELETE
+ * HTTP DELETE https://endpoint/things/thingName/shadow */
+const char DELETETHINGSHADOW_THING_HTTPS_PATH[] = "/things/" AWS_IOT_HTTPS_THINGNAME "/shadow";
+const char DELETETHINGSHADOW_THING_HTTPS_REQUEST_METHOD[] = "DELETE";
+const char DELETETHINGSHADOW_THING_HTTPS_REQUEST_MESSAGE_BODY[] = "";
+
+/* HTTPS user buffer size */
+const int HTTPS_USER_BUFFER_SIZE = 600;
+
+const char *HTTPS_OK_STR = "200 OK";
+
+#endif  // End of AWS_IOT_HTTPS_TEST
+
+}
+
+#if AWS_IOT_MQTT_TEST
+
+/**
+ * /brief   AWS_IoT_MQTT_Test implements the logic with AWS IoT User/Thing Shadow topics through MQTT.
+ */
+class AWS_IoT_MQTT_Test {
+
+public:
+    /**
+     * @brief   AWS_IoT_MQTT_Test Constructor
+     *
+     * @param[in] domain    Domain name of the MQTT server
+     * @param[in] port      Port number of the MQTT server
+     * @param[in] net_iface Network interface
+     */
+    AWS_IoT_MQTT_Test(const char * domain, const uint16_t port, NetworkInterface *net_iface) :
+        _domain(domain), _port(port) {
+        _tlssocket = new TLSSocket(net_iface, SSL_CA_CERT_PEM, SSL_USER_CERT_PEM, SSL_USER_PRIV_KEY_PEM);
+        /* Blocking mode */
+        _tlssocket->set_blocking(true);
+        /* Print Mbed TLS handshake log */
+        _tlssocket->set_debug(true);
+
+        _mqtt_client = new MQTT::Client<TLSSocket, Countdown, MAX_MQTT_PACKET_SIZE>(*_tlssocket);
+    }
+
+    /**
+     * @brief AWS_IoT_MQTT_Test Destructor
+     */
+    ~AWS_IoT_MQTT_Test() {
+        delete _mqtt_client;
+        _mqtt_client = NULL;
+
+        _tlssocket->close();
+        delete _tlssocket;
+        _tlssocket = NULL;
+    }
+    /**
+     * @brief   Start AWS IoT test through MQTT
+     */
+    void start_test() {
+
+        int tls_rc;
+        int mqtt_rc;
+        
+        do {
+            /* Connect to the server */
+            /* Initialize TLS-related stuff */
+            printf("Connecting with %s:%d\n", _domain, _port);
+            tls_rc = _tlssocket->connect(_domain, _port);
+            if (tls_rc != NSAPI_ERROR_OK) {
+                printf("Connects with %s:%d failed: %d\n", _domain, _port, tls_rc);
+                break;
+            }
+            printf("Connects with %s:%d OK\n", _domain, _port);
+            
+            /* See the link below for AWS IoT support for MQTT:
+             * http://docs.aws.amazon.com/iot/latest/developerguide/protocols.html */
+         
+            /* MQTT connect */
+            /* The message broker does not support persistent sessions (connections made with 
+             * the cleanSession flag set to false. */
+            MQTTPacket_connectData conn_data = MQTTPacket_connectData_initializer;
+            /* AWS IoT message broker implementation is based on MQTT version 3.1.1
+             * 3 = 3.1
+             * 4 = 3.1.1 */
+            conn_data.MQTTVersion = 4;
+            /* Version number of this structure. Must be 0 */
+            conn_data.struct_version = 0;
+            /* The message broker uses the client ID to identify each client. The client ID is passed
+             * in from the client to the message broker as part of the MQTT payload. Two clients with
+             * the same client ID are not allowed to be connected concurrently to the message broker.
+             * When a client connects to the message broker using a client ID that another client is using,
+             * a CONNACK message will be sent to both clients and the currently connected client will be
+             * disconnected. */
+            conn_data.clientID.cstring = AWS_IOT_MQTT_CLIENTNAME;
+            /* The message broker does not support persistent sessions (connections made with 
+             * the cleanSession flag set to false. The AWS IoT message broker assumes all sessions 
+             * are clean sessions and messages are not stored across sessions. If an MQTT client 
+             * attempts to connect to the AWS IoT message broker with the cleanSession set to false, 
+             * the client will be disconnected. */
+            conn_data.cleansession = 1;
+            //conn_data.username.cstring = "USERNAME";
+            //conn_data.password.cstring = "PASSWORD";
+        
+            MQTT::connackData connack_data;
+        
+            /* _tlssocket must connect to the network endpoint before calling this. */
+            printf("MQTT connecting");
+            if ((mqtt_rc = _mqtt_client->connect(conn_data, connack_data)) != 0) {
+                printf("\rMQTT connects failed: %d\n", mqtt_rc);
+                break;
+            }
+            printf("\rMQTT connects OK\n\n");
+            
+            /* Subscribe/publish user topic */
+            printf("Subscribing/publishing user topic\n");
+            if (! sub_pub_topic(USER_MQTT_TOPIC, USER_MQTT_TOPIC_FILTERS, sizeof (USER_MQTT_TOPIC_FILTERS) / sizeof (USER_MQTT_TOPIC_FILTERS[0]), USER_MQTT_TOPIC_PUBLISH_MESSAGE)) {
+                break;
+            }
+            printf("Subscribes/publishes user topic OK\n\n");
+            
+            /* Subscribe/publish UpdateThingShadow topic */
+            printf("Subscribing/publishing UpdateThingShadow topic\n");
+            if (! sub_pub_topic(UPDATETHINGSHADOW_MQTT_TOPIC, UPDATETHINGSHADOW_MQTT_TOPIC_FILTERS, sizeof (UPDATETHINGSHADOW_MQTT_TOPIC_FILTERS) / sizeof (UPDATETHINGSHADOW_MQTT_TOPIC_FILTERS[0]), UPDATETHINGSHADOW_MQTT_TOPIC_PUBLISH_MESSAGE)) {
+                break;
+            }
+            printf("Subscribes/publishes UpdateThingShadow topic OK\n\n");
+            
+            /* Subscribe/publish GetThingShadow topic */
+            printf("Subscribing/publishing GetThingShadow topic\n");
+            if (! sub_pub_topic(GETTHINGSHADOW_MQTT_TOPIC, GETTHINGSHADOW_MQTT_TOPIC_FILTERS, sizeof (GETTHINGSHADOW_MQTT_TOPIC_FILTERS) / sizeof (GETTHINGSHADOW_MQTT_TOPIC_FILTERS[0]), GETTHINGSHADOW_MQTT_TOPIC_PUBLISH_MESSAGE)) {
+                break;
+            }
+            printf("Subscribes/publishes GetThingShadow topic OK\n\n");
+            
+            /* Subscribe/publish DeleteThingShadow topic */
+            printf("Subscribing/publishing DeleteThingShadow topic\n");
+            if (! sub_pub_topic(DELETETHINGSHADOW_MQTT_TOPIC, DELETETHINGSHADOW_MQTT_TOPIC_FILTERS, sizeof (DELETETHINGSHADOW_MQTT_TOPIC_FILTERS) / sizeof (DELETETHINGSHADOW_MQTT_TOPIC_FILTERS[0]), DELETETHINGSHADOW_MQTT_TOPIC_PUBLISH_MESSAGE)) {
+                break;
+            }
+            printf("Subscribes/publishes DeleteThingShadow topic OK\n\n");
+            
+        } while (0);
+        
+        printf("MQTT disconnecting");
+        if ((mqtt_rc = _mqtt_client->disconnect()) != 0) {
+            printf("\rMQTT disconnects failed %d\n", mqtt_rc);
+        }
+        printf("\rMQTT disconnects OK\n");
+        
+        _tlssocket->close();
+    }
+
+    
+protected:
+
+    /**
+     * @brief   Subscribe/publish specific topic
+     */
+    bool sub_pub_topic(const char *topic, const char **topic_filters, size_t topic_filters_size, const char *publish_message_body) {
+        
+        bool ret = false;
+        int mqtt_rc;
+        
+        do {
+            const char **topic_filter;
+            const char **topic_filter_end = topic_filters + topic_filters_size;
+
+            for (topic_filter = topic_filters; topic_filter != topic_filter_end; topic_filter ++) {
+                /* AWS IoT does not support publishing and subscribing with QoS 2.
+                 * The AWS IoT message broker does not send a PUBACK or SUBACK when QoS 2 is requested. */
+                printf("MQTT subscribing to %s", *topic_filter);
+                if ((mqtt_rc = _mqtt_client->subscribe(*topic_filter, MQTT::QOS1, message_arrived)) != 0) {
+                    printf("\rMQTT subscribes to %s failed: %d\n", *topic_filter, mqtt_rc);
+                    continue;
+                }
+                printf("\rMQTT subscribes to %s OK\n", *topic_filter);
+            }
+
+            MQTT::Message message;
+
+            int _bpos;
+        
+            _bpos = snprintf(_buffer, sizeof (_buffer) - 1, publish_message_body);
+            if (_bpos < 0 || ((size_t) _bpos) > (sizeof (_buffer) - 1)) {
+                printf("snprintf failed: %d\n", _bpos);
+                break;
+            }
+            _buffer[_bpos] = 0;
+            /* AWS IoT does not support publishing and subscribing with QoS 2.
+             * The AWS IoT message broker does not send a PUBACK or SUBACK when QoS 2 is requested. */
+            message.qos = MQTT::QOS1;
+            message.retained = false;
+            message.dup = false;
+            message.payload = _buffer;
+            message.payloadlen = strlen(_buffer);
+            /* Print publish message */
+            printf("Message to publish:\n");
+            printf("%s\n", _buffer);
+            printf("MQTT publishing message to %s", topic);
+            if ((mqtt_rc = _mqtt_client->publish(topic, message)) != 0) {
+                printf("\rMQTT publishes message to %s failed: %d\n", topic, mqtt_rc);
+                break;
+            }
+            printf("\rMQTT publishes message to %s OK\n", topic);
+        
+            /* Receive message with subscribed topic */
+            while (! _message_arrive_count) {
+                _mqtt_client->yield(100);
+            }
+            clear_message_arrive_count();
+            printf("\n");
+
+            /* Unsubscribe 
+             * We meet second unsubscribe failed. This is caused by MQTT lib bug. */
+            for (topic_filter = topic_filters; topic_filter != topic_filter_end; topic_filter ++) {
+                printf("MQTT unsubscribing from %s", *topic_filter);
+                if ((mqtt_rc = _mqtt_client->unsubscribe(*topic_filter)) != 0) {
+                    printf("\rMQTT unsubscribes from %s failed: %d\n", *topic_filter, mqtt_rc);
+                    continue;
+                }
+                printf("\rMQTT unsubscribes from %s OK\n", *topic_filter);
+            }
+
+            ret = true;
+        
+        } while (0);
+        
+        return ret;
+    }
+    
+protected:
+    TLSSocket *                                                             _tlssocket;
+    MQTT::Client<TLSSocket, Countdown, MAX_MQTT_PACKET_SIZE> *              _mqtt_client;
+
+    const char *_domain;                    /**< Domain name of the MQTT server */
+    const uint16_t _port;                   /**< Port number of the MQTT server */
+    char _buffer[MQTT_USER_BUFFER_SIZE];    /**< User buffer */
+    
+private:
+    static volatile uint16_t   _message_arrive_count;
+
+    static void message_arrived(MQTT::MessageData& md) {
+        MQTT::Message &message = md.message;
+        printf("Message arrived: qos %d, retained %d, dup %d, packetid %d\r\n", message.qos, message.retained, message.dup, message.id);
+        printf("Payload:\n");
+        printf("%.*s\n", message.payloadlen, (char*)message.payload);
+        ++ _message_arrive_count;
+    }
+    
+    static void clear_message_arrive_count() {
+        _message_arrive_count = 0;
+    }
+};
+
+volatile uint16_t   AWS_IoT_MQTT_Test::_message_arrive_count = 0;
+
+#endif  // End of AWS_IOT_MQTT_TEST
+
+
+#if AWS_IOT_HTTPS_TEST
+
+/**
+ * /brief   AWS_IoT_HTTPS_Test implements the logic with AWS IoT User/Thing Shadow topics (publish-only)
+ *          and Thing Shadow RESTful API through HTTPS.
+ */
+class AWS_IoT_HTTPS_Test {
+
+public:
+    /**
+     * @brief   AWS_IoT_HTTPS_Test Constructor
+     *
+     * @param[in] domain    Domain name of the HTTPS server
+     * @param[in] port      Port number of the HTTPS server
+     * @param[in] net_iface Network interface
+     */
+    AWS_IoT_HTTPS_Test(const char * domain, const uint16_t port, NetworkInterface *net_iface) :
+            _domain(domain), _port(port) {
+
+        _tlssocket = new TLSSocket(net_iface, SSL_CA_CERT_PEM, SSL_USER_CERT_PEM, SSL_USER_PRIV_KEY_PEM);
+        /* Non-blocking mode */
+        _tlssocket->set_blocking(false);
+        /* Print Mbed TLS handshake log */
+        _tlssocket->set_debug(true);
+    }
+    /**
+     * @brief AWS_IoT_HTTPS_Test Destructor
+     */
+    ~AWS_IoT_HTTPS_Test() {
+        _tlssocket->close();
+        delete _tlssocket;
+        _tlssocket = NULL;
+    }
+    /**
+     * @brief Start AWS IoT test through HTTPS
+     *
+     * @param[in] path  The path of the file to fetch from the HTTPS server
+     */
+    void start_test() {
+        
+        int tls_rc;
+         
+        do {
+            /* Connect to the server */
+            /* Initialize TLS-related stuff */
+            printf("Connecting with %s:%d\n", _domain, _port);
+            tls_rc = _tlssocket->connect(_domain, _port);
+            if (tls_rc != NSAPI_ERROR_OK) {
+                printf("Connects with %s:%d failed: %d\n", _domain, _port, tls_rc);
+                break;
+            }
+            printf("Connects with %s:%d OK\n\n", _domain, _port);
+
+            /* Publish to user topic through HTTPS/POST */
+            printf("Publishing to user topic through HTTPS/POST\n");
+            if (! run_req_resp(USER_TOPIC_HTTPS_PATH, USER_TOPIC_HTTPS_REQUEST_METHOD, USER_TOPIC_HTTPS_REQUEST_MESSAGE_BODY)) {
+                break;
+            }
+            printf("Publishes to user topic through HTTPS/POST OK\n\n");
+        
+            /* Update thing shadow by publishing to UpdateThingShadow topic through HTTPS/POST */
+            printf("Updating thing shadow by publishing to Update Thing Shadow topic through HTTPS/POST\n");
+            if (! run_req_resp(UPDATETHINGSHADOW_TOPIC_HTTPS_PATH, UPDATETHINGSHADOW_TOPIC_HTTPS_REQUEST_METHOD, UPDATETHINGSHADOW_TOPIC_HTTPS_REQUEST_MESSAGE_BODY)) {
+                break;
+            }
+            printf("Update thing shadow by publishing to Update Thing Shadow topic through HTTPS/POST OK\n\n");
+            
+            /* Get thing shadow by publishing to GetThingShadow topic through HTTPS/POST */
+            printf("Getting thing shadow by publishing to GetThingShadow topic through HTTPS/POST\n");
+            if (! run_req_resp(GETTHINGSHADOW_TOPIC_HTTPS_PATH, GETTHINGSHADOW_TOPIC_HTTPS_REQUEST_METHOD, GETTHINGSHADOW_TOPIC_HTTPS_REQUEST_MESSAGE_BODY)) {
+                break;
+            }
+            printf("Get thing shadow by publishing to GetThingShadow topic through HTTPS/POST OK\n\n");
+            
+            /* Delete thing shadow by publishing to DeleteThingShadow topic through HTTPS/POST */
+            printf("Deleting thing shadow by publishing to DeleteThingShadow topic through HTTPS/POST\n");
+            if (! run_req_resp(DELETETHINGSHADOW_TOPIC_HTTPS_PATH, DELETETHINGSHADOW_TOPIC_HTTPS_REQUEST_METHOD, DELETETHINGSHADOW_TOPIC_HTTPS_REQUEST_MESSAGE_BODY)) {
+                break;
+            }
+            printf("Delete thing shadow by publishing to DeleteThingShadow topic through HTTPS/POST OK\n\n");
+            
+            /* Update thing shadow RESTfully through HTTPS/POST */
+            printf("Updating thing shadow RESTfully through HTTPS/POST\n");
+            if (! run_req_resp(UPDATETHINGSHADOW_THING_HTTPS_PATH, UPDATETHINGSHADOW_THING_HTTPS_REQUEST_METHOD, UPDATETHINGSHADOW_THING_HTTPS_REQUEST_MESSAGE_BODY)) {
+                break;
+            }
+            printf("Update thing shadow RESTfully through HTTPS/POST OK\n\n");
+            
+            /* Get thing shadow RESTfully through HTTPS/GET */
+            printf("Getting thing shadow RESTfully through HTTPS/GET\n");
+            if (! run_req_resp(GETTHINGSHADOW_THING_HTTPS_PATH, GETTHINGSHADOW_THING_HTTPS_REQUEST_METHOD, GETTHINGSHADOW_THING_HTTPS_REQUEST_MESSAGE_BODY)) {
+                break;
+            }
+            printf("Get thing shadow RESTfully through HTTPS/GET OK\n\n");
+            
+            /* Delete thing shadow RESTfully through HTTPS/DELETE */
+            printf("Deleting thing shadow RESTfully through HTTPS/DELETE\n");
+            if (! run_req_resp(DELETETHINGSHADOW_THING_HTTPS_PATH, DELETETHINGSHADOW_THING_HTTPS_REQUEST_METHOD, DELETETHINGSHADOW_THING_HTTPS_REQUEST_MESSAGE_BODY)) {
+                break;
+            }
+            printf("Delete thing shadow RESTfully through HTTPS/DELETE OK\n\n");
+            
+        } while (0);
+        
+        /* Close socket */
+        _tlssocket->close();
+    }
+
+protected:
+
+    /**
+     * @brief   Run request/response through HTTPS
+     */
+    bool run_req_resp(const char *https_path, const char *https_request_method, const char *https_request_message_body) {
+        
+        bool ret = false;
+        
+        do {
+            int tls_rc;
+            bool _got200 = false;
+
+            int _bpos;
+
+            /* Fill the request buffer */
+            _bpos = snprintf(_buffer, sizeof(_buffer) - 1,
+                            "%s %s HTTP/1.1\r\n" "Host: %s\r\n" "Content-Length: %d\r\n" "\r\n" "%s",
+                            https_request_method, https_path, AWS_IOT_HTTPS_SERVER_NAME, strlen(https_request_message_body), https_request_message_body);
+            if (_bpos < 0 || ((size_t) _bpos) > (sizeof (_buffer) - 1)) {
+                printf("snprintf failed: %d\n", _bpos);
+                break;
+            }
+            _buffer[_bpos] = 0;
+            /* Print request message */
+            printf("HTTPS: Request message:\n");
+            printf("%s\n", _buffer);
+        
+            int offset = 0;
+            do {
+                tls_rc = _tlssocket->send((const unsigned char *) _buffer + offset, _bpos - offset);
+                if (tls_rc > 0) {
+                    offset += tls_rc;
+                }
+            } while (offset < _bpos && 
+                    (tls_rc > 0 || tls_rc == MBEDTLS_ERR_SSL_WANT_READ || tls_rc == MBEDTLS_ERR_SSL_WANT_WRITE));
+            if (tls_rc < 0) {
+                print_mbedtls_error("_tlssocket->send", tls_rc);
+                break;
+            }
+
+            /* Read data out of the socket */
+            offset = 0;
+            size_t content_length = 0;
+            size_t offset_end = 0;
+            char *line_beg = _buffer;
+            char *line_end = NULL;
+            do {
+                tls_rc = _tlssocket->recv((unsigned char *) _buffer + offset, sizeof(_buffer) - offset - 1);
+                if (tls_rc > 0) {
+                    offset += tls_rc;
+                }
+                
+                /* Make it null-terminated */
+                _buffer[offset] = 0;
+
+                /* Scan response message
+                 *             
+                 * 1. A status line which includes the status code and reason message (e.g., HTTP/1.1 200 OK)
+                 * 2. Response header fields (e.g., Content-Type: text/html)
+                 * 3. An empty line (\r\n)
+                 * 4. An optional message body
+                 */
+                if (! offset_end) {
+                    line_end = strstr(line_beg, "\r\n");
+                    if (line_end) {
+                        /* Scan status line */
+                        if (! _got200) {
+                            _got200 = strstr(line_beg, HTTPS_OK_STR) != NULL;
+                        }
+            
+                        /* Scan response header fields for Content-Length 
+                         * 
+                         * NOTE: Assume chunked transfer (Transfer-Encoding: chunked) is not used
+                         * NOTE: Assume response field name are in lower case
+                         */
+                        if (content_length == 0) {
+                            sscanf(line_beg, "content-length:%d", &content_length);
+                        }
+                    
+                        /* An empty line indicates end of response header fields */
+                        if (line_beg == line_end) {
+                            offset_end = line_end - _buffer + 2 + content_length;
+                        }
+                    
+                        /* Go to next line */
+                        line_beg = line_end + 2;
+                        line_end = NULL;
+                    }
+                }
+            } while ((offset_end == 0 || offset < offset_end) &&
+                    (tls_rc > 0 || tls_rc == MBEDTLS_ERR_SSL_WANT_READ || tls_rc == MBEDTLS_ERR_SSL_WANT_WRITE));
+            if (tls_rc < 0 && 
+                tls_rc != MBEDTLS_ERR_SSL_WANT_READ && 
+                tls_rc != MBEDTLS_ERR_SSL_WANT_WRITE) {
+                print_mbedtls_error("_tlssocket->read", tls_rc);
+                break;
+            }
+            _bpos = offset;
+
+            _buffer[_bpos] = 0;
+
+            /* Print status messages */
+            printf("HTTPS: Received %d chars from server\n", _bpos);
+            printf("HTTPS: Received 200 OK status ... %s\n", _got200 ? "[OK]" : "[FAIL]");
+            printf("HTTPS: Received message:\n");
+            printf("%s\n", _buffer);
+        
+            ret = true;
+            
+        } while (0);
+        
+        return ret;
+    }
+     
+protected:
+    TLSSocket *     _tlssocket;
+
+    const char *_domain;                    /**< Domain name of the HTTPS server */
+    const uint16_t _port;                   /**< Port number of the HTTPS server */
+    char _buffer[HTTPS_USER_BUFFER_SIZE];   /**< User buffer */
+};
+
+#endif  // End of AWS_IOT_HTTPS_TEST
+
+int main() {
+    
+    /* The default 9600 bps is too slow to print full TLS debug info and could
+     * cause the other party to time out. */
+
+    printf("\nStarting AWS IoT test\n");
+
+#if defined(MBED_MAJOR_VERSION)
+    printf("Using Mbed OS %d.%d.%d\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION);
+#else
+    printf("Using Mbed OS from master.\n");
+#endif
+
+    /* Use the easy-connect lib to support multiple network bearers.   */
+    /* See https://github.com/ARMmbed/easy-connect README.md for info. */
+
+    NetworkInterface* network = easy_connect(false);
+    if (NULL == network) {
+        printf("Connecting to the network failed. See serial output.\n");
+        return 1;
+    }
+    
+#if AWS_IOT_MQTT_TEST
+    AWS_IoT_MQTT_Test *mqtt_test = new AWS_IoT_MQTT_Test(AWS_IOT_MQTT_SERVER_NAME, AWS_IOT_MQTT_SERVER_PORT, network);
+    mqtt_test->start_test();
+    delete mqtt_test;
+#endif  // End of AWS_IOT_MQTT_TEST
+    
+#if AWS_IOT_HTTPS_TEST
+    AWS_IoT_HTTPS_Test *https_test = new AWS_IoT_HTTPS_Test(AWS_IOT_HTTPS_SERVER_NAME, AWS_IOT_HTTPS_SERVER_PORT, network);
+    https_test->start_test();
+    delete https_test;
+#endif  // End of AWS_IOT_HTTPS_TEST
+
+    /* Heap usage */
+    mbed_stats_heap_t heap_stats;
+    mbed_stats_heap_get(&heap_stats);
+    printf("\nCurrent heap size: %lu\n", heap_stats.current_size);
+    printf("Max heap size: %lu\n\n", heap_stats.max_size);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-os.lib	Wed Mar 14 03:03:16 2018 +0000
@@ -0,0 +1,1 @@
+https://github.com/ARMmbed/mbed-os/#91e6db1ea251ffcc973001ed90477f42fdca5751
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_app.json	Wed Mar 14 03:03:16 2018 +0000
@@ -0,0 +1,48 @@
+{
+    "macros": [
+        "MBED_CONF_APP_MAIN_STACK_SIZE=4096",
+        "MBEDTLS_USER_CONFIG_FILE=\"mbedtls_user_config.h\"",
+        "MBED_HEAP_STATS_ENABLED=1",
+        "MBED_MEM_TRACING_ENABLED=1"
+    ],
+    "config": {
+        "network-interface":{
+            "help": "options are ETHERNET, WIFI_ESP8266, WIFI_ODIN, WIFI_IDW01M1, WIFI_RTW, MESH_LOWPAN_ND, MESH_THREAD",
+            "value": "ETHERNET"
+        },
+        "esp8266-tx": {
+            "help": "Pin used as TX (connects to ESP8266 RX)",
+            "value": "D1"
+        },
+        "esp8266-rx": {
+            "help": "Pin used as RX (connects to ESP8266 TX)",
+            "value": "D0"
+        },
+        "esp8266-debug": {
+            "value": false
+        },
+        "wifi-ssid": {
+            "value": "\"SSID\""
+        },
+        "wifi-password": {
+            "value": "\"PASSWORD\""
+        }
+    },
+    "target_overrides": {
+        "*": {
+             "platform.stdio-baud-rate": 9600,
+             "platform.stdio-convert-newlines": true
+        },
+        "UBLOX_EVK_ODIN_W2": {
+            "target.device_has_remove": ["EMAC"]
+        },
+        "NUMAKER_PFM_NUC472": {
+            "target.macros_remove": ["MBEDTLS_CONFIG_HW_SUPPORT"],
+            "drivers.uart-serial-rxbuf-size": 1024
+        },
+        "NUMAKER_PFM_M487": {
+            "target.macros_remove": ["MBEDTLS_CONFIG_HW_SUPPORT"],
+            "drivers.uart-serial-rxbuf-size": 1024
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbedtls_user_config.h	Wed Mar 14 03:03:16 2018 +0000
@@ -0,0 +1,45 @@
+/*
+ *  Copyright (C) 2006-2016, 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)
+ */
+
+#if !defined(MBEDTLS_ENTROPY_HARDWARE_ALT) && \
+    !defined(MBEDTLS_ENTROPY_NV_SEED) && !defined(MBEDTLS_TEST_NULL_ENTROPY)
+#error "This hardware does not have an entropy source."
+#endif /* !MBEDTLS_ENTROPY_HARDWARE_ALT && !MBEDTLS_ENTROPY_NV_SEED &&
+        * !MBEDTLS_TEST_NULL_ENTROPY */
+
+#if !defined(MBEDTLS_SHA1_C)
+#define MBEDTLS_SHA1_C
+#endif /* !MBEDTLS_SHA1_C */
+
+/*
+ *  This value is sufficient for handling 2048 bit RSA keys.
+ *
+ *  Set this value higher to enable handling larger keys, but be aware that this
+ *  will increase the stack usage.
+ */
+#define MBEDTLS_MPI_MAX_SIZE        256
+
+#define MBEDTLS_MPI_WINDOW_SIZE     1
+
+#if defined(TARGET_STM32F439xI) && defined(MBEDTLS_CONFIG_HW_SUPPORT)
+#undef MBEDTLS_AES_ALT
+#endif /* TARGET_STM32F439xI && MBEDTLS_CONFIG_HW_SUPPORT */
+
+/* Internal test only. Don't uncomment it out */
+//#define MBEDTLS_SSL_MAX_CONTENT_LEN     4096
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbedtls_utils.h	Wed Mar 14 03:03:16 2018 +0000
@@ -0,0 +1,36 @@
+/*
+ * PackageLicenseDeclared: Apache-2.0
+ * Copyright (c) 2017 ARM Limited
+ *
+ * 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.
+ */
+
+#ifndef _MBEDTLS_UTILS_H_
+#define _MBEDTLS_UTILS_H_
+
+#include "mbedtls/platform.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/error.h"
+
+/**
+  * Helper for pretty-printing mbed TLS error codes
+  */
+__STATIC_INLINE void print_mbedtls_error(const char *name, int err) {
+    char buf[128];
+    mbedtls_strerror(err, buf, sizeof (buf));
+    mbedtls_printf("%s() failed: -0x%04x (%d): %s\r\n", name, -err, err, buf);
+}
+
+#endif // _MBEDTLS_UTILS_H_