/* * X.509 cert verification callback * * XXX This is a stub to get you started, just printing some information. */ static int my_verify( void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags ) { char buf[1024]; struct vrfy_state *state = (struct vrfy_state *) data; mbedtls_printf( "\nVerify requested for (Depth %d):\n", depth ); mbedtls_x509_crt_info( buf, sizeof( buf ), " ", crt ); mbedtls_printf( "%s", buf ); x509_crt_pkhash( crt, buf, sizeof( buf ) ); mbedtls_printf( " Certificate public key hash: %s\n", buf ); // TODO: check certificate against pins (void) state; if ( ( *flags ) == 0 ) mbedtls_printf( " This certificate has no issues\n" ); else { mbedtls_x509_crt_verify_info( buf, sizeof( buf ), " ! ", *flags ); mbedtls_printf( "%s\n", buf ); } return( 0 ); }
static bool mbedtls_handshake_result(const pmbedtls_msg Threadmsg) { if (Threadmsg == NULL) return false; if (Threadmsg->ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER) { int ret = 0; if (Threadmsg->listen_fd.fd == -1) ret = ssl_option.client.cert_ca_sector.flag; else ret = ssl_option.server.cert_ca_sector.flag; if (ret == 1){ ret = mbedtls_ssl_get_verify_result(&Threadmsg->ssl); if (ret != 0) { char vrfy_buf[512]; os_memset(vrfy_buf, 0, sizeof(vrfy_buf)-1); mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "!", ret); os_printf("%s\n", vrfy_buf); Threadmsg->verify_result = ret; return false; } else return true; } else return true; }else return false; }
static int do_handshake( mbedtls_ssl_context *ssl ) { int ret; uint32_t flags; unsigned char buf[1024]; memset(buf, 0, 1024); /* * 4. Handshake */ mbedtls_printf( " . Performing the SSL/TLS handshake..." ); fflush( stdout ); while( ( ret = mbedtls_ssl_handshake( ssl ) ) != 0 ) { if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) { #if defined(MBEDTLS_ERROR_C) mbedtls_strerror( ret, (char *) buf, 1024 ); #endif mbedtls_printf( " failed\n ! mbedtls_ssl_handshake returned %d: %s\n\n", ret, buf ); return( -1 ); } } mbedtls_printf( " ok\n [ Ciphersuite is %s ]\n", mbedtls_ssl_get_ciphersuite( ssl ) ); /* * 5. Verify the server certificate */ mbedtls_printf( " . Verifying peer X.509 certificate..." ); /* In real life, we probably want to bail out when ret != 0 */ if( ( flags = mbedtls_ssl_get_verify_result( ssl ) ) != 0 ) { char vrfy_buf[512]; mbedtls_printf( " failed\n" ); mbedtls_x509_crt_verify_info( vrfy_buf, sizeof( vrfy_buf ), " ! ", flags ); mbedtls_printf( "%s\n", vrfy_buf ); } else mbedtls_printf( " ok\n" ); mbedtls_printf( " . Peer certificate information ...\n" ); mbedtls_x509_crt_info( (char *) buf, sizeof( buf ) - 1, " ", mbedtls_ssl_get_peer_cert( ssl ) ); mbedtls_printf( "%s\n", buf ); return( 0 ); }
static void verify_certificate(esp_tls_t *tls) { int flags; char buf[100]; if ((flags = mbedtls_ssl_get_verify_result(&tls->ssl)) != 0) { ESP_LOGI(TAG, "Failed to verify peer certificate!"); bzero(buf, sizeof(buf)); mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags); ESP_LOGI(TAG, "verification info: %s", buf); } else { ESP_LOGI(TAG, "Certificate verified."); } }
static int my_verify( void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags ) { char buf[1024]; ((void) data); // some hokey way to say "UNUSED"??? printf( "\nVerify requested for (Depth %d):\n", depth ); mbedtls_x509_crt_info( buf, sizeof( buf ) - 1, "", crt ); printf( "%s", buf ); if ( ( *flags ) == 0 ) printf( " This certificate has no flags\n" ); else { mbedtls_x509_crt_verify_info( buf, sizeof( buf ), " ! ", *flags ); printf( "%s\n", buf ); } return( 0 ); }
int ssl_socket_connect(void *state_data, void *data, bool timeout_enable, bool nonblock) { struct ssl_state *state = (struct ssl_state*)state_data; int ret, flags; if (socket_connect(state->net_ctx.fd, data, timeout_enable)) return -1; if (mbedtls_ssl_config_defaults(&state->conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT) != 0) return -1; mbedtls_ssl_conf_authmode(&state->conf, MBEDTLS_SSL_VERIFY_OPTIONAL); mbedtls_ssl_conf_ca_chain(&state->conf, &state->ca, NULL); mbedtls_ssl_conf_rng(&state->conf, mbedtls_ctr_drbg_random, &state->ctr_drbg); mbedtls_ssl_conf_dbg(&state->conf, ssl_debug, stderr); if (mbedtls_ssl_setup(&state->ctx, &state->conf) != 0) return -1; #if defined(MBEDTLS_X509_CRT_PARSE_C) if (mbedtls_ssl_set_hostname(&state->ctx, state->domain) != 0) return -1; #endif mbedtls_ssl_set_bio(&state->ctx, &state->net_ctx, mbedtls_net_send, mbedtls_net_recv, NULL); while ((ret = mbedtls_ssl_handshake(&state->ctx)) != 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) return -1; } if ((flags = mbedtls_ssl_get_verify_result(&state->ctx)) != 0) { char vrfy_buf[512]; mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags); } return state->net_ctx.fd; }
int main( void ) { int ret, i; mbedtls_x509_crt cacert; mbedtls_x509_crl crl; char buf[10240]; mbedtls_x509_crt_init( &cacert ); mbedtls_x509_crl_init( &crl ); /* * 1.1. Load the trusted CA */ mbedtls_printf( "\n . Loading the CA root certificate ..." ); fflush( stdout ); /* * Alternatively, you may load the CA certificates from a .pem or * .crt file by calling mbedtls_x509_crt_parse_file( &cacert, "myca.crt" ). */ ret = mbedtls_x509_crt_parse_file( &cacert, "ssl/test-ca/test-ca.crt" ); if( ret != 0 ) { mbedtls_printf( " failed\n ! mbedtls_x509_crt_parse_file returned %d\n\n", ret ); goto exit; } mbedtls_printf( " ok\n" ); mbedtls_x509_crt_info( buf, 1024, "CRT: ", &cacert ); mbedtls_printf("%s\n", buf ); /* * 1.2. Load the CRL */ mbedtls_printf( " . Loading the CRL ..." ); fflush( stdout ); ret = mbedtls_x509_crl_parse_file( &crl, "ssl/test-ca/crl.pem" ); if( ret != 0 ) { mbedtls_printf( " failed\n ! mbedtls_x509_crl_parse_file returned %d\n\n", ret ); goto exit; } mbedtls_printf( " ok\n" ); mbedtls_x509_crl_info( buf, 1024, "CRL: ", &crl ); mbedtls_printf("%s\n", buf ); for( i = 0; i < MAX_CLIENT_CERTS; i++ ) { /* * 1.3. Load own certificate */ char name[512]; uint32_t flags; mbedtls_x509_crt clicert; mbedtls_pk_context pk; mbedtls_x509_crt_init( &clicert ); mbedtls_pk_init( &pk ); mbedtls_snprintf(name, 512, "ssl/test-ca/%s", client_certificates[i]); mbedtls_printf( " . Loading the client certificate %s...", name ); fflush( stdout ); ret = mbedtls_x509_crt_parse_file( &clicert, name ); if( ret != 0 ) { mbedtls_printf( " failed\n ! mbedtls_x509_crt_parse_file returned %d\n\n", ret ); goto exit; } mbedtls_printf( " ok\n" ); /* * 1.4. Verify certificate validity with CA certificate */ mbedtls_printf( " . Verify the client certificate with CA certificate..." ); fflush( stdout ); ret = mbedtls_x509_crt_verify( &clicert, &cacert, &crl, NULL, &flags, NULL, NULL ); if( ret != 0 ) { if( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ) { char vrfy_buf[512]; mbedtls_printf( " failed\n" ); mbedtls_x509_crt_verify_info( vrfy_buf, sizeof( vrfy_buf ), " ! ", flags ); mbedtls_printf( "%s\n", vrfy_buf ); } else { mbedtls_printf( " failed\n ! mbedtls_x509_crt_verify returned %d\n\n", ret ); goto exit; } } mbedtls_printf( " ok\n" ); /* * 1.5. Load own private key */ mbedtls_snprintf(name, 512, "ssl/test-ca/%s", client_private_keys[i]); mbedtls_printf( " . Loading the client private key %s...", name ); fflush( stdout ); ret = mbedtls_pk_parse_keyfile( &pk, name, NULL ); if( ret != 0 ) { mbedtls_printf( " failed\n ! mbedtls_pk_parse_keyfile returned %d\n\n", ret ); goto exit; } mbedtls_printf( " ok\n" ); /* * 1.6. Verify certificate validity with private key */ mbedtls_printf( " . Verify the client certificate with private key..." ); fflush( stdout ); /* EC NOT IMPLEMENTED YET */ if( ! mbedtls_pk_can_do( &clicert.pk, MBEDTLS_PK_RSA ) ) { mbedtls_printf( " failed\n ! certificate's key is not RSA\n\n" ); ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE; goto exit; } ret = mbedtls_mpi_cmp_mpi(&mbedtls_pk_rsa( pk )->N, &mbedtls_pk_rsa( clicert.pk )->N); if( ret != 0 ) { mbedtls_printf( " failed\n ! mbedtls_mpi_cmp_mpi for N returned %d\n\n", ret ); goto exit; } ret = mbedtls_mpi_cmp_mpi(&mbedtls_pk_rsa( pk )->E, &mbedtls_pk_rsa( clicert.pk )->E); if( ret != 0 ) { mbedtls_printf( " failed\n ! mbedtls_mpi_cmp_mpi for E returned %d\n\n", ret ); goto exit; } ret = mbedtls_rsa_check_privkey( mbedtls_pk_rsa( pk ) ); if( ret != 0 ) { mbedtls_printf( " failed\n ! mbedtls_rsa_check_privkey returned %d\n\n", ret ); goto exit; } mbedtls_printf( " ok\n" ); mbedtls_x509_crt_free( &clicert ); mbedtls_pk_free( &pk ); } exit: mbedtls_x509_crt_free( &cacert ); mbedtls_x509_crl_free( &crl ); #if defined(_WIN32) mbedtls_printf( " + Press Enter to exit this program.\n" ); fflush( stdout ); getchar(); #endif return( ret ); }
IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *params) { if(NULL == pNetwork) { return NULL_VALUE_ERROR; } if(NULL != params) { _iot_tls_set_connect_params(pNetwork, params->pRootCALocation, params->pDeviceCertLocation, params->pDevicePrivateKeyLocation, params->pDestinationURL, params->DestinationPort, params->timeout_ms, params->ServerVerificationFlag); } int ret = 0; const char *pers = "aws_iot_tls_wrapper"; #ifdef IOT_DEBUG unsigned char buf[MBEDTLS_SSL_MAX_CONTENT_LEN + 1]; #endif TLSDataParams *tlsDataParams = &(pNetwork->tlsDataParams); mbedtls_net_init(&(tlsDataParams->server_fd)); mbedtls_ssl_init(&(tlsDataParams->ssl)); mbedtls_ssl_config_init(&(tlsDataParams->conf)); mbedtls_ctr_drbg_init(&(tlsDataParams->ctr_drbg)); mbedtls_x509_crt_init(&(tlsDataParams->cacert)); mbedtls_x509_crt_init(&(tlsDataParams->clicert)); mbedtls_pk_init(&(tlsDataParams->pkey)); DEBUG("\n . Seeding the random number generator..."); mbedtls_entropy_init(&(tlsDataParams->entropy)); if ((ret = mbedtls_ctr_drbg_seed(&(tlsDataParams->ctr_drbg), mbedtls_entropy_func, &(tlsDataParams->entropy), (const unsigned char *) pers, strlen(pers))) != 0) { ERROR(" failed\n ! mbedtls_ctr_drbg_seed returned -0x%x\n", -ret); return NETWORK_MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED; } DEBUG(" . Loading the CA root certificate ..."); ret = mbedtls_x509_crt_parse_file(&(tlsDataParams->cacert), pNetwork->tlsConnectParams.pRootCALocation); if (ret < 0) { ERROR(" failed\n ! mbedtls_x509_crt_parse returned -0x%x while parsing root cert\n\n", -ret); return NETWORK_X509_ROOT_CRT_PARSE_ERROR; } DEBUG(" ok (%d skipped)\n", ret); DEBUG(" . Loading the client cert. and key..."); ret = mbedtls_x509_crt_parse_file(&(tlsDataParams->clicert), pNetwork->tlsConnectParams.pDeviceCertLocation); if (ret != 0) { ERROR(" failed\n ! mbedtls_x509_crt_parse returned -0x%x while parsing device cert\n\n", -ret); return NETWORK_X509_DEVICE_CRT_PARSE_ERROR; } ret = mbedtls_pk_parse_keyfile(&(tlsDataParams->pkey), pNetwork->tlsConnectParams.pDevicePrivateKeyLocation, ""); if (ret != 0) { ERROR(" failed\n ! mbedtls_pk_parse_key returned -0x%x while parsing private key\n\n", -ret); DEBUG(" path : %s ", pNetwork->tlsConnectParams.pDevicePrivateKeyLocation); return NETWORK_PK_PRIVATE_KEY_PARSE_ERROR; } DEBUG(" ok\n"); char portBuffer[6]; snprintf(portBuffer, 6, "%d", pNetwork->tlsConnectParams.DestinationPort); DEBUG(" . Connecting to %s/%s...", pNetwork->tlsConnectParams.pDestinationURL, portBuffer); if ((ret = mbedtls_net_connect(&(tlsDataParams->server_fd), pNetwork->tlsConnectParams.pDestinationURL, portBuffer, MBEDTLS_NET_PROTO_TCP)) != 0) { ERROR(" failed\n ! mbedtls_net_connect returned -0x%x\n\n", -ret); switch(ret) { case MBEDTLS_ERR_NET_SOCKET_FAILED: return NETWORK_ERR_NET_SOCKET_FAILED; case MBEDTLS_ERR_NET_UNKNOWN_HOST: return NETWORK_ERR_NET_UNKNOWN_HOST; case MBEDTLS_ERR_NET_CONNECT_FAILED: default: return NETWORK_ERR_NET_CONNECT_FAILED; }; } ret = mbedtls_net_set_block(&(tlsDataParams->server_fd)); if (ret != 0) { ERROR(" failed\n ! net_set_(non)block() returned -0x%x\n\n", -ret); return SSL_CONNECTION_ERROR; } DEBUG(" ok\n"); DEBUG(" . Setting up the SSL/TLS structure..."); if ((ret = mbedtls_ssl_config_defaults(&(tlsDataParams->conf), MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { ERROR(" failed\n ! mbedtls_ssl_config_defaults returned -0x%x\n\n", -ret); return SSL_CONNECTION_ERROR; } mbedtls_ssl_conf_verify(&(tlsDataParams->conf), _iot_tls_verify_cert, NULL); if (pNetwork->tlsConnectParams.ServerVerificationFlag == true) { mbedtls_ssl_conf_authmode(&(tlsDataParams->conf), MBEDTLS_SSL_VERIFY_REQUIRED); } else { mbedtls_ssl_conf_authmode(&(tlsDataParams->conf), MBEDTLS_SSL_VERIFY_OPTIONAL); } mbedtls_ssl_conf_rng(&(tlsDataParams->conf), mbedtls_ctr_drbg_random, &(tlsDataParams->ctr_drbg)); mbedtls_ssl_conf_ca_chain(&(tlsDataParams->conf), &(tlsDataParams->cacert), NULL); if ((ret = mbedtls_ssl_conf_own_cert(&(tlsDataParams->conf), &(tlsDataParams->clicert), &(tlsDataParams->pkey))) != 0) { ERROR(" failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret); return SSL_CONNECTION_ERROR; } mbedtls_ssl_conf_read_timeout(&(tlsDataParams->conf), pNetwork->tlsConnectParams.timeout_ms); if ((ret = mbedtls_ssl_setup(&(tlsDataParams->ssl), &(tlsDataParams->conf))) != 0) { ERROR(" failed\n ! mbedtls_ssl_setup returned -0x%x\n\n", -ret); return SSL_CONNECTION_ERROR; } if ((ret = mbedtls_ssl_set_hostname(&(tlsDataParams->ssl), pNetwork->tlsConnectParams.pDestinationURL)) != 0) { ERROR(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret); return SSL_CONNECTION_ERROR; } DEBUG("\n\nSSL state connect : %d ", tlsDataParams->ssl.state); mbedtls_ssl_set_bio(&(tlsDataParams->ssl), &(tlsDataParams->server_fd), mbedtls_net_send, NULL, mbedtls_net_recv_timeout); DEBUG(" ok\n"); DEBUG("\n\nSSL state connect : %d ", tlsDataParams->ssl.state); DEBUG(" . Performing the SSL/TLS handshake..."); while ((ret = mbedtls_ssl_handshake(&(tlsDataParams->ssl))) != 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { ERROR(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n", -ret); if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) { ERROR(" Unable to verify the server's certificate. " "Either it is invalid,\n" " or you didn't set ca_file or ca_path " "to an appropriate value.\n" " Alternatively, you may want to use " "auth_mode=optional for testing purposes.\n"); } return SSL_CONNECTION_ERROR; } } DEBUG(" ok\n [ Protocol is %s ]\n [ Ciphersuite is %s ]\n", mbedtls_ssl_get_version(&(tlsDataParams->ssl)), mbedtls_ssl_get_ciphersuite(&(tlsDataParams->ssl))); if ((ret = mbedtls_ssl_get_record_expansion(&(tlsDataParams->ssl))) >= 0) { DEBUG(" [ Record expansion is %d ]\n", ret); } else { DEBUG(" [ Record expansion is unknown (compression) ]\n"); } DEBUG(" . Verifying peer X.509 certificate..."); if(pNetwork->tlsConnectParams.ServerVerificationFlag == true) { if((tlsDataParams->flags = mbedtls_ssl_get_verify_result(&(tlsDataParams->ssl))) != 0) { char vrfy_buf[512]; ERROR(" failed\n"); mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", tlsDataParams->flags); ERROR("%s\n", vrfy_buf); ret = SSL_CONNECTION_ERROR; } else { DEBUG(" ok\n"); ret = SUCCESS; } } else { DEBUG(" Server Verification skipped\n"); ret = SUCCESS; } #ifdef IOT_DEBUG if (mbedtls_ssl_get_peer_cert(&(tlsDataParams->ssl)) != NULL) { DEBUG(" . Peer certificate information ...\n"); mbedtls_x509_crt_info((char *) buf, sizeof(buf) - 1, " ", mbedtls_ssl_get_peer_cert(&(tlsDataParams->ssl))); DEBUG("%s\n", buf); } #endif mbedtls_ssl_conf_read_timeout(&(tlsDataParams->conf), IOT_SSL_READ_TIMEOUT); return ret; }
int dtlsclient_main( int argc, char *argv[] ) { int ret, len; mbedtls_net_context server_fd; uint32_t flags; unsigned char buf[1024]; const char *pers = "dtls_client"; int retry_left = MAX_RETRY; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_ssl_context ssl; mbedtls_ssl_config conf; mbedtls_x509_crt cacert; mbedtls_timing_delay_context timer; ((void) argc); ((void) argv); #if defined(MBEDTLS_DEBUG_C) mbedtls_debug_set_threshold( DEBUG_LEVEL ); #endif /* * 0. Initialize the RNG and the session data */ mbedtls_net_init( &server_fd ); mbedtls_ssl_init( &ssl ); mbedtls_ssl_config_init( &conf ); mbedtls_x509_crt_init( &cacert ); mbedtls_ctr_drbg_init( &ctr_drbg ); mbedtls_printf( "\n . Seeding the random number generator..." ); fflush( stdout ); mbedtls_entropy_init( &entropy ); if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) pers, strlen( pers ) ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret ); goto exit; } mbedtls_printf( " ok\n" ); /* * 0. Load certificates */ mbedtls_printf( " . Loading the CA root certificate ..." ); fflush( stdout ); ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) mbedtls_test_cas_pem, mbedtls_test_cas_pem_len ); if( ret < 0 ) { mbedtls_printf( " failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret ); goto exit; } mbedtls_printf( " ok (%d skipped)\n", ret ); /* * 1. Start the connection */ mbedtls_printf( " . Connecting to udp/%s/%s...", SERVER_NAME, SERVER_PORT ); fflush( stdout ); if( ( ret = mbedtls_net_connect( &server_fd, SERVER_ADDR, SERVER_PORT, MBEDTLS_NET_PROTO_UDP ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_net_connect returned %d\n\n", ret ); goto exit; } mbedtls_printf( " ok\n" ); /* * 2. Setup stuff */ mbedtls_printf( " . Setting up the DTLS structure..." ); fflush( stdout ); if( ( ret = mbedtls_ssl_config_defaults( &conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret ); goto exit; } /* OPTIONAL is usually a bad choice for security, but makes interop easier * in this simplified example, in which the ca chain is hardcoded. * Production code should set a proper ca chain and use REQUIRED. */ mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_OPTIONAL ); mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL ); mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg ); mbedtls_ssl_conf_dbg( &conf, my_debug, stdout ); if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_setup returned %d\n\n", ret ); goto exit; } if( ( ret = mbedtls_ssl_set_hostname( &ssl, SERVER_NAME ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret ); goto exit; } mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout ); mbedtls_ssl_set_timer_cb( &ssl, &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay ); mbedtls_printf( " ok\n" ); /* * 4. Handshake */ mbedtls_printf( " . Performing the SSL/TLS handshake..." ); fflush( stdout ); do ret = mbedtls_ssl_handshake( &ssl ); while( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ); if( ret != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", -ret ); goto exit; } mbedtls_printf( " ok\n" ); /* * 5. Verify the server certificate */ mbedtls_printf( " . Verifying peer X.509 certificate..." ); /* In real life, we would have used MBEDTLS_SSL_VERIFY_REQUIRED so that the * handshake would not succeed if the peer's cert is bad. Even if we used * MBEDTLS_SSL_VERIFY_OPTIONAL, we would bail out here if ret != 0 */ if( ( flags = mbedtls_ssl_get_verify_result( &ssl ) ) != 0 ) { char vrfy_buf[512]; mbedtls_printf( " failed\n" ); mbedtls_x509_crt_verify_info( vrfy_buf, sizeof( vrfy_buf ), " ! ", flags ); mbedtls_printf( "%s\n", vrfy_buf ); } else mbedtls_printf( " ok\n" ); /* * 6. Write the echo request */ send_request: mbedtls_printf( " > Write to server:" ); fflush( stdout ); len = sizeof( MESSAGE ) - 1; do ret = mbedtls_ssl_write( &ssl, (unsigned char *) MESSAGE, len ); while( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ); if( ret < 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_write returned %d\n\n", ret ); goto exit; } len = ret; mbedtls_printf( " %d bytes written\n\n%s\n\n", len, MESSAGE ); /* * 7. Read the echo response */ mbedtls_printf( " < Read from server:" ); fflush( stdout ); len = sizeof( buf ) - 1; memset( buf, 0, sizeof( buf ) ); do ret = mbedtls_ssl_read( &ssl, buf, len ); while( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ); if( ret <= 0 ) { switch( ret ) { case MBEDTLS_ERR_SSL_TIMEOUT: mbedtls_printf( " timeout\n\n" ); if( retry_left-- > 0 ) goto send_request; goto exit; case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: mbedtls_printf( " connection was closed gracefully\n" ); ret = 0; goto close_notify; default: mbedtls_printf( " mbedtls_ssl_read returned -0x%x\n\n", -ret ); goto exit; } } len = ret; mbedtls_printf( " %d bytes read\n\n%s\n\n", len, buf ); /* * 8. Done, cleanly close the connection */ close_notify: mbedtls_printf( " . Closing the connection..." ); /* No error checking, the connection might be closed already */ do ret = mbedtls_ssl_close_notify( &ssl ); while( ret == MBEDTLS_ERR_SSL_WANT_WRITE ); ret = 0; mbedtls_printf( " done\n" ); /* * 9. Final clean-ups and exit */ exit: #ifdef MBEDTLS_ERROR_C if( ret != 0 ) { char error_buf[100]; mbedtls_strerror( ret, error_buf, 100 ); mbedtls_printf( "Last error was: %d - %s\n\n", ret, error_buf ); } #endif mbedtls_net_free( &server_fd ); mbedtls_x509_crt_free( &cacert ); mbedtls_ssl_free( &ssl ); mbedtls_ssl_config_free( &conf ); mbedtls_ctr_drbg_free( &ctr_drbg ); mbedtls_entropy_free( &entropy ); #if defined(_WIN32) mbedtls_printf( " + Press Enter to exit this program.\n" ); fflush( stdout ); getchar(); #endif /* Shell can not handle large exit numbers -> 1 for errors */ if( ret < 0 ) ret = 1; return( ret ); }
int main( int argc, const char *argv[] ) { /* Client and server declarations. */ int ret; int len; #if SOCKET_COMMUNICATION mbedtls_net_context listen_fd, client_fd, server_fd; #endif unsigned char buf[1024]; /* Handshake step counter */ size_t step = 1; int flags; mbedtls_ssl_context s_ssl, c_ssl; mbedtls_ssl_config s_conf, c_conf; mbedtls_x509_crt srvcert; mbedtls_pk_context pkey; #if defined(MBEDTLS_SSL_CACHE_C) mbedtls_ssl_cache_context cache; #endif if( argc == 3) { packet_in_num = atoi(argv[1]); packet_in_file = argv[2]; } else if( argc != 1) { usage(argv[0]); exit(1); } /* Server init */ #if SOCKET_COMMUNICATION mbedtls_net_init( &listen_fd ); mbedtls_net_init( &client_fd ); #endif mbedtls_ssl_init( &s_ssl ); mbedtls_ssl_config_init( &s_conf ); #if defined(MBEDTLS_SSL_CACHE_C) mbedtls_ssl_cache_init( &cache ); #endif mbedtls_x509_crt_init( &srvcert ); mbedtls_pk_init( &pkey ); /* Client init */ #if SOCKET_COMMUNICATION mbedtls_net_init( &server_fd ); #endif mbedtls_ssl_init( &c_ssl ); mbedtls_ssl_config_init( &c_conf ); /*mbedtls_x509_crt_init( &cacert );*/ #if defined(MBEDTLS_DEBUG_C) mbedtls_debug_set_threshold( DEBUG_LEVEL ); #endif /* * Server: * Load the certificates and private RSA key */ if( packet_in_num == 0 ) { mbedtls_printf( " . Loading the server cert. and key..." ); fflush( stdout ); } /* * This demonstration program uses embedded test certificates. * Instead, you may want to use mbedtls_x509_crt_parse_file() to read the * server and CA certificates, as well as mbedtls_pk_parse_keyfile(). */ ret = mbedtls_x509_crt_parse( &srvcert, (const unsigned char *) mbedtls_test_srv_crt, mbedtls_test_srv_crt_len ); if( ret != 0 ) { mbedtls_printf( " failed\n ! mbedtls_x509_crt_parse returned %d\n\n", ret ); goto exit; } ret = mbedtls_x509_crt_parse( &srvcert, (const unsigned char *) mbedtls_test_cas_pem, mbedtls_test_cas_pem_len ); if( ret != 0 ) { mbedtls_printf( " failed\n ! mbedtls_x509_crt_parse returned %d\n\n", ret ); goto exit; } ret = mbedtls_pk_parse_key( &pkey, (const unsigned char *) mbedtls_test_srv_key, mbedtls_test_srv_key_len, NULL, 0 ); if( ret != 0 ) { mbedtls_printf( " failed\n ! mbedtls_pk_parse_key returned %d\n\n", ret ); goto exit; } if( packet_in_num == 0 ) { mbedtls_printf( " ok\n" ); } /* * Server: * Setup stuff */ if( packet_in_num == 0 ) { mbedtls_printf( " . Server: Setting up the SSL data...." ); fflush( stdout ); } if( ( ret = mbedtls_ssl_config_defaults( &s_conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret ); goto exit; } mbedtls_ssl_conf_rng( &s_conf, mbedtls_ctr_drbg_deterministic, NULL ); mbedtls_ssl_conf_dbg( &s_conf, my_debug, stdout ); #if defined(MBEDTLS_SSL_CACHE_C) mbedtls_ssl_conf_session_cache( &s_conf, &cache, mbedtls_ssl_cache_get, mbedtls_ssl_cache_set ); #endif mbedtls_ssl_conf_ca_chain( &s_conf, srvcert.next, NULL ); if( ( ret = mbedtls_ssl_conf_own_cert( &s_conf, &srvcert, &pkey ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret ); goto exit; } if( ( ret = mbedtls_ssl_setup( &s_ssl, &s_conf ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_setup returned %d\n\n", ret ); goto exit; } if( packet_in_num == 0 ) { mbedtls_printf( " ok\n" ); } mbedtls_ssl_session_reset( &s_ssl ); #if SOCKET_COMMUNICATION /* * Server: * Setup the listening TCP socket */ if( packet_in_num == 0 ) { mbedtls_printf( " . Bind on https://localhost:%s/ ...", SERVER_PORT ); fflush( stdout ); } if( ( ret = mbedtls_net_bind( &listen_fd, NULL, SERVER_PORT, MBEDTLS_NET_PROTO_TCP ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_net_bind returned %d\n\n", ret ); goto exit; } if( packet_in_num == 0 ) { mbedtls_printf( " ok\n" ); } /* * Client: * Start the connection */ if( packet_in_num == 0 ) { mbedtls_printf( " . Connecting to tcp/%s/%s...", SERVER_NAME, SERVER_PORT ); fflush( stdout ); } if( ( ret = mbedtls_net_connect( &server_fd, SERVER_NAME, SERVER_PORT, MBEDTLS_NET_PROTO_TCP ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_net_connect returned %d\n\n", ret ); goto exit; } if( packet_in_num == 0 ) { mbedtls_printf( " ok\n" ); } /* * Server: * Start listening for client connections */ if( packet_in_num == 0 ) { mbedtls_printf( " . Waiting for a remote connection ..." ); fflush( stdout ); } /* * Server: * Accept client connection (socket is set non-blocking in * library/net.c) */ if( ( ret = mbedtls_net_accept( &listen_fd, &client_fd, NULL, 0, NULL ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_net_accept returned %d\n\n", ret ); goto exit; } if( packet_in_num == 0 ) { mbedtls_printf( " ok\n" ); } mbedtls_ssl_set_bio( &s_ssl, &client_fd, mbedtls_send_custom, mbedtls_recv_custom, NULL ); #else mbedtls_ssl_set_bio( &s_ssl, NULL, mbedtls_server_send_buf, mbedtls_server_recv_buf, NULL ); #endif /* * Client: * Setup stuff */ if( packet_in_num == 0 ) { mbedtls_printf( " . Client: Setting up the SSL/TLS structure..." ); fflush( stdout ); } if( ( ret = mbedtls_ssl_config_defaults( &c_conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret ); goto exit; } if( packet_in_num == 0 ) { mbedtls_printf( " ok\n" ); } /* OPTIONAL is not optimal for security, * but makes interop easier in this simplified example */ mbedtls_ssl_conf_authmode( &c_conf, MBEDTLS_SSL_VERIFY_OPTIONAL ); /* NONE permits man-in-the-middle attacks. */ /*mbedtls_ssl_conf_authmode( &c_conf, MBEDTLS_SSL_VERIFY_NONE );*/ /*mbedtls_ssl_conf_authmode( &c_conf, MBEDTLS_SSL_VERIFY_REQUIRED );*/ mbedtls_ssl_conf_ca_chain( &c_conf, &srvcert, NULL ); mbedtls_ssl_conf_rng( &c_conf, mbedtls_ctr_drbg_deterministic, NULL ); mbedtls_ssl_conf_dbg( &c_conf, my_debug, stdout ); if( ( ret = mbedtls_ssl_setup( &c_ssl, &c_conf ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_setup returned %d\n\n", ret ); goto exit; } if( ( ret = mbedtls_ssl_set_hostname( &c_ssl, "mbed TLS Server 1" ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret ); goto exit; } #if SOCKET_COMMUNICATION mbedtls_ssl_set_bio( &c_ssl, &server_fd, mbedtls_send_custom, mbedtls_recv_custom, NULL ); #else mbedtls_ssl_set_bio( &c_ssl, NULL, mbedtls_client_send_buf, mbedtls_client_recv_buf, NULL ); #endif if( packet_in_num == 0 ) { mbedtls_printf( " . Performing the SSL/TLS handshake...\n" ); fflush( stdout ); } /* * The following number of steps are hardcoded to ensure * that the client and server complete the handshake without * waiting infinitely for the other side to send data. * * 1 2 3 4 5 6 7 8 9 10 */ int client_steps[] = { 2, 1, 1, 1, 4, 2, 1, 1, 2, 1 }; int server_steps[] = { 3, 1, 1, 2, 3, 1, 2, 1, 1, 1 }; do { /* * Client: * Handshake step */ int i; int no_steps; if( c_ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER) { no_steps = 0; } else { no_steps = client_steps[step - 1]; } for (i = 0; i < no_steps; i++) { if( ( ret = mbedtls_ssl_handshake_step( &c_ssl ) ) != 0 ) { if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) { mbedtls_printf( " failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", -ret ); goto exit; } } } if( packet_in_num == 0 ) { mbedtls_printf( "--- client handshake step %zd ok\n", step ); } /* * Server: * Handshake step */ if( s_ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER) { no_steps = 0; } else { no_steps = server_steps[step - 1]; } for (i = 0; i < no_steps; i++) { if( ( ret = mbedtls_ssl_handshake_step( &s_ssl ) ) != 0 ) { if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) { mbedtls_printf( " failed\n ! mbedtls_ssl_handshake returned %d\n\n", ret ); goto exit; } } } if( packet_in_num == 0 ) { mbedtls_printf( "--- server handshake step %zd ok\n", step ); } step++; } while( ((c_ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER) || (s_ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER)) && (step <= MAX_HANDSHAKE_STEPS) ); if( packet_in_num == 0 ) { mbedtls_printf( "c_ssl.state: %d\n", c_ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER ); mbedtls_printf( "s_ssl.state: %d\n", s_ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER ); } /* * Client: * Verify the server certificate */ if( packet_in_num == 0 ) { mbedtls_printf( " . Verifying peer X.509 certificate..." ); } /* In real life, we probably want to bail out when ret != 0 */ if( ( flags = mbedtls_ssl_get_verify_result( &c_ssl ) ) != 0 ) { char vrfy_buf[512]; mbedtls_printf( " failed\n" ); mbedtls_x509_crt_verify_info( vrfy_buf, sizeof( vrfy_buf ), " ! ", flags ); mbedtls_printf( "%s\n", vrfy_buf ); } else if( packet_in_num == 0 ) { mbedtls_printf( " ok\n" ); } /* * Client: * Write the GET request */ if( packet_in_num == 0 ) { mbedtls_printf( " > Write to server:" ); fflush( stdout ); } len = sprintf( (char *) buf, GET_REQUEST ); while( ( ret = mbedtls_ssl_write( &c_ssl, buf, len ) ) <= 0 ) { if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) { mbedtls_printf( " failed\n ! mbedtls_ssl_write returned %d\n\n", ret ); goto exit; } } len = ret; if( packet_in_num == 0 ) { mbedtls_printf( " %d bytes written\n\n%s", len, (char *) buf ); } /* * Server: * Read the HTTP Request */ if( packet_in_num == 0 ) { mbedtls_printf( " < Read from client:" ); fflush( stdout ); } do { len = sizeof( buf ) - 1; memset( buf, 0, sizeof( buf ) ); ret = mbedtls_ssl_read( &s_ssl, buf, len ); if( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ) continue; if( ret <= 0 ) { switch( ret ) { case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: mbedtls_printf( " connection was closed gracefully\n" ); break; case MBEDTLS_ERR_NET_CONN_RESET: mbedtls_printf( " connection was reset by peer\n" ); break; default: mbedtls_printf( " mbedtls_ssl_read returned -0x%x\n", -ret ); break; } break; } len = ret; if( packet_in_num == 0 ) { mbedtls_printf( " %d bytes read\n\n%s", len, (char *) buf ); } if( ret > 0 ) break; } while( 1 ); /* * Server: * Write the 200 Response */ if( packet_in_num == 0 ) { mbedtls_printf( " > Write to client:" ); fflush( stdout ); } len = sprintf( (char *) buf, HTTP_RESPONSE, mbedtls_ssl_get_ciphersuite( &s_ssl ) ); while( ( ret = mbedtls_ssl_write( &s_ssl, buf, len ) ) <= 0 ) { if( ret == MBEDTLS_ERR_NET_CONN_RESET ) { mbedtls_printf( " failed\n ! peer closed the connection\n\n" ); goto exit; } if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) { mbedtls_printf( " failed\n ! mbedtls_ssl_write returned %d\n\n", ret ); goto exit; } } len = ret; if( packet_in_num == 0 ) { mbedtls_printf( " %d bytes written\n\n%s\n", len, (char *) buf ); } /* * Client: * Read the HTTP response */ if( packet_in_num == 0 ) { mbedtls_printf( " < Read from server:" ); fflush( stdout ); } do { len = sizeof( buf ) - 1; memset( buf, 0, sizeof( buf ) ); ret = mbedtls_ssl_read( &c_ssl, buf, len ); if( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ) continue; if( ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY ) { ret = 0; break; } if( ret < 0 ) { mbedtls_printf( "failed\n ! mbedtls_ssl_read returned %d\n\n", ret ); break; } if( ret == 0 ) { mbedtls_printf( "\n\nEOF\n\n" ); break; } len = ret; if( packet_in_num == 0 ) { mbedtls_printf( " %d bytes read\n\n%s", len, (char *) buf ); } /* * Server: * Client read response. Close connection. */ if ( packet_in_num == 0 ) { mbedtls_printf( " . Closing the connection..." ); fflush( stdout ); } while( ( ret = mbedtls_ssl_close_notify( &s_ssl ) ) < 0 ) { if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) { mbedtls_printf( " failed\n ! mbedtls_ssl_close_notify returned %d\n\n", ret ); goto exit; } } if( packet_in_num == 0 ) { mbedtls_printf( " ok\n" ); } } while( 1 ); /* * Client: * Close connection. */ if( packet_in_num == 0 ) { mbedtls_printf( " . Closing the connection..." ); fflush( stdout ); } mbedtls_ssl_close_notify( &c_ssl ); if( packet_in_num == 0 ) { mbedtls_printf( " ok\n" ); } /* * Server: * We do not have multiple clients and therefore do not goto reset. */ /*ret = 0;*/ /*goto reset;*/ exit: #ifdef MBEDTLS_ERROR_C if( ret != 0 ) { char error_buf[100]; mbedtls_strerror( ret, error_buf, 100 ); mbedtls_printf("Last error was: %d - %s\n\n", ret, error_buf ); } #endif #if SOCKET_COMMUNICATION mbedtls_net_free( &client_fd ); mbedtls_net_free( &listen_fd ); mbedtls_net_free( &server_fd ); #endif mbedtls_x509_crt_free( &srvcert ); mbedtls_pk_free( &pkey ); mbedtls_ssl_free( &s_ssl ); mbedtls_ssl_free( &c_ssl ); mbedtls_ssl_config_free( &s_conf ); mbedtls_ssl_config_free( &c_conf ); #if defined(MBEDTLS_SSL_CACHE_C) mbedtls_ssl_cache_free( &cache ); #endif #if defined(_WIN32) mbedtls_printf( " Press Enter to exit this program.\n" ); fflush( stdout ); getchar(); #endif return( ret ); }
static void https_get_task(void *pvParameters) { char buf[512]; int ret, flags, len; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_ssl_context ssl; mbedtls_x509_crt cacert; mbedtls_ssl_config conf; mbedtls_net_context server_fd; mbedtls_ssl_init(&ssl); mbedtls_x509_crt_init(&cacert); mbedtls_ctr_drbg_init(&ctr_drbg); ESP_LOGI(TAG, "Seeding the random number generator"); mbedtls_ssl_config_init(&conf); mbedtls_entropy_init(&entropy); if((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0)) != 0) { ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", ret); abort(); } ESP_LOGI(TAG, "Loading the CA root certificate..."); ret = mbedtls_x509_crt_parse(&cacert, server_root_cert_pem_start, server_root_cert_pem_end-server_root_cert_pem_start); if(ret < 0) { ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); abort(); } ESP_LOGI(TAG, "Setting hostname for TLS session..."); /* Hostname set here should match CN in server certificate */ if((ret = mbedtls_ssl_set_hostname(&ssl, WEB_SERVER)) != 0) { ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned -0x%x", -ret); abort(); } ESP_LOGI(TAG, "Setting up the SSL/TLS structure..."); if((ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret); goto exit; } /* MBEDTLS_SSL_VERIFY_OPTIONAL is bad for security, in this example it will print a warning if CA verification fails but it will continue to connect. You should consider using MBEDTLS_SSL_VERIFY_REQUIRED in your own code. */ mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL); mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL); mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); #ifdef CONFIG_MBEDTLS_DEBUG mbedtls_esp_enable_debug_log(&conf, 4); #endif if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) { ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x\n\n", -ret); goto exit; } while(1) { /* Wait for the callback to set the CONNECTED_BIT in the event group. */ xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY); ESP_LOGI(TAG, "Connected to AP"); mbedtls_net_init(&server_fd); ESP_LOGI(TAG, "Connecting to %s:%s...", WEB_SERVER, WEB_PORT); if ((ret = mbedtls_net_connect(&server_fd, WEB_SERVER, WEB_PORT, MBEDTLS_NET_PROTO_TCP)) != 0) { ESP_LOGE(TAG, "mbedtls_net_connect returned -%x", -ret); goto exit; } ESP_LOGI(TAG, "Connected."); mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL); ESP_LOGI(TAG, "Performing the SSL/TLS handshake..."); while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret); goto exit; } } ESP_LOGI(TAG, "Verifying peer X.509 certificate..."); if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) { /* In real life, we probably want to close connection if ret != 0 */ ESP_LOGW(TAG, "Failed to verify peer certificate!"); bzero(buf, sizeof(buf)); mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags); ESP_LOGW(TAG, "verification info: %s", buf); } else { ESP_LOGI(TAG, "Certificate verified."); } ESP_LOGI(TAG, "Cipher suite is %s", mbedtls_ssl_get_ciphersuite(&ssl)); ESP_LOGI(TAG, "Writing HTTP request..."); size_t written_bytes = 0; do { ret = mbedtls_ssl_write(&ssl, (const unsigned char *)REQUEST + written_bytes, strlen(REQUEST) - written_bytes); if (ret >= 0) { ESP_LOGI(TAG, "%d bytes written", ret); written_bytes += ret; } else if (ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret != MBEDTLS_ERR_SSL_WANT_READ) { ESP_LOGE(TAG, "mbedtls_ssl_write returned -0x%x", -ret); goto exit; } } while(written_bytes < strlen(REQUEST)); ESP_LOGI(TAG, "Reading HTTP response..."); do { len = sizeof(buf) - 1; bzero(buf, sizeof(buf)); ret = mbedtls_ssl_read(&ssl, (unsigned char *)buf, len); if(ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) continue; if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { ret = 0; break; } if(ret < 0) { ESP_LOGE(TAG, "mbedtls_ssl_read returned -0x%x", -ret); break; } if(ret == 0) { ESP_LOGI(TAG, "connection closed"); break; } len = ret; ESP_LOGD(TAG, "%d bytes read", len); /* Print response directly to stdout as it is read */ for(int i = 0; i < len; i++) { putchar(buf[i]); } } while(1); mbedtls_ssl_close_notify(&ssl); exit: mbedtls_ssl_session_reset(&ssl); mbedtls_net_free(&server_fd); if(ret != 0) { mbedtls_strerror(ret, buf, 100); ESP_LOGE(TAG, "Last error was: -0x%x - %s", -ret, buf); } putchar('\n'); // JSON output doesn't have a newline at end static int request_count; ESP_LOGI(TAG, "Completed %d requests", ++request_count); for(int countdown = 10; countdown >= 0; countdown--) { ESP_LOGI(TAG, "%d...", countdown); vTaskDelay(1000 / portTICK_PERIOD_MS); } ESP_LOGI(TAG, "Starting again!"); } }
mbedtls_x509_crt *load_cert_file( const char *ca_file, const char *certfile ) { int ret = 0; unsigned char buf[1024]; mbedtls_net_context server_fd; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_ssl_context ssl; mbedtls_ssl_config conf; mbedtls_x509_crt cacert; mbedtls_x509_crt *cur; mbedtls_x509_crt *cert; mbedtls_pk_context pkey; int i; uint32_t flags; int verify = 0; char *p, *q; /* * Set to sane values */ cert = (mbedtls_x509_crt *)mbedtls_calloc(1, sizeof(*cert)); cur = cert; mbedtls_x509_crt_init( cert ); mbedtls_ctr_drbg_init( &ctr_drbg ); mbedtls_x509_crt_init( &cacert ); /* Zeroize structure as CRL parsing is not supported and we have to pass it to the verify function */ mbedtls_pk_init( &pkey ); /* * 1.1. Load the trusted CA */ mbedtls_printf( " . Loading the CA root certificate ..." ); fflush( stdout ); ret = mbedtls_x509_crt_parse_file( &cacert, ca_file ); if( ret < 0 ) { fprintf(stderr, " failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret ); return NULL; } mbedtls_printf( " ok (%d skipped)\n", ret ); /* * 1.1. Load the certificate(s) */ printf( "\n . Loading the certificate at: %s ...", certfile); ret = mbedtls_x509_crt_parse_file( cert, certfile ); if( ret < 0 ) { char errorbuf[256]; mbedtls_strerror( ret, errorbuf, sizeof(errorbuf)); printf( " failed\n ! mbedtls_x509_crt_parse_file returned %d: %s\n\n", ret, errorbuf ); mbedtls_x509_crt_free( cert ); goto exit; } printf( " ok\n" ); /* * 1.2 Print the certificate(s) */ while( cur != NULL ) { printf( " . Peer certificate information ...\n" ); ret = mbedtls_x509_crt_info( (char *) buf, sizeof( buf ) - 1, " ", cur ); if( ret == -1 ) { printf( " failed\n ! mbedtls_x509_crt_info returned %d\n\n", ret ); goto exit; } printf( "%s\n", buf ); cur = cur->next; } ret = 0; /* * 1.3 Verify the certificate */ printf( " . Verifying X.509 certificate..." ); if( ( ret = mbedtls_x509_crt_verify( cert, &cacert, NULL, NULL, &flags, my_verify, NULL ) ) != 0 ) { char vrfy_buf[512]; printf( " failed\n" ); mbedtls_x509_crt_verify_info( vrfy_buf, sizeof( vrfy_buf ), " ! ", flags ); printf( "%s\n", vrfy_buf ); goto exit; } else printf( " ok\n" ); exit: //mbedtls_net_free( &server_fd ); mbedtls_x509_crt_free( &cacert ); mbedtls_pk_free( &pkey ); mbedtls_ctr_drbg_free( &ctr_drbg ); mbedtls_entropy_free( &entropy ); if( ret < 0 ) { mbedtls_x509_crt_free( cert ); mbedtls_free(cert); return NULL; } return cert; }
void WiiSocket::Update(bool read, bool write, bool except) { auto it = pending_sockops.begin(); while (it != pending_sockops.end()) { s32 ReturnValue = 0; bool forceNonBlock = false; IPCCommandType ct = static_cast<IPCCommandType>(Memory::Read_U32(it->_CommandAddress)); if (!it->is_ssl && ct == IPC_CMD_IOCTL) { u32 BufferIn = Memory::Read_U32(it->_CommandAddress + 0x10); u32 BufferInSize = Memory::Read_U32(it->_CommandAddress + 0x14); u32 BufferOut = Memory::Read_U32(it->_CommandAddress + 0x18); u32 BufferOutSize = Memory::Read_U32(it->_CommandAddress + 0x1C); switch (it->net_type) { case IOCTL_SO_FCNTL: { u32 cmd = Memory::Read_U32(BufferIn + 4); u32 arg = Memory::Read_U32(BufferIn + 8); ReturnValue = FCntl(cmd, arg); break; } case IOCTL_SO_BIND: { // u32 has_addr = Memory::Read_U32(BufferIn + 0x04); sockaddr_in local_name; WiiSockAddrIn* wii_name = (WiiSockAddrIn*)Memory::GetPointer(BufferIn + 0x08); WiiSockMan::Convert(*wii_name, local_name); int ret = bind(fd, (sockaddr*)&local_name, sizeof(local_name)); ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_BIND", false); INFO_LOG(WII_IPC_NET, "IOCTL_SO_BIND (%08X %s:%d) = %d ", fd, inet_ntoa(local_name.sin_addr), Common::swap16(local_name.sin_port), ret); break; } case IOCTL_SO_CONNECT: { // u32 has_addr = Memory::Read_U32(BufferIn + 0x04); sockaddr_in local_name; WiiSockAddrIn* wii_name = (WiiSockAddrIn*)Memory::GetPointer(BufferIn + 0x08); WiiSockMan::Convert(*wii_name, local_name); int ret = connect(fd, (sockaddr*)&local_name, sizeof(local_name)); ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_CONNECT", false); INFO_LOG(WII_IPC_NET, "IOCTL_SO_CONNECT (%08x, %s:%d)", fd, inet_ntoa(local_name.sin_addr), Common::swap16(local_name.sin_port)); break; } case IOCTL_SO_ACCEPT: { if (BufferOutSize > 0) { sockaddr_in local_name; WiiSockAddrIn* wii_name = (WiiSockAddrIn*)Memory::GetPointer(BufferOut); WiiSockMan::Convert(*wii_name, local_name); socklen_t addrlen = sizeof(sockaddr_in); int ret = (s32)accept(fd, (sockaddr*)&local_name, &addrlen); ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_ACCEPT", true); WiiSockMan::Convert(local_name, *wii_name, addrlen); } else { int ret = (s32)accept(fd, nullptr, nullptr); ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_ACCEPT", true); } WiiSockMan::GetInstance().AddSocket(ReturnValue); INFO_LOG(WII_IPC_NET, "IOCTL_SO_ACCEPT " "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", BufferIn, BufferInSize, BufferOut, BufferOutSize); break; } default: break; } // Fix blocking error codes if (!nonBlock) { if (it->net_type == IOCTL_SO_CONNECT && ReturnValue == -SO_EISCONN) { ReturnValue = SO_SUCCESS; } } } else if (ct == IPC_CMD_IOCTLV) { SIOCtlVBuffer CommandBuffer(it->_CommandAddress); u32 BufferIn = 0, BufferIn2 = 0; u32 BufferInSize = 0, BufferInSize2 = 0; u32 BufferOut = 0, BufferOut2 = 0; u32 BufferOutSize = 0, BufferOutSize2 = 0; if (CommandBuffer.InBuffer.size() > 0) { BufferIn = CommandBuffer.InBuffer.at(0).m_Address; BufferInSize = CommandBuffer.InBuffer.at(0).m_Size; } if (CommandBuffer.PayloadBuffer.size() > 0) { BufferOut = CommandBuffer.PayloadBuffer.at(0).m_Address; BufferOutSize = CommandBuffer.PayloadBuffer.at(0).m_Size; } if (CommandBuffer.PayloadBuffer.size() > 1) { BufferOut2 = CommandBuffer.PayloadBuffer.at(1).m_Address; BufferOutSize2 = CommandBuffer.PayloadBuffer.at(1).m_Size; } if (CommandBuffer.InBuffer.size() > 1) { BufferIn2 = CommandBuffer.InBuffer.at(1).m_Address; BufferInSize2 = CommandBuffer.InBuffer.at(1).m_Size; } if (it->is_ssl) { int sslID = Memory::Read_U32(BufferOut) - 1; if (SSLID_VALID(sslID)) { switch (it->ssl_type) { case IOCTLV_NET_SSL_DOHANDSHAKE: { mbedtls_ssl_context* ctx = &CWII_IPC_HLE_Device_net_ssl::_SSL[sslID].ctx; int ret = mbedtls_ssl_handshake(ctx); if (ret) { char error_buffer[256] = ""; mbedtls_strerror(ret, error_buffer, sizeof(error_buffer)); ERROR_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_DOHANDSHAKE: %s", error_buffer); } switch (ret) { case 0: Memory::Write_U32(SSL_OK, BufferIn); break; case MBEDTLS_ERR_SSL_WANT_READ: Memory::Write_U32(SSL_ERR_RAGAIN, BufferIn); if (!nonBlock) ReturnValue = SSL_ERR_RAGAIN; break; case MBEDTLS_ERR_SSL_WANT_WRITE: Memory::Write_U32(SSL_ERR_WAGAIN, BufferIn); if (!nonBlock) ReturnValue = SSL_ERR_WAGAIN; break; case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: { char error_buffer[256] = ""; int res = mbedtls_ssl_get_verify_result(ctx); mbedtls_x509_crt_verify_info(error_buffer, sizeof(error_buffer), "", res); ERROR_LOG(WII_IPC_SSL, "MBEDTLS_ERR_X509_CERT_VERIFY_FAILED (verify_result = %d): %s", res, error_buffer); if (res & MBEDTLS_X509_BADCERT_CN_MISMATCH) res = SSL_ERR_VCOMMONNAME; else if (res & MBEDTLS_X509_BADCERT_NOT_TRUSTED) res = SSL_ERR_VROOTCA; else if (res & MBEDTLS_X509_BADCERT_REVOKED) res = SSL_ERR_VCHAIN; else if (res & MBEDTLS_X509_BADCERT_EXPIRED || res & MBEDTLS_X509_BADCERT_FUTURE) res = SSL_ERR_VDATE; else res = SSL_ERR_FAILED; Memory::Write_U32(res, BufferIn); if (!nonBlock) ReturnValue = res; break; } default: Memory::Write_U32(SSL_ERR_FAILED, BufferIn); break; } // mbedtls_ssl_get_peer_cert(ctx) seems not to work if handshake failed // Below is an alternative to dump the peer certificate if (SConfig::GetInstance().m_SSLDumpPeerCert && ctx->session_negotiate != nullptr) { const mbedtls_x509_crt* cert = ctx->session_negotiate->peer_cert; if (cert != nullptr) { std::string filename = File::GetUserPath(D_DUMPSSL_IDX) + ((ctx->hostname != nullptr) ? ctx->hostname : "") + "_peercert.der"; File::IOFile(filename, "wb").WriteBytes(cert->raw.p, cert->raw.len); } } INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_DOHANDSHAKE = (%d) " "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " "BufferOut: (%08x, %i), BufferOut2: (%08x, %i)", ret, BufferIn, BufferInSize, BufferIn2, BufferInSize2, BufferOut, BufferOutSize, BufferOut2, BufferOutSize2); break; } case IOCTLV_NET_SSL_WRITE: { int ret = mbedtls_ssl_write(&CWII_IPC_HLE_Device_net_ssl::_SSL[sslID].ctx, Memory::GetPointer(BufferOut2), BufferOutSize2); if (SConfig::GetInstance().m_SSLDumpWrite && ret > 0) { std::string filename = File::GetUserPath(D_DUMPSSL_IDX) + SConfig::GetInstance().GetGameID() + "_write.bin"; File::IOFile(filename, "ab").WriteBytes(Memory::GetPointer(BufferOut2), ret); } if (ret >= 0) { // Return bytes written or SSL_ERR_ZERO if none Memory::Write_U32((ret == 0) ? SSL_ERR_ZERO : ret, BufferIn); } else { switch (ret) { case MBEDTLS_ERR_SSL_WANT_READ: Memory::Write_U32(SSL_ERR_RAGAIN, BufferIn); if (!nonBlock) ReturnValue = SSL_ERR_RAGAIN; break; case MBEDTLS_ERR_SSL_WANT_WRITE: Memory::Write_U32(SSL_ERR_WAGAIN, BufferIn); if (!nonBlock) ReturnValue = SSL_ERR_WAGAIN; break; default: Memory::Write_U32(SSL_ERR_FAILED, BufferIn); break; } } break; } case IOCTLV_NET_SSL_READ: { int ret = mbedtls_ssl_read(&CWII_IPC_HLE_Device_net_ssl::_SSL[sslID].ctx, Memory::GetPointer(BufferIn2), BufferInSize2); if (SConfig::GetInstance().m_SSLDumpRead && ret > 0) { std::string filename = File::GetUserPath(D_DUMPSSL_IDX) + SConfig::GetInstance().GetGameID() + "_read.bin"; File::IOFile(filename, "ab").WriteBytes(Memory::GetPointer(BufferIn2), ret); } if (ret >= 0) { // Return bytes read or SSL_ERR_ZERO if none Memory::Write_U32((ret == 0) ? SSL_ERR_ZERO : ret, BufferIn); } else { switch (ret) { case MBEDTLS_ERR_SSL_WANT_READ: Memory::Write_U32(SSL_ERR_RAGAIN, BufferIn); if (!nonBlock) ReturnValue = SSL_ERR_RAGAIN; break; case MBEDTLS_ERR_SSL_WANT_WRITE: Memory::Write_U32(SSL_ERR_WAGAIN, BufferIn); if (!nonBlock) ReturnValue = SSL_ERR_WAGAIN; break; default: Memory::Write_U32(SSL_ERR_FAILED, BufferIn); break; } } break; } default: break; } } else { Memory::Write_U32(SSL_ERR_ID, BufferIn); } } else { switch (it->net_type) { case IOCTLV_SO_SENDTO: { u32 flags = Memory::Read_U32(BufferIn2 + 0x04); u32 has_destaddr = Memory::Read_U32(BufferIn2 + 0x08); // Not a string, Windows requires a const char* for sendto const char* data = (const char*)Memory::GetPointer(BufferIn); // Act as non blocking when SO_MSG_NONBLOCK is specified forceNonBlock = ((flags & SO_MSG_NONBLOCK) == SO_MSG_NONBLOCK); // send/sendto only handles MSG_OOB flags &= SO_MSG_OOB; sockaddr_in local_name = {0}; if (has_destaddr) { WiiSockAddrIn* wii_name = (WiiSockAddrIn*)Memory::GetPointer(BufferIn2 + 0x0C); WiiSockMan::Convert(*wii_name, local_name); } int ret = sendto(fd, data, BufferInSize, flags, has_destaddr ? (struct sockaddr*)&local_name : nullptr, has_destaddr ? sizeof(sockaddr) : 0); ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_SENDTO", true); DEBUG_LOG( WII_IPC_NET, "%s = %d Socket: %08x, BufferIn: (%08x, %i), BufferIn2: (%08x, %i), %u.%u.%u.%u", has_destaddr ? "IOCTLV_SO_SENDTO " : "IOCTLV_SO_SEND ", ReturnValue, fd, BufferIn, BufferInSize, BufferIn2, BufferInSize2, local_name.sin_addr.s_addr & 0xFF, (local_name.sin_addr.s_addr >> 8) & 0xFF, (local_name.sin_addr.s_addr >> 16) & 0xFF, (local_name.sin_addr.s_addr >> 24) & 0xFF); break; } case IOCTLV_SO_RECVFROM: { u32 flags = Memory::Read_U32(BufferIn + 0x04); // Not a string, Windows requires a char* for recvfrom char* data = (char*)Memory::GetPointer(BufferOut); int data_len = BufferOutSize; sockaddr_in local_name; memset(&local_name, 0, sizeof(sockaddr_in)); if (BufferOutSize2 != 0) { WiiSockAddrIn* wii_name = (WiiSockAddrIn*)Memory::GetPointer(BufferOut2); WiiSockMan::Convert(*wii_name, local_name); } // Act as non blocking when SO_MSG_NONBLOCK is specified forceNonBlock = ((flags & SO_MSG_NONBLOCK) == SO_MSG_NONBLOCK); // recv/recvfrom only handles PEEK/OOB flags &= SO_MSG_PEEK | SO_MSG_OOB; #ifdef _WIN32 if (flags & SO_MSG_PEEK) { unsigned long totallen = 0; ioctlsocket(fd, FIONREAD, &totallen); ReturnValue = totallen; break; } #endif socklen_t addrlen = sizeof(sockaddr_in); int ret = recvfrom(fd, data, data_len, flags, BufferOutSize2 ? (struct sockaddr*)&local_name : nullptr, BufferOutSize2 ? &addrlen : nullptr); ReturnValue = WiiSockMan::GetNetErrorCode(ret, BufferOutSize2 ? "SO_RECVFROM" : "SO_RECV", true); INFO_LOG(WII_IPC_NET, "%s(%d, %p) Socket: %08X, Flags: %08X, " "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " "BufferOut: (%08x, %i), BufferOut2: (%08x, %i)", BufferOutSize2 ? "IOCTLV_SO_RECVFROM " : "IOCTLV_SO_RECV ", ReturnValue, data, fd, flags, BufferIn, BufferInSize, BufferIn2, BufferInSize2, BufferOut, BufferOutSize, BufferOut2, BufferOutSize2); if (BufferOutSize2 != 0) { WiiSockAddrIn* wii_name = (WiiSockAddrIn*)Memory::GetPointer(BufferOut2); WiiSockMan::Convert(local_name, *wii_name, addrlen); } break; } default: break; } } } if (nonBlock || forceNonBlock || (!it->is_ssl && ReturnValue != -SO_EAGAIN && ReturnValue != -SO_EINPROGRESS && ReturnValue != -SO_EALREADY) || (it->is_ssl && ReturnValue != SSL_ERR_WAGAIN && ReturnValue != SSL_ERR_RAGAIN)) { DEBUG_LOG(WII_IPC_NET, "IOCTL(V) Sock: %08x ioctl/v: %d returned: %d nonBlock: %d forceNonBlock: %d", fd, it->is_ssl ? (int)it->ssl_type : (int)it->net_type, ReturnValue, nonBlock, forceNonBlock); Memory::Write_U32(ReturnValue, it->_CommandAddress + 4); WII_IPC_HLE_Interface::EnqueueReply(it->_CommandAddress); it = pending_sockops.erase(it); } else { ++it; } }
IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *params) { int ret = SUCCESS; TLSDataParams *tlsDataParams = NULL; char portBuffer[6]; char info_buf[256]; if(NULL == pNetwork) { return NULL_VALUE_ERROR; } if(NULL != params) { _iot_tls_set_connect_params(pNetwork, params->pRootCALocation, params->pDeviceCertLocation, params->pDevicePrivateKeyLocation, params->pDestinationURL, params->DestinationPort, params->timeout_ms, params->ServerVerificationFlag); } tlsDataParams = &(pNetwork->tlsDataParams); mbedtls_net_init(&(tlsDataParams->server_fd)); mbedtls_ssl_init(&(tlsDataParams->ssl)); mbedtls_ssl_config_init(&(tlsDataParams->conf)); #ifdef CONFIG_MBEDTLS_DEBUG mbedtls_esp_enable_debug_log(&(tlsDataParams->conf), 4); #endif mbedtls_ctr_drbg_init(&(tlsDataParams->ctr_drbg)); mbedtls_x509_crt_init(&(tlsDataParams->cacert)); mbedtls_x509_crt_init(&(tlsDataParams->clicert)); mbedtls_pk_init(&(tlsDataParams->pkey)); ESP_LOGD(TAG, "Seeding the random number generator..."); mbedtls_entropy_init(&(tlsDataParams->entropy)); if((ret = mbedtls_ctr_drbg_seed(&(tlsDataParams->ctr_drbg), mbedtls_entropy_func, &(tlsDataParams->entropy), (const unsigned char *) TAG, strlen(TAG))) != 0) { ESP_LOGE(TAG, "failed! mbedtls_ctr_drbg_seed returned -0x%x", -ret); return NETWORK_MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED; } /* Load root CA... Certs/keys can be paths or they can be raw data. These use a very basic heuristic: if the cert starts with '/' then it's a path, if it's longer than this then it's raw cert data (PEM or DER, neither of which can start with a slash. */ if (pNetwork->tlsConnectParams.pRootCALocation[0] == '/') { ESP_LOGD(TAG, "Loading CA root certificate from file ..."); ret = mbedtls_x509_crt_parse_file(&(tlsDataParams->cacert), pNetwork->tlsConnectParams.pRootCALocation); } else { ESP_LOGD(TAG, "Loading embedded CA root certificate ..."); ret = mbedtls_x509_crt_parse(&(tlsDataParams->cacert), (const unsigned char *)pNetwork->tlsConnectParams.pRootCALocation, strlen(pNetwork->tlsConnectParams.pRootCALocation)+1); } if(ret < 0) { ESP_LOGE(TAG, "failed! mbedtls_x509_crt_parse returned -0x%x while parsing root cert", -ret); return NETWORK_X509_ROOT_CRT_PARSE_ERROR; } ESP_LOGD(TAG, "ok (%d skipped)", ret); /* Load client certificate... */ if (pNetwork->tlsConnectParams.pDeviceCertLocation[0] == '/') { ESP_LOGD(TAG, "Loading client cert from file..."); ret = mbedtls_x509_crt_parse_file(&(tlsDataParams->clicert), pNetwork->tlsConnectParams.pDeviceCertLocation); } else { ESP_LOGD(TAG, "Loading embedded client certificate..."); ret = mbedtls_x509_crt_parse(&(tlsDataParams->clicert), (const unsigned char *)pNetwork->tlsConnectParams.pDeviceCertLocation, strlen(pNetwork->tlsConnectParams.pDeviceCertLocation)+1); } if(ret != 0) { ESP_LOGE(TAG, "failed! mbedtls_x509_crt_parse returned -0x%x while parsing device cert", -ret); return NETWORK_X509_DEVICE_CRT_PARSE_ERROR; } /* Parse client private key... */ if (pNetwork->tlsConnectParams.pDevicePrivateKeyLocation[0] == '/') { ESP_LOGD(TAG, "Loading client private key from file..."); ret = mbedtls_pk_parse_keyfile(&(tlsDataParams->pkey), pNetwork->tlsConnectParams.pDevicePrivateKeyLocation, ""); } else { ESP_LOGD(TAG, "Loading embedded client private key..."); ret = mbedtls_pk_parse_key(&(tlsDataParams->pkey), (const unsigned char *)pNetwork->tlsConnectParams.pDevicePrivateKeyLocation, strlen(pNetwork->tlsConnectParams.pDevicePrivateKeyLocation)+1, (const unsigned char *)"", 0); } if(ret != 0) { ESP_LOGE(TAG, "failed! mbedtls_pk_parse_key returned -0x%x while parsing private key", -ret); return NETWORK_PK_PRIVATE_KEY_PARSE_ERROR; } /* Done parsing certs */ ESP_LOGD(TAG, "ok"); snprintf(portBuffer, 6, "%d", pNetwork->tlsConnectParams.DestinationPort); ESP_LOGD(TAG, "Connecting to %s/%s...", pNetwork->tlsConnectParams.pDestinationURL, portBuffer); if((ret = mbedtls_net_connect(&(tlsDataParams->server_fd), pNetwork->tlsConnectParams.pDestinationURL, portBuffer, MBEDTLS_NET_PROTO_TCP)) != 0) { ESP_LOGE(TAG, "failed! mbedtls_net_connect returned -0x%x", -ret); switch(ret) { case MBEDTLS_ERR_NET_SOCKET_FAILED: return NETWORK_ERR_NET_SOCKET_FAILED; case MBEDTLS_ERR_NET_UNKNOWN_HOST: return NETWORK_ERR_NET_UNKNOWN_HOST; case MBEDTLS_ERR_NET_CONNECT_FAILED: default: return NETWORK_ERR_NET_CONNECT_FAILED; }; } ret = mbedtls_net_set_block(&(tlsDataParams->server_fd)); if(ret != 0) { ESP_LOGE(TAG, "failed! net_set_(non)block() returned -0x%x", -ret); return SSL_CONNECTION_ERROR; } ESP_LOGD(TAG, "ok"); ESP_LOGD(TAG, "Setting up the SSL/TLS structure..."); if((ret = mbedtls_ssl_config_defaults(&(tlsDataParams->conf), MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { ESP_LOGE(TAG, "failed! mbedtls_ssl_config_defaults returned -0x%x", -ret); return SSL_CONNECTION_ERROR; } mbedtls_ssl_conf_verify(&(tlsDataParams->conf), _iot_tls_verify_cert, NULL); if(pNetwork->tlsConnectParams.ServerVerificationFlag == true) { mbedtls_ssl_conf_authmode(&(tlsDataParams->conf), MBEDTLS_SSL_VERIFY_REQUIRED); } else { mbedtls_ssl_conf_authmode(&(tlsDataParams->conf), MBEDTLS_SSL_VERIFY_OPTIONAL); } mbedtls_ssl_conf_rng(&(tlsDataParams->conf), mbedtls_ctr_drbg_random, &(tlsDataParams->ctr_drbg)); mbedtls_ssl_conf_ca_chain(&(tlsDataParams->conf), &(tlsDataParams->cacert), NULL); ret = mbedtls_ssl_conf_own_cert(&(tlsDataParams->conf), &(tlsDataParams->clicert), &(tlsDataParams->pkey)); if(ret != 0) { ESP_LOGE(TAG, "failed! mbedtls_ssl_conf_own_cert returned %d", ret); return SSL_CONNECTION_ERROR; } mbedtls_ssl_conf_read_timeout(&(tlsDataParams->conf), pNetwork->tlsConnectParams.timeout_ms); #ifdef CONFIG_MBEDTLS_SSL_ALPN /* Use the AWS IoT ALPN extension for MQTT, if port 443 is requested */ if (pNetwork->tlsConnectParams.DestinationPort == 443) { const char *alpnProtocols[] = { "x-amzn-mqtt-ca", NULL }; if ((ret = mbedtls_ssl_conf_alpn_protocols(&(tlsDataParams->conf), alpnProtocols)) != 0) { ESP_LOGE(TAG, "failed! mbedtls_ssl_conf_alpn_protocols returned -0x%x", -ret); return SSL_CONNECTION_ERROR; } } #endif if((ret = mbedtls_ssl_setup(&(tlsDataParams->ssl), &(tlsDataParams->conf))) != 0) { ESP_LOGE(TAG, "failed! mbedtls_ssl_setup returned -0x%x", -ret); return SSL_CONNECTION_ERROR; } if((ret = mbedtls_ssl_set_hostname(&(tlsDataParams->ssl), pNetwork->tlsConnectParams.pDestinationURL)) != 0) { ESP_LOGE(TAG, "failed! mbedtls_ssl_set_hostname returned %d", ret); return SSL_CONNECTION_ERROR; } ESP_LOGD(TAG, "SSL state connect : %d ", tlsDataParams->ssl.state); mbedtls_ssl_set_bio(&(tlsDataParams->ssl), &(tlsDataParams->server_fd), mbedtls_net_send, NULL, mbedtls_net_recv_timeout); ESP_LOGD(TAG, "ok"); ESP_LOGD(TAG, "SSL state connect : %d ", tlsDataParams->ssl.state); ESP_LOGD(TAG, "Performing the SSL/TLS handshake..."); while((ret = mbedtls_ssl_handshake(&(tlsDataParams->ssl))) != 0) { if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { ESP_LOGE(TAG, "failed! mbedtls_ssl_handshake returned -0x%x", -ret); if(ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) { ESP_LOGE(TAG, " Unable to verify the server's certificate. "); } return SSL_CONNECTION_ERROR; } } ESP_LOGD(TAG, "ok [ Protocol is %s ] [ Ciphersuite is %s ]", mbedtls_ssl_get_version(&(tlsDataParams->ssl)), mbedtls_ssl_get_ciphersuite(&(tlsDataParams->ssl))); if((ret = mbedtls_ssl_get_record_expansion(&(tlsDataParams->ssl))) >= 0) { ESP_LOGD(TAG, " [ Record expansion is %d ]", ret); } else { ESP_LOGD(TAG, " [ Record expansion is unknown (compression) ]"); } ESP_LOGD(TAG, "Verifying peer X.509 certificate..."); if(pNetwork->tlsConnectParams.ServerVerificationFlag == true) { if((tlsDataParams->flags = mbedtls_ssl_get_verify_result(&(tlsDataParams->ssl))) != 0) { ESP_LOGE(TAG, "failed"); mbedtls_x509_crt_verify_info(info_buf, sizeof(info_buf), " ! ", tlsDataParams->flags); ESP_LOGE(TAG, "%s", info_buf); ret = SSL_CONNECTION_ERROR; } else { ESP_LOGD(TAG, "ok"); ret = SUCCESS; } } else { ESP_LOGW(TAG, " Server Verification skipped"); ret = SUCCESS; } if(LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) { if (mbedtls_ssl_get_peer_cert(&(tlsDataParams->ssl)) != NULL) { ESP_LOGD(TAG, "Peer certificate information:"); mbedtls_x509_crt_info((char *) info_buf, sizeof(info_buf) - 1, " ", mbedtls_ssl_get_peer_cert(&(tlsDataParams->ssl))); ESP_LOGD(TAG, "%s", info_buf); } } return (IoT_Error_t) ret; }
void http_get_task(void *pvParameters) { int successes = 0, failures = 0, ret; printf("HTTP get task starting...\n"); uint32_t flags; unsigned char buf[1024]; const char *pers = "ssl_client1"; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_ssl_context ssl; mbedtls_x509_crt cacert; mbedtls_ssl_config conf; mbedtls_net_context server_fd; /* * 0. Initialize the RNG and the session data */ mbedtls_ssl_init(&ssl); mbedtls_x509_crt_init(&cacert); mbedtls_ctr_drbg_init(&ctr_drbg); printf("\n . Seeding the random number generator..."); mbedtls_ssl_config_init(&conf); mbedtls_entropy_init(&entropy); if((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) pers, strlen(pers))) != 0) { printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret); abort(); } printf(" ok\n"); /* * 0. Initialize certificates */ printf(" . Loading the CA root certificate ..."); ret = mbedtls_x509_crt_parse(&cacert, (uint8_t*)server_root_cert, strlen(server_root_cert)+1); if(ret < 0) { printf(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); abort(); } printf(" ok (%d skipped)\n", ret); /* Hostname set here should match CN in server certificate */ if((ret = mbedtls_ssl_set_hostname(&ssl, WEB_SERVER)) != 0) { printf(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret); abort(); } /* * 2. Setup stuff */ printf(" . Setting up the SSL/TLS structure..."); if((ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { printf(" failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret); goto exit; } printf(" ok\n"); /* OPTIONAL is not optimal for security, in this example it will print a warning if CA verification fails but it will continue to connect. */ mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL); mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL); mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); #ifdef MBEDTLS_DEBUG_C mbedtls_debug_set_threshold(DEBUG_LEVEL); mbedtls_ssl_conf_dbg(&conf, my_debug, stdout); #endif if((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) { printf(" failed\n ! mbedtls_ssl_setup returned %d\n\n", ret); goto exit; } /* Wait until we can resolve the DNS for the server, as an indication our network is probably working... */ printf("Waiting for server DNS to resolve... "); err_t dns_err; ip_addr_t host_ip; do { vTaskDelay(500 / portTICK_PERIOD_MS); dns_err = netconn_gethostbyname(WEB_SERVER, &host_ip); } while(dns_err != ERR_OK); printf("done.\n"); while(1) { mbedtls_net_init(&server_fd); printf("top of loop, free heap = %u\n", xPortGetFreeHeapSize()); /* * 1. Start the connection */ printf(" . Connecting to %s:%s...", WEB_SERVER, WEB_PORT); if((ret = mbedtls_net_connect(&server_fd, WEB_SERVER, WEB_PORT, MBEDTLS_NET_PROTO_TCP)) != 0) { printf(" failed\n ! mbedtls_net_connect returned %d\n\n", ret); goto exit; } printf(" ok\n"); mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL); /* * 4. Handshake */ printf(" . Performing the SSL/TLS handshake..."); while((ret = mbedtls_ssl_handshake(&ssl)) != 0) { if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { printf(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", -ret); goto exit; } } printf(" ok\n"); /* * 5. Verify the server certificate */ printf(" . Verifying peer X.509 certificate..."); /* In real life, we probably want to bail out when ret != 0 */ if((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) { char vrfy_buf[512]; printf(" failed\n"); mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags); printf("%s\n", vrfy_buf); } else printf(" ok\n"); /* * 3. Write the GET request */ printf(" > Write to server:"); int len = sprintf((char *) buf, GET_REQUEST); while((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0) { if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { printf(" failed\n ! mbedtls_ssl_write returned %d\n\n", ret); goto exit; } } len = ret; printf(" %d bytes written\n\n%s", len, (char *) buf); /* * 7. Read the HTTP response */ printf(" < Read from server:"); do { len = sizeof(buf) - 1; memset(buf, 0, sizeof(buf)); ret = mbedtls_ssl_read(&ssl, buf, len); if(ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) continue; if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { ret = 0; break; } if(ret < 0) { printf("failed\n ! mbedtls_ssl_read returned %d\n\n", ret); break; } if(ret == 0) { printf("\n\nEOF\n\n"); break; } len = ret; printf(" %d bytes read\n\n%s", len, (char *) buf); } while(1); mbedtls_ssl_close_notify(&ssl); exit: mbedtls_ssl_session_reset(&ssl); mbedtls_net_free(&server_fd); if(ret != 0) { char error_buf[100]; mbedtls_strerror(ret, error_buf, 100); printf("\n\nLast error was: %d - %s\n\n", ret, error_buf); failures++; } else { successes++; } printf("\n\nsuccesses = %d failures = %d\n", successes, failures); for(int countdown = successes ? 10 : 5; countdown >= 0; countdown--) { printf("%d... ", countdown); vTaskDelay(1000 / portTICK_PERIOD_MS); } printf("\nStarting again!\n"); } }
int main(int argc, char *argv[]) { int ret, exitcode; mbedtls_net_context server_fd; uint32_t flags; char scenario[10000] = ""; char server_host[100] = ""; char server_port[6] = ""; char server_ssl_hostname[100] = ""; const char *pers = "dtls_client"; int opt; struct timeval t0, t1; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_ssl_context ssl; mbedtls_ssl_config conf; mbedtls_x509_crt cacert; mbedtls_timing_delay_context timer; /* Parse command line */ while ((opt = getopt(argc, argv, "h:n:p:s:")) != -1) { switch (opt) { case 'h': strncpy(server_host, optarg, sizeof(server_host)); break; case 'n': strncpy(server_ssl_hostname, optarg, sizeof(server_ssl_hostname)); break; case 'p': strncpy(server_port, optarg, sizeof(server_port)); break; case 's': strncpy(scenario, optarg, sizeof(scenario)); break; default: /* '?' */ print_usage(argv[0]); } } if (!(scenario[0] && server_port[0] && server_host[0])) { print_usage(argv[0]); } if (!server_ssl_hostname[0]) { strncpy(server_ssl_hostname, server_host, sizeof(server_ssl_hostname)); } #if defined(MBEDTLS_DEBUG_C) mbedtls_debug_set_threshold(DEBUG_LEVEL); #endif /* * 0. Initialize the RNG and the session data */ mbedtls_net_init(&server_fd); mbedtls_ssl_init(&ssl); mbedtls_ssl_config_init(&conf); mbedtls_x509_crt_init(&cacert); mbedtls_ctr_drbg_init(&ctr_drbg); plog("Seeding the random number generator..."); mbedtls_entropy_init(&entropy); if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers))) != 0) { plog("ERROR: failed! mbedtls_ctr_drbg_seed returned %d", ret); goto exit; } /* * 0. Load certificates */ plog("Loading the CA root certificate ..."); ret = mbedtls_x509_crt_parse(&cacert, (const unsigned char *)mbedtls_test_cas_pem, mbedtls_test_cas_pem_len); if (ret < 0) { plog("ERROR: failed! mbedtls_x509_crt_parse returned -0x%x", -ret); goto exit; } plog("Connecting to udp %s:%s (SSL hostname: %s)...", server_host, server_port, server_ssl_hostname); if ((ret = mbedtls_net_connect(&server_fd, server_host, server_port, MBEDTLS_NET_PROTO_UDP)) != 0) { plog("ERROR: failed! mbedtls_net_connect returned %d", ret); goto exit; } plog("The local client UDP source port is %d", get_source_port(server_fd.fd)); plog("Setting up the DTLS structure..."); if ((ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { plog("ERROR: failed! mbedtls_ssl_config_defaults returned %d", ret); goto exit; } /* OPTIONAL is usually a bad choice for security, but makes interop easier * in this simplified example, in which the ca chain is hardcoded. * Production code should set a proper ca chain and use REQUIRED. */ mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL); mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL); mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); mbedtls_ssl_conf_dbg(&conf, log_mbedtls_debug_callback, NULL); /* TODO timeouts */ if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) { plog("ERROR: failed! mbedtls_ssl_setup returned %d", ret); goto exit; } if ((ret = mbedtls_ssl_set_hostname(&ssl, server_ssl_hostname)) != 0) { plog("ERROR: failed! mbedtls_ssl_set_hostname returned %d", ret); goto exit; } mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout); mbedtls_ssl_set_timer_cb(&ssl, &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay); plog("Performing the SSL/TLS handshake..."); gettimeofday(&t0, NULL); do { ret = mbedtls_ssl_handshake(&ssl); plog(" ... during SSL handshake, ret=%d (WANT_READ=%d, WANT_WRITE=%d, RECV_FAILED=%d", ret, MBEDTLS_ERR_SSL_WANT_READ, MBEDTLS_ERR_SSL_WANT_WRITE, MBEDTLS_ERR_NET_RECV_FAILED); gettimeofday(&t1, NULL); } while ((duration_ms(&t1, &t0) <= SSL_HANDSHAKE_TIMEOUT_MILLISECS) && (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)); plog("handshake duration: %d milliseconds", duration_ms(&t1, &t0)); if (duration_ms(&t1, &t0) > SSL_HANDSHAKE_TIMEOUT_MILLISECS) { plog("ERROR: long time to perform handshake: %d milliseconds", duration_ms(&t1, &t0)); ret = MBEDTLS_ERR_SSL_TIMEOUT; goto exit; } if (ret != 0) { plog("ERROR: failed! mbedtls_ssl_handshake returned -0x%x", -ret); goto exit; } plog("Verifying peer X.509 certificate..."); /* In real life, we would have used MBEDTLS_SSL_VERIFY_REQUIRED so that the * handshake would not succeed if the peer's cert is bad. Even if we used * MBEDTLS_SSL_VERIFY_OPTIONAL, we would bail out here if ret != 0 */ if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) { char vrfy_buf[512]; mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "! ", flags); plog("Verification failed: %s", vrfy_buf); } else { plog("Certificates ok"); } ret = run_scenario(scenario, &ssl); if (ret != 0) { goto exit; } plog("Closing the connection..."); /* No error checking, the connection might be closed already */ do { ret = mbedtls_ssl_close_notify(&ssl); } while (ret == MBEDTLS_ERR_SSL_WANT_WRITE); ret = 0; exit: #ifdef MBEDTLS_ERROR_C if (ret != 0) { char error_buf[100]; mbedtls_strerror(ret, error_buf, 100); plog("ERROR: Last error was: %d - %s", ret, error_buf); } #endif mbedtls_net_free(&server_fd); mbedtls_x509_crt_free(&cacert); mbedtls_ssl_free(&ssl); mbedtls_ssl_config_free(&conf); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); exitcode = ret == 0 ? 0 : 1; plog("Done, exitcode=%d", exitcode); return exitcode; }
int iot_tls_connect(Network *pNetwork, TLSConnectParams params) { const char *pers = "aws_iot_tls_wrapper"; unsigned char buf[MBEDTLS_SSL_MAX_CONTENT_LEN + 1]; DEBUG(" . Loading the CA root certificate ..."); ret = mbedtls_x509_crt_parse_file(&cacert, params.pRootCALocation); if (ret < 0) { ERROR(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); return ret; } DEBUG(" ok (%d skipped)\n", ret); DEBUG(" . Loading the client cert. and key..."); ret = mbedtls_x509_crt_parse_file(&clicert, params.pDeviceCertLocation); if (ret != 0) { ERROR(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); return ret; } ret = mbedtls_pk_parse_keyfile(&pkey, params.pDevicePrivateKeyLocation, ""); if (ret != 0) { ERROR(" failed\n ! mbedtls_pk_parse_key returned -0x%x\n\n", -ret); return ret; } DEBUG(" ok\n"); char portBuffer[6]; sprintf(portBuffer, "%d", params.DestinationPort); DEBUG(" . Connecting to %s/%s...", params.pDestinationURL, portBuffer); if ((ret = mbedtls_net_connect(&server_fd, params.pDestinationURL, portBuffer, MBEDTLS_NET_PROTO_TCP)) != 0) { ERROR(" failed\n ! mbedtls_net_connect returned -0x%x\n\n", -ret); return ret; } ret = mbedtls_net_set_block(&server_fd); if (ret != 0) { ERROR(" failed\n ! net_set_(non)block() returned -0x%x\n\n", -ret); return ret; } DEBUG(" ok\n"); DEBUG(" . Setting up the SSL/TLS structure..."); if ((ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { ERROR(" failed\n ! mbedtls_ssl_config_defaults returned -0x%x\n\n", -ret); return ret; } mbedtls_ssl_conf_verify(&conf, myCertVerify, NULL); if (params.ServerVerificationFlag == true) { mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED); } else { mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL); } mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL); if ((ret = mbedtls_ssl_conf_own_cert(&conf, &clicert, &pkey)) != 0) { ERROR(" failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret); return ret; } mbedtls_ssl_conf_read_timeout(&conf, params.timeout_ms); if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) { ERROR(" failed\n ! mbedtls_ssl_setup returned -0x%x\n\n", -ret); return ret; } if ((ret = mbedtls_ssl_set_hostname(&ssl, params.pDestinationURL)) != 0) { ERROR(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret); return ret; } mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, NULL, mbedtls_net_recv_timeout); DEBUG(" ok\n"); DEBUG(" . Performing the SSL/TLS handshake..."); while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { ERROR(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n", -ret); if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) { ERROR(" Unable to verify the server's certificate. " "Either it is invalid,\n" " or you didn't set ca_file or ca_path " "to an appropriate value.\n" " Alternatively, you may want to use " "auth_mode=optional for testing purposes.\n"); } return ret; } } DEBUG(" ok\n [ Protocol is %s ]\n [ Ciphersuite is %s ]\n", mbedtls_ssl_get_version(&ssl), mbedtls_ssl_get_ciphersuite(&ssl)); if ((ret = mbedtls_ssl_get_record_expansion(&ssl)) >= 0) { DEBUG(" [ Record expansion is %d ]\n", ret); } else { DEBUG(" [ Record expansion is unknown (compression) ]\n"); } DEBUG(" . Verifying peer X.509 certificate..."); if (params.ServerVerificationFlag == true) { if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) { char vrfy_buf[512]; ERROR(" failed\n"); mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags); ERROR("%s\n", vrfy_buf); } else { DEBUG(" ok\n"); ret = NONE_ERROR; } } else { DEBUG(" Server Verification skipped\n"); ret = NONE_ERROR; } if (mbedtls_ssl_get_peer_cert(&ssl) != NULL) { DEBUG(" . Peer certificate information ...\n"); mbedtls_x509_crt_info((char *) buf, sizeof(buf) - 1, " ", mbedtls_ssl_get_peer_cert(&ssl)); DEBUG("%s\n", buf); } mbedtls_ssl_conf_read_timeout(&conf, 10); return ret; }