Demo application for using the AT&T IoT Starter Kit Powered by AWS.

Dependencies:   SDFileSystem

Fork of ATT_AWS_IoT_demo by Anthony Phillips

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers network_mbedtls_wrapper.cpp Source File

network_mbedtls_wrapper.cpp

00001 /*
00002  * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License").
00005  * You may not use this file except in compliance with the License.
00006  * A copy of the License is located at
00007  *
00008  *  http://aws.amazon.com/apache2.0
00009  *
00010  * or in the "license" file accompanying this file. This file is distributed
00011  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
00012  * express or implied. See the License for the specific language governing
00013  * permissions and limitations under the License.
00014  */
00015 
00016 #include <stdbool.h>
00017 #include <string.h>
00018 
00019 #include "aws_iot_config.h"
00020 #include "aws_iot_error.h"
00021 #include "aws_iot_log.h"
00022 #include "network_interface.h"
00023 #include "mbedtls/config.h"
00024 
00025 #include "mbedtls/net.h"
00026 #include "mbedtls/ssl.h"
00027 #include "mbedtls/entropy.h"
00028 #include "mbedtls/ctr_drbg.h"
00029 #include "mbedtls/certs.h"
00030 #include "mbedtls/x509.h"
00031 #include "mbedtls/error.h"
00032 #include "mbedtls/debug.h"
00033 #include "mbedtls/timing.h"
00034 #include "mbedtls/net_sockets.h"
00035 #include "pem.h"
00036 
00037 #include "platform.h"
00038 #include "WNCTCPSocketConnection.h"
00039 
00040 #ifdef USING_AVNET_SHIELD
00041 // Used for BIO connections
00042 extern WNCTCPSocketConnection* _tcpsocket;
00043 #endif
00044 
00045 // SD File System
00046 #include "SDFileSystem.h"
00047 
00048 // SD defines
00049 #define CERT_MAX_SIZE 4096
00050 
00051 // SD file pointer/buffer
00052 FILE *fp;
00053 char fp_buffer[CERT_MAX_SIZE];
00054 
00055 // From main.cpp
00056 extern char HostAddress[255];
00057 extern char MqttClientID[32];
00058 extern char ThingName[32];
00059 extern char PortString[4];
00060 
00061 /*
00062  * This is a function to do further verification if needed on the cert received
00063  */
00064 static int myCertVerify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) {
00065     char buf[1024];
00066     ((void) data);
00067 
00068     DEBUG("\nVerify requested for (Depth %d):\n", depth);
00069     mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt);
00070     DEBUG("%s", buf);
00071 
00072     if ((*flags) == 0) {
00073         DEBUG("  This certificate has no flags\n");
00074     } else {
00075         DEBUG(buf, sizeof(buf), "  ! ", *flags); DEBUG("%s\n", buf);
00076     }
00077 
00078     return (0);
00079 }
00080 
00081 static int ret = 0, i;
00082 static mbedtls_entropy_context entropy;
00083 static mbedtls_ctr_drbg_context ctr_drbg;
00084 static mbedtls_ssl_context ssl;
00085 static mbedtls_ssl_config conf;
00086 static uint32_t flags;
00087 static mbedtls_x509_crt cacert;
00088 static mbedtls_x509_crt clicert;
00089 static mbedtls_pk_context pkey;
00090 static mbedtls_net_context server_fd;
00091 
00092 // Used to zero the given buffer
00093 static void mbedtls_zeroize( char *v, size_t n ) {
00094     volatile char *p = v; while( n-- ) *p++ = 0;
00095 }
00096 
00097 // Parser sub function
00098 int mqtt_parse_sub(std::string *search_str, char *param, const char *str_to_find)
00099 {
00100     int index_start, index_end;
00101     mbedtls_zeroize(param, strlen(param));
00102     
00103     index_start = search_str->find(str_to_find);
00104     if (index_start < 0)
00105         return -1;
00106     
00107     index_end = search_str->find("\n", index_start); 
00108     if (index_end < 0)
00109         index_end = search_str->find("\0", index_start);
00110         
00111     if (index_end < 0)
00112         return -1;
00113     
00114     index_start += strlen(str_to_find);
00115     strcpy(param, search_str->substr(index_start, index_end-index_start-1).c_str());
00116     
00117     return 0;
00118 } 
00119 
00120 // Read MQTT config info
00121 int mbedtls_mqtt_config_parse_file(ShadowParameters_t *sp, const char *path )
00122 {
00123     int ret, size;
00124     mbedtls_zeroize(fp_buffer, CERT_MAX_SIZE);
00125     
00126     INFO("...Reading MQTT data from SD");
00127     fp = fopen(path, "r");   
00128     if (fp != NULL) {
00129         size = fread(fp_buffer, sizeof(char), CERT_MAX_SIZE, fp);
00130         DEBUG("...Number of data read: %d, text from file: %s", size, fp_buffer);
00131         fclose(fp);
00132     }
00133     else {
00134         ERROR("Could not open file: %s", path);
00135         return -1;
00136     }
00137     
00138     std::string filestr(fp_buffer);
00139         
00140     ret = mqtt_parse_sub(&filestr, HostAddress, "AWS_IOT_MQTT_HOST=");
00141     sp->pHost = HostAddress;
00142     INFO("...Host=%s", sp->pHost);
00143     if (ret < 0) {
00144         ERROR("Could not parse AWS_IOT_MQTT_HOST string.");
00145         return ret;
00146     }
00147     
00148     ret = mqtt_parse_sub(&filestr, PortString, "AWS_IOT_MQTT_PORT=");
00149     sp->port = atoi(PortString);
00150     INFO("...Port=%d", sp->port);
00151     if (ret < 0) {
00152         ERROR("Could not parse AWS_IOT_MQTT_PORT string.");
00153         return ret;
00154     }
00155     
00156     ret = mqtt_parse_sub(&filestr, MqttClientID, "AWS_IOT_MQTT_CLIENT_ID=");
00157     sp->pMqttClientId = MqttClientID;
00158     INFO("...pMqttClientId=%s", sp->pMqttClientId);
00159     if (ret < 0) {
00160         ERROR("Could not parse AWS_IOT_MQTT_CLIENT_ID string.");
00161         return ret;
00162     }
00163     
00164     ret = mqtt_parse_sub(&filestr, ThingName, "AWS_IOT_MY_THING_NAME=");
00165     sp->pMyThingName = ThingName;
00166     INFO("...pMyThingName=%s", sp->pMyThingName);
00167     if (ret < 0) {
00168         ERROR("Could not parse AWS_IOT_MY_THING_NAME string.");
00169         return ret;
00170     }
00171 
00172     return( ret );
00173 }
00174 
00175 // Override function: Parses CRT from SD
00176 int mbedtls_x509_crt_parse_file( mbedtls_x509_crt *chain, const char *path )
00177 {
00178     int ret, size;
00179     mbedtls_zeroize(fp_buffer, CERT_MAX_SIZE);
00180     
00181     INFO("...Reading CERT data from SD");
00182     fp = fopen(path, "r");
00183     if (fp != NULL) {
00184         size = fread(fp_buffer, sizeof(char), CERT_MAX_SIZE, fp);
00185         DEBUG("...Number of data read: %d, text from file: %s", size, fp_buffer);
00186         fclose(fp);
00187     }
00188     else {
00189         ERROR("Could not open file: %s", path);
00190         return -1;
00191     }
00192 
00193     DEBUG("...CRT Parse");
00194     ret = mbedtls_x509_crt_parse( chain, (unsigned char *)fp_buffer, size+2);
00195   
00196     return( ret );
00197 }
00198 
00199 // Override function: Parses KEY from SD
00200 int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx,
00201                               const char *path, const char *pwd )
00202 {
00203     int ret, size;  
00204     mbedtls_zeroize(fp_buffer, CERT_MAX_SIZE);
00205 
00206     INFO("...Reading KEY data from SD");
00207     fp = fopen(path, "r");
00208     if (fp != NULL) {
00209         size = fread(fp_buffer, sizeof(char), CERT_MAX_SIZE, fp);
00210         DEBUG("...Number of data read: %d, text from file: %s", size, fp_buffer);
00211         fclose(fp);
00212     }
00213     else {
00214         ERROR("Could not open file: %s", path);
00215         return -1;
00216     }
00217 
00218     DEBUG("...Key Parse");
00219     if( pwd == NULL ) {
00220         DEBUG("...Using PWD");
00221         ret = mbedtls_pk_parse_key( ctx, (unsigned char *)fp_buffer, size+1, NULL, 0 );
00222     }
00223     else {
00224         DEBUG("...No PWD");
00225         ret = mbedtls_pk_parse_key( ctx, (unsigned char *)fp_buffer, size+1, (const unsigned char *) pwd, strlen( pwd ) );
00226     }
00227   
00228     return( ret );
00229 }
00230 
00231 
00232 /* personalization string for the drbg */
00233 const char *DRBG_PERS = "mbed TLS helloword client";
00234 
00235 int iot_tls_init(Network *pNetwork) {
00236     IoT_Error_t ret_val = NONE_ERROR;
00237     const char *pers = "aws_iot_tls_wrapper";
00238     unsigned char buf[MBEDTLS_SSL_MAX_CONTENT_LEN + 1];
00239     
00240     mbedtls_net_init(&server_fd);
00241     mbedtls_ssl_init(&ssl);
00242     mbedtls_ssl_config_init(&conf);
00243     mbedtls_ctr_drbg_init(&ctr_drbg);
00244     mbedtls_x509_crt_init(&cacert);
00245     mbedtls_x509_crt_init(&clicert);
00246     mbedtls_pk_init(&pkey);
00247     
00248     DEBUG("...Seeding the random number generator");
00249     mbedtls_entropy_init(&entropy);
00250     if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) DRBG_PERS, sizeof (DRBG_PERS))) != 0) {         
00251         ERROR(" failed\n  ! mbedtls_ctr_drbg_seed returned -0x%x\n", -ret);
00252         return ret_val;
00253     }   
00254     DEBUG(" ok\n");
00255 
00256     pNetwork->my_socket = 0;
00257     pNetwork->connect = iot_tls_connect;
00258     pNetwork->mqttread = iot_tls_read;
00259     pNetwork->mqttwrite = iot_tls_write;
00260     pNetwork->disconnect = iot_tls_disconnect;
00261     pNetwork->isConnected = iot_tls_is_connected;
00262     pNetwork->destroy = iot_tls_destroy;
00263 
00264     return ret_val;
00265 }
00266 
00267 int iot_tls_is_connected(Network *pNetwork) {
00268     /* Use this to add implementation which can check for physical layer disconnect */
00269     return 1;
00270 }
00271 
00272 int iot_tls_connect(Network *pNetwork, TLSConnectParams params) {
00273     const char *pers = "aws_iot_tls_wrapper";
00274 
00275     DEBUG("...Loading the CA root certificate");    
00276 #ifdef USING_SD_CARD
00277     ret = mbedtls_x509_crt_parse_file(&cacert, AWS_IOT_ROOT_CA_FILENAME);
00278 #else
00279     ret = mbedtls_x509_crt_parse(&cacert, (const unsigned char *)AWS_IOT_ROOT_CA, strlen ((const char *)AWS_IOT_ROOT_CA)+1);
00280 #endif
00281     if (ret < 0) {
00282         ERROR(" failed\n  !  mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
00283         return ret;
00284     } 
00285     DEBUG(" ok (%d skipped)", ret);
00286     
00287     
00288     DEBUG("...Loading the client cert");
00289 #ifdef USING_SD_CARD
00290     ret = mbedtls_x509_crt_parse_file(&clicert, AWS_IOT_CERTIFICATE_FILENAME);
00291 #else
00292     ret = mbedtls_x509_crt_parse(&clicert, (const unsigned char *)AWS_IOT_CERTIFICATE, strlen ((const char *)AWS_IOT_CERTIFICATE)+1);
00293 #endif
00294     if (ret != 0) {
00295         ERROR(" failed\n  !  mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
00296         return ret;
00297     }
00298     DEBUG(" ok");
00299     
00300     DEBUG("...Loading the client key");
00301 #ifdef USING_SD_CARD
00302     ret = mbedtls_pk_parse_keyfile(&pkey, AWS_IOT_PRIVATE_KEY_FILENAME, "");
00303 #else
00304     ret = mbedtls_pk_parse_key(&pkey, (const unsigned char *)AWS_IOT_PRIVATE_KEY, strlen ((const char *)AWS_IOT_PRIVATE_KEY)+1, NULL, 0 );  
00305 #endif  
00306     if (ret != 0) {
00307         ERROR(" failed\n  !  mbedtls_pk_parse_key returned -0x%x\n\n", -ret);
00308         return ret;
00309     } 
00310     DEBUG(" ok");
00311 
00312     char portBuffer[6];
00313     sprintf(portBuffer, "%d", params.DestinationPort); 
00314     DEBUG("...Connecting to %s/%s", params.pDestinationURL, portBuffer);
00315     if ((ret = mbedtls_net_connect(&server_fd, params.pDestinationURL, portBuffer, MBEDTLS_NET_PROTO_TCP)) != 0) {
00316         ERROR(" failed\n  ! mbedtls_net_connect returned -0x%x\n\n", -ret);
00317         return ret;
00318     }
00319 
00320     
00321     ret = mbedtls_net_set_block(&server_fd);
00322     if (ret != 0) {
00323         ERROR(" failed\n  ! net_set_(non)block() returned -0x%x\n\n", -ret);
00324         return ret;
00325     } 
00326     DEBUG(" ok");
00327     
00328 
00329     DEBUG("...Setting up the SSL/TLS structure");
00330     if ((ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM,
00331             MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
00332         ERROR(" failed\n  ! mbedtls_ssl_config_defaults returned -0x%x\n\n", -ret);
00333         return ret;
00334     }
00335 
00336 
00337     mbedtls_ssl_conf_verify(&conf, myCertVerify, NULL);
00338     if (params.ServerVerificationFlag == true) {
00339         mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
00340     } else {
00341         mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
00342     }
00343     mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
00344 
00345     mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
00346     if ((ret = mbedtls_ssl_conf_own_cert(&conf, &clicert, &pkey)) != 0) {
00347         ERROR(" failed\n  ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret);
00348         return ret;
00349     }
00350 
00351     mbedtls_ssl_conf_read_timeout(&conf, params.timeout_ms);
00352 
00353     if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
00354         ERROR(" failed\n  ! mbedtls_ssl_setup returned -0x%x\n\n", -ret);
00355         return ret;
00356     }
00357     if ((ret = mbedtls_ssl_set_hostname(&ssl, params.pDestinationURL)) != 0) {
00358         ERROR(" failed\n  ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
00359         return ret;
00360     }
00361     
00362     DEBUG("...Set Socket I/O Functions");
00363     mbedtls_ssl_set_bio(&ssl, static_cast<void *>(_tcpsocket), mbedtls_net_send, NULL, mbedtls_net_recv_timeout );
00364     DEBUG(" ok");
00365     
00366 
00367     DEBUG("...Performing the SSL/TLS handshake");
00368     while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
00369         if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
00370             ERROR(" failed\n  ! mbedtls_ssl_handshake returned -0x%x\n", -ret);
00371             if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
00372                 ERROR("    Unable to verify the server's certificate. "
00373                         "Either it is invalid,\n"
00374                         "    or you didn't set ca_file or ca_path "
00375                         "to an appropriate value.\n"
00376                         "    Alternatively, you may want to use "
00377                         "auth_mode=optional for testing purposes.\n");
00378             }
00379             return ret;
00380         }
00381     }
00382     
00383 
00384     DEBUG(" ok\n    [ Protocol is %s ]\n    [ Ciphersuite is %s ]\n", mbedtls_ssl_get_version(&ssl), mbedtls_ssl_get_ciphersuite(&ssl));
00385     if ((ret = mbedtls_ssl_get_record_expansion(&ssl)) >= 0) {
00386         DEBUG("    [ Record expansion is %d ]\n", ret);
00387     } else {
00388         DEBUG("    [ Record expansion is unknown (compression) ]\n");
00389     }
00390 
00391 
00392     DEBUG("...Verifying peer X.509 certificate");
00393     if (params.ServerVerificationFlag == true) {
00394         if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) {
00395             char vrfy_buf[512];
00396             ERROR(" failed\n");
00397             mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "  ! ", flags);
00398             ERROR("%s\n", vrfy_buf);
00399         } else {
00400             DEBUG(" ok\n");
00401             ret = NONE_ERROR;
00402         }
00403     } else {
00404         DEBUG(" Server Verification skipped\n");
00405         ret = NONE_ERROR;
00406     }
00407 
00408 
00409     DEBUG("...SSL get peer cert");
00410     if (mbedtls_ssl_get_peer_cert(&ssl) != NULL) {
00411         DEBUG("...Peer certificate information");       
00412         const uint32_t buf_size = 1024;
00413         char *buf = new char[buf_size];
00414         mbedtls_x509_crt_info(buf,          buf_size,        "      ", mbedtls_ssl_get_peer_cert(&ssl));
00415         DEBUG("...Server certificate:\r\n%s\r", buf);
00416     }
00417 
00418     mbedtls_ssl_conf_read_timeout(&conf, 10);
00419 
00420     return ret;
00421 }
00422 
00423 int iot_tls_write(Network *pNetwork, unsigned char *pMsg, int len, int timeout_ms) {
00424 
00425     int written;
00426     int frags;
00427     
00428     for (written = 0, frags = 0; written < len; written += ret, frags++) {
00429         while ((ret = mbedtls_ssl_write(&ssl, pMsg + written, len - written)) <= 0) {
00430             if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
00431                 ERROR(" failed\n  ! mbedtls_ssl_write returned -0x%x\n\n", -ret);
00432                 return ret;
00433             }
00434         }
00435     }
00436     
00437     return written;
00438 }
00439 
00440 int iot_tls_read(Network *pNetwork, unsigned char *pMsg, int len, int timeout_ms) {
00441     int rxLen = 0;
00442     bool isErrorFlag = false;
00443     bool isCompleteFlag = false;
00444 
00445     // TODO check this against base
00446     //mbedtls_ssl_conf_read_timeout(&conf, timeout_ms);
00447 
00448     do {
00449         ret = mbedtls_ssl_read(&ssl, pMsg, len);
00450         if (ret > 0) {
00451             rxLen += ret;
00452         } else if (ret != MBEDTLS_ERR_SSL_WANT_READ) {
00453             isErrorFlag = true;
00454         }
00455         if (rxLen >= len) {
00456             isCompleteFlag = true;
00457         }
00458     } while (!isErrorFlag && !isCompleteFlag);
00459 
00460     return ret;
00461 }
00462 
00463 void iot_tls_disconnect(Network *pNetwork) {
00464     do {
00465         ret = mbedtls_ssl_close_notify(&ssl);
00466     } while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
00467 }
00468 
00469 int iot_tls_destroy(Network *pNetwork) {
00470 
00471     mbedtls_net_free(&server_fd);
00472 
00473     mbedtls_x509_crt_free(&clicert);
00474     mbedtls_x509_crt_free(&cacert);
00475     mbedtls_pk_free(&pkey);
00476     mbedtls_ssl_free(&ssl);
00477     mbedtls_ssl_config_free(&conf);
00478     mbedtls_ctr_drbg_free(&ctr_drbg);
00479     mbedtls_entropy_free(&entropy);
00480 
00481     return 0;
00482 }
00483 
00484