Jim Flynn / Mbed OS aws-iot-device-sdk-mbed-c
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 "mbed.h"
00017 
00018 #include "easy-connect.h"
00019 
00020 #define MBEDTLS_FS_IO 1
00021 
00022 #include <stdbool.h>
00023 #include <string.h>
00024 #include <timer_platform.h >
00025 #include <network_interface.h>
00026 
00027 #include "mbedtls/platform.h"
00028 #include "mbedtls/ssl.h"
00029 #include "mbedtls/entropy.h"
00030 #include "mbedtls/ctr_drbg.h"
00031 #include "mbedtls/error.h"
00032 #include "mbedtls/x509_crt.h"
00033 #include "mbedtls/pk.h"
00034 
00035 #if DEBUG_LEVEL > 0
00036 #include "mbedtls/debug.h"
00037 #endif
00038 
00039 #include "aws_iot_error.h"
00040 #include "aws_iot_log.h"
00041 #include "network_interface.h"
00042 #include "network_platform.h"
00043 
00044 #include "awscerts.h"
00045 
00046 /* This is the value used for ssl read timeout (in msec) */
00047 #define IOT_SSL_READ_TIMEOUT 10000
00048 
00049 /* This defines the value of the debug buffer that gets allocated.
00050  * The value can be altered based on memory constraints
00051  */
00052 #ifdef ENABLE_IOT_DEBUG
00053 #define MBEDTLS_DEBUG_BUFFER_SIZE 2048
00054 #endif
00055 
00056 
00057 void mbedtls_aws_init( mbedtls_net_context * );
00058 int  mbedtls_aws_connect( mbedtls_net_context *, const char *host, uint16_t port, int proto );
00059 int  mbedtls_aws_bind( mbedtls_net_context *, const char *bind_ip, const char *port, int proto );
00060 int  mbedtls_aws_accept( mbedtls_net_context *bind_ctx, mbedtls_net_context *client_ctx, void *client_ip, size_t buf_size, size_t *ip_len ) ;
00061 void mbedtls_aws_usleep( unsigned long );
00062 int  mbedtls_aws_recv( void *, unsigned char *, size_t );
00063 int  mbedtls_aws_recv_timeout( void *, unsigned char *, size_t , uint32_t );
00064 int  mbedtls_aws_send( void *, const unsigned char *, size_t  );
00065 void mbedtls_aws_free( mbedtls_net_context * );
00066 
00067 /*
00068  * This is a function to do further verification if needed on the cert received
00069  */
00070 
00071 static int _iot_tls_verify_cert(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) 
00072 {
00073     char buf[1024];
00074     ((void) data);
00075     FUNC_ENTRY;
00076 
00077     IOT_DEBUG("Verify requested for (Depth %d):", depth);
00078     mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt);
00079     IOT_DEBUG("%s", buf);
00080 
00081     if((*flags) == 0) {
00082         IOT_DEBUG("This certificate has no flags");
00083     } else {
00084         IOT_DEBUG(buf, sizeof(buf), "  ! ", *flags);
00085         IOT_DEBUG("%s", buf);
00086     }
00087 
00088     FUNC_EXIT_RC( 0);
00089 }
00090 
00091 void _iot_tls_set_connect_params(Network *pNetwork, char *pRootCALocation, char *pDeviceCertLocation,
00092                                  char *pDevicePrivateKeyLocation, char *pDestinationURL,
00093                                  uint16_t destinationPort, uint32_t timeout_ms, bool ServerVerificationFlag) 
00094 {
00095     FUNC_ENTRY;
00096     pNetwork->tlsConnectParams.DestinationPort = destinationPort;
00097     pNetwork->tlsConnectParams.pDestinationURL = pDestinationURL;
00098     pNetwork->tlsConnectParams.pDeviceCertLocation = pDeviceCertLocation;
00099     pNetwork->tlsConnectParams.pDevicePrivateKeyLocation = pDevicePrivateKeyLocation;
00100     pNetwork->tlsConnectParams.pRootCALocation = pRootCALocation;
00101     pNetwork->tlsConnectParams.timeout_ms = timeout_ms;
00102     pNetwork->tlsConnectParams.ServerVerificationFlag = ServerVerificationFlag;
00103 }
00104 
00105 IoT_Error_t iot_tls_init(Network *pNetwork, char *pRootCALocation, char *pDeviceCertLocation,
00106                          char *pDevicePrivateKeyLocation, char *pDestinationURL,
00107                          uint16_t destinationPort, uint32_t timeout_ms, bool ServerVerificationFlag) 
00108 {
00109     FUNC_ENTRY;
00110     _iot_tls_set_connect_params(pNetwork, pRootCALocation, pDeviceCertLocation, pDevicePrivateKeyLocation,
00111                                     pDestinationURL, destinationPort, timeout_ms, ServerVerificationFlag);
00112 
00113     pNetwork->connect = iot_tls_connect;
00114     pNetwork->read = iot_tls_read;
00115     pNetwork->write = iot_tls_write;
00116     pNetwork->disconnect = iot_tls_disconnect;
00117     pNetwork->isConnected = iot_tls_is_connected;
00118     pNetwork->destroy = iot_tls_destroy;
00119 
00120     pNetwork->tlsDataParams.flags = 0;
00121 
00122     FUNC_EXIT_RC( AWS_SUCCESS);
00123 }
00124 
00125 IoT_Error_t iot_tls_is_connected(Network *pNetwork) 
00126 {
00127     FUNC_ENTRY;
00128     /* Use this to add implementation which can check for physical layer disconnect */
00129     FUNC_EXIT_RC( NETWORK_PHYSICAL_LAYER_CONNECTED);
00130 }
00131 
00132 IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *params) 
00133 {
00134     int ret = 0;
00135     const char *pers = "aws_iot_tls_wrapper";
00136     TLSDataParams *tlsDataParams = NULL;
00137     char vrfy_buf[512];
00138     const char *alpnProtocols[] = { "x-amzn-mqtt-ca", NULL };
00139 
00140     FUNC_ENTRY;
00141 
00142     if(pNetwork == NULL) {
00143         FUNC_EXIT_RC(NULL_VALUE_ERROR);
00144     }
00145 
00146     if( params != NULL) {
00147         _iot_tls_set_connect_params(pNetwork, params->pRootCALocation, params->pDeviceCertLocation,
00148                                     params->pDevicePrivateKeyLocation, params->pDestinationURL,
00149                                     params->DestinationPort, params->timeout_ms, params->ServerVerificationFlag);
00150         }
00151 
00152     tlsDataParams = &(pNetwork->tlsDataParams);
00153 
00154 
00155     mbedtls_entropy_init(&(tlsDataParams->entropy));
00156     mbedtls_ctr_drbg_init(&(tlsDataParams->ctr_drbg));
00157     mbedtls_x509_crt_init(&(tlsDataParams->clicert));
00158     mbedtls_x509_crt_init(&(tlsDataParams->cacert));
00159     mbedtls_ssl_init(&(tlsDataParams->ssl));
00160     mbedtls_ssl_config_init(&(tlsDataParams->conf));
00161     mbedtls_pk_init(&(tlsDataParams->pkey));
00162 
00163     IOT_DEBUG("\nSeed the random number generator...");
00164     if((ret = mbedtls_ctr_drbg_seed(&(tlsDataParams->ctr_drbg), mbedtls_entropy_func, &(tlsDataParams->entropy),
00165                      (const unsigned char *) pers, 
00166                      strlen(pers))) != 0) {
00167         IOT_ERROR(" failed\n  ! mbedtls_ctr_drbg_seed returned -0x%x\n", -ret);
00168         FUNC_EXIT_RC(NETWORK_MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED);
00169     }
00170 
00171     IOT_DEBUG("Load the IoT certificate ...");
00172     #ifdef USING_SD_CARD
00173     ret = mbedtls_x509_crt_parse_file(&(tlsDataParams->clicert), pNetwork->tlsConnectParams.pDeviceCertLocation);
00174     #else
00175     ret = mbedtls_x509_crt_parse(&(tlsDataParams->clicert), (const unsigned char*)aws_iot_certificate, 
00176                   strlen(aws_iot_certificate)+1);
00177     #endif
00178     if(ret != 0) {
00179         IOT_ERROR(" failed\n  !  mbedtls_x509_crt_parse returned -0x%x while parsing device cert\n\n", -ret);
00180         FUNC_EXIT_RC(NETWORK_X509_DEVICE_CRT_PARSE_ERROR);
00181     }
00182 
00183     IOT_DEBUG("Load the private key ...");
00184     #ifdef USING_SD_CARD
00185     ret = mbedtls_pk_parse_keyfile(&(tlsDataParams->pkey), pNetwork->tlsConnectParams.pDevicePrivateKeyLocation, "");
00186     #else
00187     ret = mbedtls_pk_parse_key(&(tlsDataParams->pkey), (const unsigned char*)aws_iot_private_key, 
00188                   strlen(aws_iot_private_key)+1, NULL, 0 ); 
00189     #endif  
00190     if(ret != 0) {
00191         IOT_ERROR(" failed\n  !  mbedtls_pk_parse_key returned -0x%x while parsing private key\n\n", -ret);
00192         IOT_DEBUG(" path : %s ", pNetwork->tlsConnectParams.pDevicePrivateKeyLocation);
00193         FUNC_EXIT_RC(NETWORK_PK_PRIVATE_KEY_PARSE_ERROR);
00194     }
00195 
00196     IOT_DEBUG("Load the CA root certificate ...");
00197     #ifdef USING_SD_CARD
00198     ret = mbedtls_x509_crt_parse_file(&(tlsDataParams->cacert), pNetwork->tlsConnectParams.pRootCALocation);
00199     #else
00200     ret = mbedtls_x509_crt_parse(&(tlsDataParams->cacert), (const unsigned char*)aws_iot_rootCA, 
00201                   sizeof(aws_iot_rootCA));
00202     #endif
00203     if(ret < 0) {
00204         IOT_ERROR(" failed\n  !  mbedtls_x509_crt_parse returned -0x%x while parsing root cert\n\n", -ret);
00205         FUNC_EXIT_RC(NETWORK_X509_ROOT_CRT_PARSE_ERROR);
00206     }
00207 
00208     IOT_DEBUG("done.\nSetting up the SSL/TLS structure...");
00209     if((ret = mbedtls_ssl_config_defaults(&(tlsDataParams->conf), 
00210                   MBEDTLS_SSL_IS_CLIENT, 
00211                   MBEDTLS_SSL_TRANSPORT_STREAM,
00212                   MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
00213         IOT_ERROR(" failed\n  ! mbedtls_ssl_config_defaults returned -0x%x\n\n", -ret);
00214         FUNC_EXIT_RC(SSL_CONNECTION_ERROR);
00215     }
00216 
00217     mbedtls_ssl_conf_ca_chain(&(tlsDataParams->conf), &(tlsDataParams->cacert), NULL);
00218     mbedtls_ssl_conf_rng(&(tlsDataParams->conf), mbedtls_ctr_drbg_random, &(tlsDataParams->ctr_drbg));
00219 
00220     if((ret = mbedtls_ssl_setup(&(tlsDataParams->ssl), &(tlsDataParams->conf))) != 0) {
00221         IOT_ERROR(" failed\n  ! mbedtls_ssl_setup returned -0x%x\n\n", -ret);
00222         FUNC_EXIT_RC(SSL_CONNECTION_ERROR);
00223     }
00224 
00225     if((ret = mbedtls_ssl_set_hostname(&(tlsDataParams->ssl), pNetwork->tlsConnectParams.pDestinationURL)) != 0) {
00226         IOT_ERROR(" failed\n  ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
00227         FUNC_EXIT_RC(SSL_CONNECTION_ERROR);
00228     }
00229     IOT_DEBUG("Set the SSL BIO ...");
00230     mbedtls_ssl_set_bio(&(tlsDataParams->ssl), &(tlsDataParams->server_fd), mbedtls_aws_send, NULL,
00231                         mbedtls_aws_recv_timeout);
00232     mbedtls_ssl_conf_verify(&(tlsDataParams->conf), _iot_tls_verify_cert, NULL);
00233     if(pNetwork->tlsConnectParams.ServerVerificationFlag == true) 
00234         mbedtls_ssl_conf_authmode(&(tlsDataParams->conf), MBEDTLS_SSL_VERIFY_REQUIRED);
00235     else
00236         mbedtls_ssl_conf_authmode(&(tlsDataParams->conf), MBEDTLS_SSL_VERIFY_OPTIONAL);
00237 
00238     if((ret = mbedtls_ssl_conf_own_cert(&(tlsDataParams->conf), &(tlsDataParams->clicert), 
00239                    &(tlsDataParams->pkey))) != 0) {
00240         IOT_ERROR(" failed\n!!! mbedtls_ssl_conf_own_cert returned %d\n\n", ret);
00241         FUNC_EXIT_RC(SSL_CONNECTION_ERROR);
00242         }
00243 
00244     mbedtls_ssl_conf_read_timeout(&(tlsDataParams->conf), pNetwork->tlsConnectParams.timeout_ms);
00245 
00246     /* Use the AWS IoT ALPN extension for MQTT if port 443 is requested. */
00247     if(443 == pNetwork->tlsConnectParams.DestinationPort) {
00248         if((ret = mbedtls_ssl_conf_alpn_protocols(&(tlsDataParams->conf), alpnProtocols)) != 0) {
00249             IOT_ERROR(" failed\n  ! mbedtls_ssl_conf_alpn_protocols returned -0x%x\n\n", -ret);
00250             FUNC_EXIT_RC(SSL_CONNECTION_ERROR);
00251         }
00252     }
00253 
00254     mbedtls_aws_init(&(tlsDataParams->server_fd));
00255     if( (tlsDataParams->server_fd).fd == -1 ) {
00256         IOT_ERROR(" Network connected failed!\n");
00257         FUNC_EXIT_RC(NETWORK_ERR_NET_CONNECT_FAILED);
00258         }
00259 
00260     IOT_DEBUG("Connecting to %s/%d...", pNetwork->tlsConnectParams.pDestinationURL, pNetwork->tlsConnectParams.DestinationPort);
00261     if((ret = mbedtls_aws_connect(&(tlsDataParams->server_fd), pNetwork->tlsConnectParams.pDestinationURL, 
00262                         pNetwork->tlsConnectParams.DestinationPort, 
00263                         MBEDTLS_NET_PROTO_TCP)) != 0) {
00264         IOT_ERROR(" failed\n  ! mbedtls_aws_connect returned -0x%x\n\n", -ret);
00265         switch(ret) {
00266             case MBEDTLS_ERR_NET_SOCKET_FAILED:
00267                 FUNC_EXIT_RC(NETWORK_ERR_NET_SOCKET_FAILED);
00268             case MBEDTLS_ERR_NET_UNKNOWN_HOST:
00269                 FUNC_EXIT_RC(NETWORK_ERR_NET_UNKNOWN_HOST);
00270             case MBEDTLS_ERR_NET_CONNECT_FAILED:
00271             default:
00272                 FUNC_EXIT_RC(NETWORK_ERR_NET_CONNECT_FAILED);
00273         };
00274     }
00275 
00276     IOT_DEBUG("\n\nPerform the SSL/TLS handshake...\n\n\n\n");
00277 
00278     while((ret = mbedtls_ssl_handshake(&(tlsDataParams->ssl))) != 0) {
00279         if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
00280             IOT_ERROR(" failed\n  ! mbedtls_ssl_handshake returned -0x%x (%d)\n", -ret, ret);
00281             if(ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
00282                 IOT_ERROR( "Unable to verify the server's certificate.  Either it is invalid, or you\n"
00283                            "didn't set ca_file or ca_path to an appropriate value.  Alternatively,\n"
00284                            "you may want to use auth_mode=optional for testing purposes.\n" );
00285                 }
00286             FUNC_EXIT_RC(SSL_CONNECTION_ERROR);
00287             }
00288         }
00289 
00290     IOT_DEBUG("[ Protocol is %s ]\n[ Ciphersuite is %s ]\n", mbedtls_ssl_get_version(&(tlsDataParams->ssl)),
00291     mbedtls_ssl_get_ciphersuite(&(tlsDataParams->ssl)));
00292     if((ret = mbedtls_ssl_get_record_expansion(&(tlsDataParams->ssl))) >= 0) {
00293         IOT_DEBUG("[Record expansion is %d]", ret);
00294         } 
00295     else{
00296         IOT_DEBUG("[Record expansion is unknown (compression)]");
00297         }
00298     IOT_DEBUG("Verifying peer X.509 certificate...");
00299 
00300     if(pNetwork->tlsConnectParams.ServerVerificationFlag == true) {
00301         if((tlsDataParams->flags = mbedtls_ssl_get_verify_result(&(tlsDataParams->ssl))) != 0) {
00302             IOT_ERROR(" FAIL\n");
00303             mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "  ! ", tlsDataParams->flags);
00304             IOT_ERROR("%s\n", vrfy_buf);
00305             ret = SSL_CONNECTION_ERROR;
00306         } else {
00307             IOT_DEBUG("Verified OK\n");
00308             ret = AWS_SUCCESS;
00309         }
00310     } else {
00311         IOT_DEBUG("Server Verification skipped\n");
00312         ret = AWS_SUCCESS;
00313     }
00314 
00315 #ifdef ENABLE_IOT_DEBUG
00316     if (mbedtls_ssl_get_peer_cert(&(tlsDataParams->ssl)) != NULL) {
00317         unsigned char buf[MBEDTLS_DEBUG_BUFFER_SIZE];
00318         IOT_DEBUG("Peer certificate information    ...\n");
00319         mbedtls_x509_crt_info((char *) buf, sizeof(buf) - 1, "      ", mbedtls_ssl_get_peer_cert(&(tlsDataParams->ssl)));
00320         IOT_DEBUG("%s", buf);
00321     }
00322 #endif
00323 
00324     mbedtls_ssl_conf_read_timeout(&(tlsDataParams->conf), IOT_SSL_READ_TIMEOUT);
00325 
00326     FUNC_EXIT_RC((IoT_Error_t) ret);
00327 }
00328 
00329 IoT_Error_t iot_tls_write(Network *pNetwork, unsigned char *pMsg, size_t len, awsTimer *timer, size_t *written_len) 
00330 {
00331     size_t written_so_far;
00332     bool isErrorFlag = false;
00333     int frags;
00334     int ret = 0;
00335     TLSDataParams *tlsDataParams = &(pNetwork->tlsDataParams);
00336 
00337     FUNC_ENTRY;
00338     for(written_so_far = 0, frags = 0;
00339         written_so_far < len && !has_timer_expired(timer); written_so_far += ret, frags++) {
00340         while(!has_timer_expired(timer) &&
00341               (ret = mbedtls_ssl_write(&(tlsDataParams->ssl), pMsg + written_so_far, len - written_so_far)) <= 0) {
00342             if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
00343                 IOT_ERROR("FAILED!\n  ! mbedtls_ssl_write returned -0x%x\n\n", -ret);
00344                 /* All other negative return values indicate connection needs to be reset.
00345                  * Will be caught in ping request so ignored here */
00346                 isErrorFlag = true;
00347                 break;
00348             }
00349         }
00350         if(isErrorFlag) {
00351             break;
00352         }
00353     }
00354 
00355     *written_len = written_so_far;
00356 
00357     if(isErrorFlag) {
00358         FUNC_EXIT_RC(NETWORK_SSL_WRITE_ERROR);
00359     } else if(has_timer_expired(timer) && written_so_far != len) {
00360         FUNC_EXIT_RC(NETWORK_SSL_WRITE_TIMEOUT_ERROR);
00361     }
00362 
00363     FUNC_EXIT_RC(AWS_SUCCESS);
00364 }
00365 
00366 IoT_Error_t iot_tls_read(Network *pNetwork, unsigned char *pMsg, size_t len, awsTimer *timer, size_t *read_len) 
00367 {
00368     mbedtls_ssl_context *ssl = &(pNetwork->tlsDataParams.ssl);
00369     size_t rxLen = 0;
00370     int ret=0;
00371     FUNC_ENTRY;
00372 
00373     while (len > 0) {
00374         // This read will timeout after IOT_SSL_READ_TIMEOUT if there's no data to be read
00375 
00376         while( ret == 0 && !has_timer_expired(timer) )
00377             ret = mbedtls_ssl_read(ssl, pMsg, len);
00378 
00379         if (ret > 0) {
00380             rxLen += ret;
00381             pMsg += ret;
00382             len -= ret;
00383             } 
00384         else if (ret == 0 || (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret != MBEDTLS_ERR_SSL_TIMEOUT)) {
00385             FUNC_EXIT_RC(NETWORK_SSL_READ_ERROR);
00386             }
00387         }
00388 
00389     if (len == 0) {
00390         *read_len = rxLen;
00391         FUNC_EXIT_RC(AWS_SUCCESS);
00392     }
00393 
00394     if (rxLen == 0) {
00395         FUNC_EXIT_RC(NETWORK_SSL_NOTHING_TO_READ);
00396     } else {
00397         FUNC_EXIT_RC(NETWORK_SSL_READ_TIMEOUT_ERROR);
00398     }
00399 }
00400 
00401 IoT_Error_t iot_tls_disconnect(Network *pNetwork) 
00402 {
00403     mbedtls_ssl_context *ssl = &(pNetwork->tlsDataParams.ssl);
00404     int ret = 0;
00405     FUNC_ENTRY;
00406     do {
00407         ret = mbedtls_ssl_close_notify(ssl);
00408     } while(ret == MBEDTLS_ERR_SSL_WANT_WRITE);
00409 
00410     /* All other negative return values indicate connection needs to be reset.
00411      * No further action required since this is disconnect call */
00412 
00413     FUNC_EXIT_RC(AWS_SUCCESS);
00414 }
00415 
00416 IoT_Error_t iot_tls_destroy(Network *pNetwork) 
00417 {
00418     TLSDataParams *tlsDataParams = &(pNetwork->tlsDataParams);
00419     FUNC_ENTRY;
00420 
00421     mbedtls_aws_free(&(tlsDataParams->server_fd));
00422 
00423     mbedtls_x509_crt_free(&(tlsDataParams->clicert));
00424     mbedtls_x509_crt_free(&(tlsDataParams->cacert));
00425     mbedtls_pk_free(&(tlsDataParams->pkey));
00426     mbedtls_ssl_free(&(tlsDataParams->ssl));
00427     mbedtls_ssl_config_free(&(tlsDataParams->conf));
00428     mbedtls_ctr_drbg_free(&(tlsDataParams->ctr_drbg));
00429     mbedtls_entropy_free(&(tlsDataParams->entropy));
00430 
00431     FUNC_EXIT_RC(AWS_SUCCESS);
00432 }
00433 
00434