test

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 #ifdef __cplusplus
00017 extern "C" {
00018 #endif
00019 
00020 #include <stdbool.h>
00021 #include <string.h>
00022 #include <timer_platform.h>
00023 #include <network_interface.h>
00024 
00025 #include "aws_iot_error.h"
00026 #include "aws_iot_log.h"
00027 #include "network_interface.h"
00028 #include "network_platform.h"
00029 
00030 #include "aws_iot_config.h"
00031 
00032 /* This is the value used for ssl read timeout */
00033 #define IOT_SSL_READ_TIMEOUT 10
00034 
00035 /*
00036  * This is a function to do further verification if needed on the cert received
00037  */
00038 
00039 static int _iot_tls_verify_cert(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) {
00040     char buf[1024];
00041     ((void) data);
00042 
00043     IOT_DEBUG("\nVerify requested for (Depth %d):\n", depth);
00044     mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt);
00045     IOT_DEBUG("%s", buf);
00046 
00047     if((*flags) == 0) {
00048         IOT_DEBUG("  This certificate has no flags\n");
00049     } else {
00050         IOT_DEBUG(buf, sizeof(buf), "  ! ", *flags);
00051         IOT_DEBUG("%s\n", buf);
00052     }
00053 
00054     return 0;
00055 }
00056 
00057 void _iot_tls_set_connect_params(Network *pNetwork, char *pRootCALocation, char *pDeviceCertLocation,
00058                                  char *pDevicePrivateKeyLocation, char *pDestinationURL,
00059                                  uint16_t destinationPort, uint32_t timeout_ms, bool ServerVerificationFlag) {
00060     pNetwork->tlsConnectParams.DestinationPort = destinationPort;
00061     pNetwork->tlsConnectParams.pDestinationURL = pDestinationURL;
00062     pNetwork->tlsConnectParams.pDeviceCertLocation = pDeviceCertLocation;
00063     pNetwork->tlsConnectParams.pDevicePrivateKeyLocation = pDevicePrivateKeyLocation;
00064     pNetwork->tlsConnectParams.pRootCALocation = pRootCALocation;
00065     pNetwork->tlsConnectParams.timeout_ms = timeout_ms;
00066     pNetwork->tlsConnectParams.ServerVerificationFlag = ServerVerificationFlag;
00067 }
00068 
00069 IoT_Error_t iot_tls_init(Network *pNetwork, char *pRootCALocation, char *pDeviceCertLocation,
00070                          char *pDevicePrivateKeyLocation, char *pDestinationURL,
00071                          uint16_t destinationPort, uint32_t timeout_ms, bool ServerVerificationFlag) {
00072     _iot_tls_set_connect_params(pNetwork, pRootCALocation, pDeviceCertLocation, pDevicePrivateKeyLocation,
00073                                 pDestinationURL, destinationPort, timeout_ms, ServerVerificationFlag);
00074 
00075     pNetwork->connect = iot_tls_connect;
00076     pNetwork->read = iot_tls_read;
00077     pNetwork->write = iot_tls_write;
00078     pNetwork->disconnect = iot_tls_disconnect;
00079     pNetwork->isConnected = iot_tls_is_connected;
00080     pNetwork->destroy = iot_tls_destroy;
00081 
00082     pNetwork->tlsDataParams.flags = 0;
00083 
00084     return SUCCESS;
00085 }
00086 
00087 IoT_Error_t iot_tls_is_connected(Network *pNetwork) {
00088     /* Use this to add implementation which can check for physical layer disconnect */
00089     return NETWORK_PHYSICAL_LAYER_CONNECTED;
00090 }
00091 
00092 IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *params) {
00093     int ret = 0;
00094     const char *pers = "aws_iot_tls_wrapper";
00095     TLSDataParams *tlsDataParams = NULL;
00096     char portBuffer[6];
00097     char vrfy_buf[512];
00098 #ifdef IOT_DEBUG
00099     unsigned char buf[MBEDTLS_SSL_MAX_CONTENT_LEN + 1];
00100 #endif
00101 
00102     if(NULL == pNetwork) {
00103         return NULL_VALUE_ERROR;
00104     }
00105 
00106     if(NULL != params) {
00107         _iot_tls_set_connect_params(pNetwork, params->pRootCALocation, params->pDeviceCertLocation,
00108                                     params->pDevicePrivateKeyLocation, params->pDestinationURL,
00109                                     params->DestinationPort, params->timeout_ms, params->ServerVerificationFlag);
00110     }
00111 
00112     tlsDataParams = &(pNetwork->tlsDataParams);
00113 
00114     mbedtls_net_init(&(tlsDataParams->server_fd));
00115     mbedtls_ssl_init(&(tlsDataParams->ssl));
00116     mbedtls_ssl_config_init(&(tlsDataParams->conf));
00117     mbedtls_ctr_drbg_init(&(tlsDataParams->ctr_drbg));
00118     mbedtls_x509_crt_init(&(tlsDataParams->cacert));
00119     mbedtls_x509_crt_init(&(tlsDataParams->clicert));
00120     mbedtls_pk_init(&(tlsDataParams->pkey));
00121 
00122     IOT_DEBUG("\n  . Seeding the random number generator...");
00123     mbedtls_entropy_init(&(tlsDataParams->entropy));
00124     if((ret = mbedtls_ctr_drbg_seed(&(tlsDataParams->ctr_drbg), mbedtls_entropy_func, &(tlsDataParams->entropy),
00125                                     (const unsigned char *) pers, strlen(pers))) != 0) {
00126         IOT_ERROR(" failed\n  ! mbedtls_ctr_drbg_seed returned -0x%x\n", -ret);
00127         return NETWORK_MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED;
00128     }
00129 
00130     IOT_DEBUG("  . Loading the CA root certificate ...");
00131     ret = mbedtls_x509_crt_parse(&(tlsDataParams->cacert), (const unsigned char *)AWS_IOT_ROOT_CA, strlen(AWS_IOT_ROOT_CA));
00132     if(ret < 0) {
00133         IOT_ERROR(" failed\n  !  mbedtls_x509_crt_parse returned -0x%x while parsing root cert\n\n", -ret);
00134         return NETWORK_X509_ROOT_CRT_PARSE_ERROR;
00135     }
00136     IOT_DEBUG(" ok (%d skipped)\n", ret);
00137 
00138     IOT_DEBUG("  . Loading the client cert. and key...");
00139     ret = mbedtls_x509_crt_parse(&(tlsDataParams->clicert), (const unsigned char *)AWS_IOT_CERTIFICATE, strlen(AWS_IOT_CERTIFICATE));
00140     if(ret != 0) {
00141         IOT_ERROR(" failed\n  !  mbedtls_x509_crt_parse returned -0x%x while parsing device cert\n\n", -ret);
00142         return NETWORK_X509_DEVICE_CRT_PARSE_ERROR;
00143     }
00144 
00145     ret = mbedtls_pk_parse_key(&(tlsDataParams->pkey), (const unsigned char *)AWS_IOT_PRIVATE_KEY, strlen(AWS_IOT_PRIVATE_KEY), (const unsigned char *)(PASSWORD),strlen(PASSWORD));
00146     if(ret != 0) {
00147         IOT_ERROR(" failed\n  !  mbedtls_pk_parse_key returned -0x%x while parsing private key\n\n", -ret);
00148         IOT_DEBUG(" path : %s ", pNetwork->tlsConnectParams.pDevicePrivateKeyLocation);
00149         return NETWORK_PK_PRIVATE_KEY_PARSE_ERROR;
00150     }
00151     IOT_DEBUG(" ok\n");
00152     snprintf(portBuffer, 6, "%d", pNetwork->tlsConnectParams.DestinationPort);
00153     IOT_DEBUG("  . Connecting to %s/%s...", pNetwork->tlsConnectParams.pDestinationURL, portBuffer);
00154     if((ret = mbedtls_net_connect(&(tlsDataParams->server_fd), pNetwork->tlsConnectParams.pDestinationURL,
00155                                   portBuffer, MBEDTLS_NET_PROTO_TCP)) != 0) {
00156         IOT_ERROR(" failed\n  ! mbedtls_net_connect returned -0x%x\n\n", -ret);
00157         switch(ret) {
00158             case MBEDTLS_ERR_NET_SOCKET_FAILED:
00159                 return NETWORK_ERR_NET_SOCKET_FAILED;
00160             case MBEDTLS_ERR_NET_UNKNOWN_HOST:
00161                 return NETWORK_ERR_NET_UNKNOWN_HOST;
00162             case MBEDTLS_ERR_NET_CONNECT_FAILED:
00163             default:
00164                 return NETWORK_ERR_NET_CONNECT_FAILED;
00165         };
00166     }
00167 
00168     ret = mbedtls_net_set_block(&(tlsDataParams->server_fd));
00169     if(ret != 0) {
00170         IOT_ERROR(" failed\n  ! net_set_(non)block() returned -0x%x\n\n", -ret);
00171         return SSL_CONNECTION_ERROR;
00172     } IOT_DEBUG(" ok\n");
00173 
00174     IOT_DEBUG("  . Setting up the SSL/TLS structure...");
00175     if((ret = mbedtls_ssl_config_defaults(&(tlsDataParams->conf), MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM,
00176                                           MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
00177         IOT_ERROR(" failed\n  ! mbedtls_ssl_config_defaults returned -0x%x\n\n", -ret);
00178         return SSL_CONNECTION_ERROR;
00179     }
00180 
00181     mbedtls_ssl_conf_verify(&(tlsDataParams->conf), _iot_tls_verify_cert, NULL);
00182     if(pNetwork->tlsConnectParams.ServerVerificationFlag == true) {
00183         mbedtls_ssl_conf_authmode(&(tlsDataParams->conf), MBEDTLS_SSL_VERIFY_REQUIRED);
00184     } else {
00185         mbedtls_ssl_conf_authmode(&(tlsDataParams->conf), MBEDTLS_SSL_VERIFY_OPTIONAL);
00186     }
00187     mbedtls_ssl_conf_rng(&(tlsDataParams->conf), mbedtls_ctr_drbg_random, &(tlsDataParams->ctr_drbg));
00188 
00189     mbedtls_ssl_conf_ca_chain(&(tlsDataParams->conf), &(tlsDataParams->cacert), NULL);
00190     if((ret = mbedtls_ssl_conf_own_cert(&(tlsDataParams->conf), &(tlsDataParams->clicert), &(tlsDataParams->pkey))) !=
00191        0) {
00192         IOT_ERROR(" failed\n  ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret);
00193         return SSL_CONNECTION_ERROR;
00194     }
00195 
00196     mbedtls_ssl_conf_read_timeout(&(tlsDataParams->conf), pNetwork->tlsConnectParams.timeout_ms);
00197 
00198     if((ret = mbedtls_ssl_setup(&(tlsDataParams->ssl), &(tlsDataParams->conf))) != 0) {
00199         IOT_ERROR(" failed\n  ! mbedtls_ssl_setup returned -0x%x\n\n", -ret);
00200         return SSL_CONNECTION_ERROR;
00201     }
00202     if((ret = mbedtls_ssl_set_hostname(&(tlsDataParams->ssl), pNetwork->tlsConnectParams.pDestinationURL)) != 0) {
00203         IOT_ERROR(" failed\n  ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
00204         return SSL_CONNECTION_ERROR;
00205     }
00206     IOT_DEBUG("\n\nSSL state connect : %d ", tlsDataParams->ssl.state);
00207     mbedtls_ssl_set_bio(&(tlsDataParams->ssl), &(tlsDataParams->server_fd), mbedtls_net_send, NULL,
00208                         mbedtls_net_recv_timeout);
00209     IOT_DEBUG(" ok\n");
00210 
00211     IOT_DEBUG("\n\nSSL state connect : %d ", tlsDataParams->ssl.state);
00212     IOT_DEBUG("  . Performing the SSL/TLS handshake...");
00213     while((ret = mbedtls_ssl_handshake(&(tlsDataParams->ssl))) != 0) {
00214         if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
00215             IOT_ERROR(" failed\n  ! mbedtls_ssl_handshake returned -0x%x\n", -ret);
00216             if(ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
00217                 IOT_ERROR("    Unable to verify the server's certificate. "
00218                               "Either it is invalid,\n"
00219                               "    or you didn't set ca_file or ca_path "
00220                               "to an appropriate value.\n"
00221                               "    Alternatively, you may want to use "
00222                               "auth_mode=optional for testing purposes.\n");
00223             }
00224             return SSL_CONNECTION_ERROR;
00225         }
00226     }
00227 
00228     IOT_DEBUG(" ok\n    [ Protocol is %s ]\n    [ Ciphersuite is %s ]\n", mbedtls_ssl_get_version(&(tlsDataParams->ssl)),
00229           mbedtls_ssl_get_ciphersuite(&(tlsDataParams->ssl)));
00230     if((ret = mbedtls_ssl_get_record_expansion(&(tlsDataParams->ssl))) >= 0) {
00231         IOT_DEBUG("    [ Record expansion is %d ]\n", ret);
00232     } else {
00233         IOT_DEBUG("    [ Record expansion is unknown (compression) ]\n");
00234     }
00235 
00236     IOT_DEBUG("  . Verifying peer X.509 certificate...");
00237 
00238     if(pNetwork->tlsConnectParams.ServerVerificationFlag == true) {
00239         if((tlsDataParams->flags = mbedtls_ssl_get_verify_result(&(tlsDataParams->ssl))) != 0) {
00240             IOT_ERROR(" failed\n");
00241             mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "  ! ", tlsDataParams->flags);
00242             IOT_ERROR("%s\n", vrfy_buf);
00243             ret = SSL_CONNECTION_ERROR;
00244         } else {
00245             IOT_DEBUG(" ok\n");
00246             ret = SUCCESS;
00247         }
00248     } else {
00249         IOT_DEBUG(" Server Verification skipped\n");
00250         ret = SUCCESS;
00251     }
00252 
00253 #ifdef IOT_DEBUG
00254     if (mbedtls_ssl_get_peer_cert(&(tlsDataParams->ssl)) != NULL) {
00255         IOT_DEBUG("  . Peer certificate information    ...\n");
00256         mbedtls_x509_crt_info((char *) buf, sizeof(buf) - 1, "      ", mbedtls_ssl_get_peer_cert(&(tlsDataParams->ssl)));
00257         IOT_DEBUG("%s\n", buf);
00258     }
00259 #endif
00260 
00261     mbedtls_ssl_conf_read_timeout(&(tlsDataParams->conf), IOT_SSL_READ_TIMEOUT);
00262 
00263     return (IoT_Error_t) ret;
00264 }
00265 
00266 IoT_Error_t iot_tls_write(Network *pNetwork, unsigned char *pMsg, size_t len, TimerAWS *timer, size_t *written_len) {
00267     size_t written_so_far;
00268     bool isErrorFlag = false;
00269     int frags, ret;
00270     TLSDataParams *tlsDataParams = &(pNetwork->tlsDataParams);
00271 
00272     for(written_so_far = 0, frags = 0;
00273         written_so_far < len && !has_timer_expired(timer); written_so_far += ret, frags++) {
00274         while(!has_timer_expired(timer) &&
00275               (ret = mbedtls_ssl_write(&(tlsDataParams->ssl), pMsg + written_so_far, len - written_so_far)) <= 0) {
00276             if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
00277                 IOT_ERROR(" failed\n  ! mbedtls_ssl_write returned -0x%x\n\n", -ret);
00278                 /* All other negative return values indicate connection needs to be reset.
00279                 * Will be caught in ping request so ignored here */
00280                 isErrorFlag = true;
00281                 break;
00282             }
00283         }
00284         if(isErrorFlag) {
00285             break;
00286         }
00287     }
00288 
00289     *written_len = written_so_far;
00290 
00291     if(isErrorFlag) {
00292         return NETWORK_SSL_WRITE_ERROR;
00293     } else if(has_timer_expired(timer) && written_so_far != len) {
00294         return NETWORK_SSL_WRITE_TIMEOUT_ERROR;
00295     }
00296 
00297     return SUCCESS;
00298 }
00299 
00300 IoT_Error_t iot_tls_read(Network *pNetwork, unsigned char *pMsg, size_t len, TimerAWS *timer, size_t *read_len) {
00301     mbedtls_ssl_context *ssl = &(pNetwork->tlsDataParams.ssl);
00302     size_t rxLen = 0;
00303     int ret;
00304 
00305     while (len > 0) {
00306         // This read will timeout after IOT_SSL_READ_TIMEOUT if there's no data to be read
00307         ret = mbedtls_ssl_read(ssl, pMsg, len);
00308         if (ret > 0) {
00309             rxLen += ret;
00310             pMsg += ret;
00311             len -= ret;
00312         } else if (ret == 0 || (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret != MBEDTLS_ERR_SSL_TIMEOUT)) {
00313             return NETWORK_SSL_READ_ERROR;
00314         }
00315 
00316         // Evaluate timeout after the read to make sure read is done at least once
00317         if (has_timer_expired(timer)) {
00318             break;
00319         }
00320     }
00321 
00322     if (len == 0) {
00323         *read_len = rxLen;
00324         return SUCCESS;
00325     }
00326 
00327     if (rxLen == 0) {
00328         return NETWORK_SSL_NOTHING_TO_READ;
00329     } else {
00330         return NETWORK_SSL_READ_TIMEOUT_ERROR;
00331     }
00332 }
00333 
00334 IoT_Error_t iot_tls_disconnect(Network *pNetwork) {
00335     mbedtls_ssl_context *ssl = &(pNetwork->tlsDataParams.ssl);
00336     int ret = 0;
00337     do {
00338         ret = mbedtls_ssl_close_notify(ssl);
00339     } while(ret == MBEDTLS_ERR_SSL_WANT_WRITE);
00340 
00341     /* All other negative return values indicate connection needs to be reset.
00342      * No further action required since this is disconnect call */
00343 
00344     return SUCCESS;
00345 }
00346 
00347 IoT_Error_t iot_tls_destroy(Network *pNetwork) {
00348     TLSDataParams *tlsDataParams = &(pNetwork->tlsDataParams);
00349 
00350     mbedtls_net_free(&(tlsDataParams->server_fd));
00351 
00352     mbedtls_x509_crt_free(&(tlsDataParams->clicert));
00353     mbedtls_x509_crt_free(&(tlsDataParams->cacert));
00354     mbedtls_pk_free(&(tlsDataParams->pkey));
00355     mbedtls_ssl_free(&(tlsDataParams->ssl));
00356     mbedtls_ssl_config_free(&(tlsDataParams->conf));
00357     mbedtls_ctr_drbg_free(&(tlsDataParams->ctr_drbg));
00358     mbedtls_entropy_free(&(tlsDataParams->entropy));
00359 
00360     return SUCCESS;
00361 }
00362 
00363 #ifdef __cplusplus
00364 }
00365 #endif