Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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
Generated on Tue Jul 12 2022 19:02:38 by
1.7.2