static void session_step_handshake(EV_P_ ev_io *w, int revents, session_context *sc) { int ret = mbedtls_ssl_handshake(&sc->ssl); char error[128] = {0}; (void)w; (void)revents; switch (ret) { case MBEDTLS_ERR_SSL_WANT_READ: case MBEDTLS_ERR_SSL_WANT_WRITE: case MBEDTLS_ERR_NET_RECV_FAILED: mbedtls_strerror(ret, error, 128); log_debug("mbedtls handshake return %s", error); session_mark_activity(EV_A_ sc); return; case 0: log_debug("(%s:%d) DTLS handshake done", sc->options->backend_host, sc->options->backend_port); session_mark_activity(EV_A_ sc); #if 0 if (connect_to_backend(EV_A_ sc) != 0) { return session_deferred_free_after_error(sc, ret, "session_step_send_backend"); } #endif sc->step = GOLDY_SESSION_STEP_OPERATIONAL; session_enable_client_rxtx(EV_A_ sc); return; case MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED: log_debug("(%s:%d) DTLS handshake requested hello verification", sc->options->backend_host, sc->options->backend_port); session_deferred_free(sc, "hello verification"); return; default: mbedtls_strerror(ret, error, 128); log_debug("unknow mbedtls error %s", error); return session_deferred_free_after_error(sc, ret, "session_cb - ssl handshake"); } }
static unsigned int _DTLSContext_setup(dtls_session_t *p_dtls_session, coap_dtls_options_t *p_options) { int result = 0; mbedtls_ssl_init(&p_dtls_session->context); result = mbedtls_ssl_setup(&p_dtls_session->context, &p_dtls_session->conf); DTLS_TRC("mbedtls_ssl_setup result 0x%04x\r\n", result); if (result == 0) { if (p_dtls_session->conf.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) { mbedtls_ssl_set_timer_cb(&p_dtls_session->context, (void *)&p_dtls_session->timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay); } #ifdef MBEDTLS_X509_CRT_PARSE_C DTLS_TRC("mbedtls_ssl_set_hostname %s\r\n", p_options->p_host); mbedtls_ssl_set_hostname(&p_dtls_session->context, p_options->p_host); #endif mbedtls_ssl_set_bio(&p_dtls_session->context, (void *)&p_dtls_session->fd, mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout); DTLS_TRC("mbedtls_ssl_set_bio result 0x%04x\r\n", result); do { result = mbedtls_ssl_handshake(&p_dtls_session->context); } while (result == MBEDTLS_ERR_SSL_WANT_READ || result == MBEDTLS_ERR_SSL_WANT_WRITE); DTLS_TRC("mbedtls_ssl_handshake result 0x%04x\r\n", result); } return (result ? DTLS_HANDSHAKE_FAILED : DTLS_SUCCESS); }
/* Connect to remote server via TLS */ int tls_connect(mbedtls_ssl_context *context, int *sock, char *hostname) { if (mbedtls_ctr_drbg_reseed(&ctr_drbg, (const unsigned char*)"Reverse Proxy", 13) != 0) { return -1; } mbedtls_ssl_init(context); if (mbedtls_ssl_setup(context, &client_config) != 0) { return -1; } mbedtls_ssl_set_bio(context, sock, mbedtls_net_send, mbedtls_net_recv, NULL); if (hostname != NULL) { mbedtls_ssl_set_hostname(context, hostname); } if (mbedtls_ssl_handshake(context) != 0) { mbedtls_ssl_free(context); return TLS_HANDSHAKE_ERROR; } return TLS_HANDSHAKE_OKE; }
int _ssl_accept(nsp_state *N, TCP_SOCKET *bsock, TCP_SOCKET *asock) { #define __FN__ __FILE__ ":_ssl_accept()" #if defined HAVE_OPENSSL if ((asock->ssl = SSL_new(bsock->ssl_ctx)) == NULL) { return -1; } /* SSL_clear(asock->ssl); */ SSL_set_fd(asock->ssl, asock->socket); if (SSL_accept(asock->ssl) == -1) { return -1; } return 0; #elif defined HAVE_MBEDTLS int rc; asock->net_context.fd = asock->socket; mbedtls_ssl_init(&asock->ssl); if ((rc = mbedtls_ssl_setup(&asock->ssl, &bsock->conf)) != 0) { print_mbedtls_error(N, __FN__, rc); return -1; } //mbedtls_ssl_session_reset(&asock->ssl); mbedtls_ssl_set_bio(&asock->ssl, &asock->net_context, mbedtls_net_send, mbedtls_net_recv, NULL); if ((rc = mbedtls_ssl_handshake(&asock->ssl)) < 0) { if (rc == MBEDTLS_ERR_SSL_WANT_READ || rc == MBEDTLS_ERR_SSL_WANT_WRITE) { print_mbedtls_error(N, __FN__, rc); } else { print_mbedtls_error(N, __FN__, rc); } } return rc; #endif #undef __FN__ }
int SSLContext::handshake(State & state, SSLContextData * ssl_context_data) { Stack * stack = state.stack; stack->push<int>(mbedtls_ssl_handshake(ssl_context_data->context)); return 1; }
/* "tcps://host:port" "tcps://:port" "udps://host:port" "udps://:port" */ static int ssl_open( UThread* ut, const UPortDevice* pdev, const UCell* from, int opt, UCell* res ) { NodeServ ns; SSLExt* ext; int ok; //int nowait = opt & UR_PORT_NOWAIT; mbedtls_net_context* nc; mbedtls_ssl_context* sc; mbedtls_ssl_config* conf; const char* pers = "ssl_client1"; (void) opt; if( ! ur_is(from, UT_STRING) ) return ur_error( ut, UR_ERR_TYPE, "socket open expected string" ); ext = (SSLExt*) memAlloc( sizeof(SSLExt) ); ext->se.addrlen = 0; #ifdef _WIN32 ext->se.event = WSA_INVALID_EVENT; #endif //if( ur_is(from, UT_STRING) ) { stringToNodeServ( ut, from, &ns ); if( ! makeSockAddr( ut, &ext->se, &ns ) ) goto fail; } if( ! ns.service ) { ur_error( ut, UR_ERR_SCRIPT, "Socket port requires hostname and/or port" ); goto fail; } if( ! boron_requestAccess( ut, "Open socket %s", ns.service ) ) goto fail; ssl_init( ext ); nc = &ext->nc; sc = &ext->sc; conf = &ext->conf; ok = mbedtls_ctr_drbg_seed( &ext->ctr_drbg, mbedtls_entropy_func, &ext->entropy, (const unsigned char*) pers, strlen(pers) ); if( ok != 0 ) { ssl_error( ut, "mbedtls_ctr_drbg_seed", ok ); goto failSSL; } ok = mbedtls_net_connect( nc, ns.node, ns.service, (ns.socktype == SOCK_DGRAM) ? MBEDTLS_NET_PROTO_UDP : MBEDTLS_NET_PROTO_TCP ); if( ok != 0 ) { ssl_error( ut, "mbedtls_net_connect", ok ); goto failSSL; } ok = mbedtls_ssl_config_defaults( conf, MBEDTLS_SSL_IS_CLIENT, (ns.socktype == SOCK_DGRAM) ? MBEDTLS_SSL_TRANSPORT_DATAGRAM : MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT ); if( ok != 0 ) { ssl_error( ut, "mbedtls_ssl_config_defaults", ok ); goto failSSL; } mbedtls_ssl_conf_authmode( conf, MBEDTLS_SSL_VERIFY_NONE ); //mbedtls_ssl_conf_ca_chain( conf, cacert, NULL ); mbedtls_ssl_conf_rng( conf, mbedtls_ctr_drbg_random, &ext->ctr_drbg ); mbedtls_ssl_conf_dbg( conf, ssl_debug, stdout ); ok = mbedtls_ssl_setup( sc, conf ); if( ok != 0 ) { ssl_error( ut, "mbedtls_ssl_setup", ok ); goto failSSL; } ok = mbedtls_ssl_set_hostname( sc, "Boron TLS Server 1" ); if( ok != 0 ) { ssl_error( ut, "mbedtls_ssl_set_hostname", ok ); goto failSSL; } mbedtls_ssl_set_bio( sc, nc, mbedtls_net_send, mbedtls_net_recv, NULL ); while( (ok = mbedtls_ssl_handshake( sc )) != 0 ) { if( ok != MBEDTLS_ERR_SSL_WANT_READ && ok != MBEDTLS_ERR_SSL_WANT_WRITE ) { ssl_error( ut, "mbedtls_ssl_handshake", ok ); goto failSSL; } } { UBuffer* pbuf; pbuf = boron_makePort( ut, pdev, ext, res ); pbuf->TCP = (ns.socktype == SOCK_STREAM) ? 1 : 0; pbuf->FD = nc->fd; //printf( "KR socket_open %d %d\n", pbuf->FD, pbuf->TCP ); } return UR_OK; failSSL: ssl_free( ext ); fail: memFree( ext ); return UR_THROW; }
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 main( void ) { int ret, len, written; mbedtls_net_context server_fd; unsigned char buf[1024]; const char *pers = "pinning_client"; /* XXX create some state for our verify callback */ struct vrfy_state vrfy_state = { .pins = pins, }; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_ssl_context ssl; mbedtls_ssl_config conf; mbedtls_x509_crt cacert; /* Ensure valid memory references */ 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_entropy_init( &entropy ); /* * 0. Initialize the RNG and the session data */ mbedtls_printf( "\n . Seeding the random number generator..." ); fflush( stdout ); 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" ); /* * 1. 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 ); /* * 2. Start the TCP connection */ 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; } mbedtls_printf( " ok\n" ); /* * 3. Setup SSL/TSL stuff */ mbedtls_printf( " . Setting up the SSL/TLS structure..." ); fflush( stdout ); if( ( ret = mbedtls_ssl_config_defaults( &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 defined(MBEDTLS_DEBUG_C) mbedtls_debug_set_threshold( DEBUG_LEVEL ); #endif 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 ); /* XXX: register our certificate verification callback */ mbedtls_ssl_conf_verify( &conf, my_verify, &vrfy_state ); 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, NULL ); mbedtls_printf( " ok\n" ); /* * 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 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", -ret ); goto exit; } } mbedtls_printf( " ok\n" ); /* * 5. Write request */ mbedtls_printf( " > Write to server:" ); fflush( stdout ); len = snprintf( (char *) buf, sizeof( buf ), GET_REQUEST ); if( len < 0 || (size_t) len > sizeof( buf ) ) { mbedtls_printf( " failed\n ! buffer too small for request\n\n" ); goto exit; } for( written = 0; written < len; written += ret ) { while( ( ret = mbedtls_ssl_write( &ssl, buf + written, len - written ) ) <= 0 ) { if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) { mbedtls_printf( " failed\n ! mbedtls_ssl_write returned -0x%x\n\n", -ret ); goto exit; } } } mbedtls_printf( " %d bytes written\n\n%s", written, (char *) buf ); /* * 6. Read the HTTP response */ mbedtls_printf( " < Read from server:" ); fflush( stdout ); 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 <= 0 ) { switch( ret ) { case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: mbedtls_printf( " connection was closed gracefully\n" ); ret = 0; goto close_notify; case 0: case MBEDTLS_ERR_NET_CONN_RESET: mbedtls_printf( " connection was reset by peer\n" ); ret = 0; goto exit; default: mbedtls_printf( " mbedtls_ssl_read returned -0x%x\n", -ret ); goto exit; } } len = ret; buf[len] = '\0'; mbedtls_printf( " %d bytes read\n\n%s", len, (char *) buf ); /* End of message should be detected according to the syntax of the * application protocol (eg HTTP), just use a dummy test here. */ if( ret > 0 && buf[len-1] == '\n' ) { ret = 0; break; } } while( 1 ); /* * 8. Done, cleanly close the connection */ close_notify: mbedtls_printf( " . Closing the connection..." ); fflush( stdout ); /* 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" ); 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 return( ret != 0 ); }
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: { int ret = mbedtls_ssl_handshake(&CWII_IPC_HLE_Device_net_ssl::_SSL[sslID].ctx); 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; default: Memory::Write_U32(SSL_ERR_FAILED, BufferIn); break; } 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); #ifdef DEBUG_SSL File::IOFile("ssl_write.bin", "ab").WriteBytes(Memory::GetPointer(BufferOut2), BufferOutSize2); #endif 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); #ifdef DEBUG_SSL if (ret > 0) { File::IOFile("ssl_read.bin", "ab").WriteBytes(Memory::GetPointer(BufferIn2), ret); } #endif 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); INFO_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); WiiSockMan::EnqueueReply(it->_CommandAddress, ReturnValue, ct); it = pending_sockops.erase(it); } else { ++it; } }
void clax_loop_ssl(clax_ctx_t *clax_ctx) { int ret = 0; char pers[] = "clax_server"; #ifdef MVS clax_etoa(pers, strlen(pers)); #endif mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_ssl_context ssl; mbedtls_ssl_config conf; mbedtls_x509_crt srvcert; mbedtls_pk_context pkey; mbedtls_ssl_cache_context cache; mbedtls_ssl_init(&ssl); mbedtls_ssl_config_init(&conf); mbedtls_ssl_cache_init(&cache); mbedtls_x509_crt_init(&srvcert); mbedtls_pk_init(&pkey); mbedtls_entropy_init(&entropy); mbedtls_ctr_drbg_init(&ctr_drbg); #if defined(MBEDTLS_DEBUG_C) mbedtls_debug_set_threshold(DEBUG_LEVEL); #endif clax_log("Loading the server cert and key..."); unsigned char *file = NULL; size_t file_len = 0; clax_log("Loading '%s'...", options.cert_file); file = clax_slurp_alloc(options.cert_file, &file_len); if (file == NULL) { clax_log("Can't load cert_file '%s': %s", options.cert_file, strerror(errno)); goto exit; } #ifdef MVS clax_etoa((char *)file, file_len); #endif clax_log("Parsing '%s'...", options.cert_file); ret = mbedtls_x509_crt_parse(&srvcert, (const unsigned char *)file, file_len); free(file); if (ret != 0) { clax_log("failed\n ! mbedtls_x509_crt_parse returned %d", ret); goto exit; } clax_log("Loading '%s'...", options.key_file); file = clax_slurp_alloc(options.key_file, &file_len); if (file == NULL) { clax_log("Can't load key_file: %s", options.key_file); goto exit; } #ifdef MVS clax_etoa((char *)file, file_len); #endif clax_log("Parsing '%s'...", options.key_file); ret = mbedtls_pk_parse_key(&pkey, (const unsigned char *)file, file_len, NULL, 0); free(file); if (ret != 0) { clax_log("failed\n ! mbedtls_pk_parse_key returned %d", ret); goto exit; } clax_log("ok"); if (options.entropy_file[0]) { clax_log("Using '%s' as entropy file...", options.entropy_file); if ((ret = mbedtls_entropy_add_source(&entropy, dev_random_entropy_poll, NULL, DEV_RANDOM_THRESHOLD, MBEDTLS_ENTROPY_SOURCE_STRONG)) != 0) { clax_log("failed\n ! mbedtls_entropy_add_source returned -0x%04x", -ret); goto exit; } clax_log("ok"); } clax_log("Seeding the random number generator..."); if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers))) != 0) { clax_log("failed\n ! mbedtls_ctr_drbg_seed returned %d", ret); goto exit; } clax_log("ok"); clax_log("Setting up the SSL data...."); if ((ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { clax_log("failed\n ! mbedtls_ssl_config_defaults returned %d", ret); goto exit; } if (!options.no_ssl_verify) { mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED); } mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); mbedtls_ssl_conf_session_cache(&conf, &cache, mbedtls_ssl_cache_get, mbedtls_ssl_cache_set); mbedtls_ssl_conf_ca_chain(&conf, srvcert.next, NULL); if ((ret = mbedtls_ssl_conf_own_cert(&conf, &srvcert, &pkey)) != 0) { clax_log(" failed\n ! mbedtls_ssl_conf_own_cert returned %d", ret); goto exit; } if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) { clax_log(" failed\n ! mbedtls_ssl_setup returned %d", ret); goto exit; } clax_log("ok"); mbedtls_ssl_session_reset(&ssl); mbedtls_ssl_set_bio(&ssl, NULL, clax_send, clax_recv, NULL); clax_log("ok"); clax_log("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) { clax_log("failed\n ! mbedtls_ssl_handshake returned %d", ret); goto exit; } } clax_log("ok"); clax_http_dispatch(clax_ctx, clax_send_ssl, clax_recv_ssl, &ssl); clax_log("Closing the connection..."); while ((ret = mbedtls_ssl_close_notify(&ssl)) < 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { clax_log("failed\n ! mbedtls_ssl_close_notify returned %d", ret); goto exit; } } clax_log("ok"); ret = 0; goto exit; exit: fflush(stdout); #ifdef MBEDTLS_ERROR_C if (ret != 0) { char error_buf[100]; mbedtls_strerror(ret, error_buf, 100); #ifdef MVS clax_atoe(error_buf, strlen(error_buf)); #endif clax_log("Last error was: %d - %s", ret, error_buf); } #endif mbedtls_x509_crt_free(&srvcert); mbedtls_pk_free(&pkey); mbedtls_ssl_free(&ssl); mbedtls_ssl_config_free(&conf); mbedtls_ssl_cache_free(&cache); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); }
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 Dtls::Process(void) { uint8_t buf[MBEDTLS_SSL_MAX_CONTENT_LEN]; bool shouldDisconnect = false; int rval; while ((mState == kStateConnecting) || (mState == kStateConnected)) { if (mState == kStateConnecting) { rval = mbedtls_ssl_handshake(&mSsl); if (mSsl.state == MBEDTLS_SSL_HANDSHAKE_OVER) { mState = kStateConnected; if (mConnectedHandler != NULL) { mConnectedHandler(mContext, true); } } } else { rval = mbedtls_ssl_read(&mSsl, buf, sizeof(buf)); } if (rval > 0) { mReceiveHandler(mContext, buf, static_cast<uint16_t>(rval)); } else if (rval == 0 || rval == MBEDTLS_ERR_SSL_WANT_READ || rval == MBEDTLS_ERR_SSL_WANT_WRITE) { break; } else { switch (rval) { case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: mbedtls_ssl_close_notify(&mSsl); ExitNow(shouldDisconnect = true); break; case MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED: break; case MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE: mbedtls_ssl_close_notify(&mSsl); ExitNow(shouldDisconnect = true); break; case MBEDTLS_ERR_SSL_INVALID_MAC: if (mSsl.state != MBEDTLS_SSL_HANDSHAKE_OVER) { mbedtls_ssl_send_alert_message(&mSsl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC); ExitNow(shouldDisconnect = true); } break; default: if (mSsl.state != MBEDTLS_SSL_HANDSHAKE_OVER) { mbedtls_ssl_send_alert_message(&mSsl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE); ExitNow(shouldDisconnect = true); } break; } mbedtls_ssl_session_reset(&mSsl); if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8) { mbedtls_ssl_set_hs_ecjpake_password(&mSsl, mPsk, mPskLength); } break; } } exit: if (shouldDisconnect) { Disconnect(); } }
void dtls_client(void) { int ret = exit_ok; struct udp_context ctx; struct dtls_timing_context timer; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_ssl_context ssl; mbedtls_ssl_config conf; mbedtls_ctr_drbg_init(&ctr_drbg); mbedtls_platform_set_printf(printf); /* * 0. Initialize and setup stuff */ mbedtls_ssl_init(&ssl); mbedtls_ssl_config_init(&conf); mbedtls_printf("\n . Seeding the random number generator..."); mbedtls_entropy_init(&entropy); mbedtls_entropy_add_source(&entropy, entropy_source, NULL, MBEDTLS_ENTROPY_MAX_GATHER, MBEDTLS_ENTROPY_SOURCE_STRONG); if (mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers)) != 0) { ret = ctr_drbg_seed_failed; mbedtls_printf (" failed\n ! mbedtls_ctr_drbg_seed returned 0x%x\n", ret); goto exit; } mbedtls_printf(" ok\n"); mbedtls_printf(" . Setting up the DTLS structure..."); ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT); if (ret != 0) { ret = ssl_config_defaults_failed; mbedtls_printf(" failed! returned 0x%x\n\n", ret); goto exit; } /* Modify this to change the default timeouts for the DTSL handshake */ /* mbedtls_ssl_conf_handshake_timeout( &conf, min, max ); */ #if defined(MBEDTLS_DEBUG_C) mbedtls_debug_set_threshold(DEBUG_THRESHOLD); #endif mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); mbedtls_ssl_conf_dbg(&conf, my_debug, NULL); #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) mbedtls_memory_buffer_alloc_init(heap, sizeof(heap)); #endif if (mbedtls_ssl_setup(&ssl, &conf) != 0) { ret = ssl_setup_failed; mbedtls_printf (" failed\n ! mbedtls_ssl_setup returned 0x%x\n\n", ret); goto exit; } mbedtls_printf(" ok\n"); /* * 1. Start the connection */ mbedtls_printf(" . Connecting to udp %d.%d.%d.%d:%d...", SERVER_IPADDR0, SERVER_IPADDR1, SERVER_IPADDR2, SERVER_IPADDR3, SERVER_PORT); if (udp_init(&ctx) != 0) { ret = connect_failed; mbedtls_printf(" failed\n ! udp_init returned 0x%x\n\n", ret); goto exit; } mbedtls_printf(" ok\n"); #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) mbedtls_printf(" . Setting up ecjpake password ..."); if (mbedtls_ssl_set_hs_ecjpake_password (&ssl, ecjpake_pw, ECJPAKE_PW_SIZE) != 0) { mbedtls_printf(" failed! set ecjpake password returned %d\n\n", ssl_setup_failed); goto exit; } #endif mbedtls_printf(" ok\n"); mbedtls_ssl_set_timer_cb(&ssl, &timer, dtls_timing_set_delay, dtls_timing_get_delay); mbedtls_ssl_set_bio(&ssl, &ctx, udp_tx, udp_rx, NULL); mbedtls_printf(" . Performing the SSL/TLS handshake..."); ret = mbedtls_ssl_handshake(&ssl); if (ret != 0) { ret = ssl_handshake_failed; mbedtls_printf (" failed\n ! mbedtls_ssl_handshake returned 0x%x\n", ret); goto exit; } mbedtls_printf(" ok\n"); /* * 2. Write the GET request and close the connection */ mbedtls_printf(" > Write to server:"); if (mbedtls_ssl_write(&ssl, (const unsigned char *)GET_REQUEST, sizeof(GET_REQUEST) - 1) <= 0) { ret = ssl_write_failed; mbedtls_printf (" failed\n ! mbedtls_ssl_write returned 0x%x\n\n", ret); goto exit; } mbedtls_printf(" ok\n"); mbedtls_printf(" . Closing the connection..."); mbedtls_ssl_close_notify(&ssl); mbedtls_printf(" done\n"); exit: mbedtls_ssl_free(&ssl); mbedtls_ssl_config_free(&conf); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); }
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 conn_link_open(struct conn_link_s *link, int *sock, bool use_ssl, uint32_t recv_timeout_ms, uint32_t send_timeout_ms) { DEBUGASSERT(link->sock < 0); #ifdef CONFIG_THINGSEE_HTTPS_PROTOCOL DEBUGASSERT(link->ssl == NULL); #ifdef CONFIG_MBEDTLS DEBUGASSERT(link->net.fd < 0); #endif #endif link->send_timeout_ms = send_timeout_ms; link->recv_timeout_ms = recv_timeout_ms; if (!use_ssl) { link->sock = *sock; *sock = -1; return OK; } else { #ifdef CONFIG_THINGSEE_HTTPS_PROTOCOL #ifdef CONFIG_MBEDTLS int ret; struct timeval tv; if (!g_https_data.initialized) { con_dbg_save_pos(); if (conn_link_mbedtls_initialize() < 0) return ERROR; } mbedtls_ssl_conf_read_timeout(&g_https_data.mbedtls->conf, link->recv_timeout_ms); /* Set up a send timeout */ tv.tv_sec = link->send_timeout_ms / 1000; tv.tv_usec = (link->send_timeout_ms % 1000) * 1000; ret = setsockopt(*sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval)); if (ret < 0) { con_dbg("Setting SO_SNDTIMEO failed, errno: %d\n", errno); /* Return here. Socket is more than likely broken */ return ERROR; } else { http_con_dbg("SO_SNDTIMEO := %d msecs\n", link->send_timeout_ms); } /* Set up a receive timeout */ tv.tv_sec = link->recv_timeout_ms / 1000; tv.tv_usec = (link->recv_timeout_ms % 1000) * 1000; ret = setsockopt(*sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)); if (ret < 0) { con_dbg("Setting SO_RCVTIMEO failed, errno: %d\n", errno); /* Return if ERROR occurred */ return ERROR; } else { http_con_dbg("SO_RCVTIMEO := %d msecs\n", link->recv_timeout_ms); } con_dbg_save_pos(); link->ssl = malloc(sizeof(*link->ssl)); if (!link->ssl) return -1; mbedtls_ssl_init(link->ssl); ret = mbedtls_ssl_setup(link->ssl, &g_https_data.mbedtls->conf); if (ret != 0) { con_dbg("mbedtls_ssl_setup error: -0x%x\n", -ret); goto err_close_tls; } link->net.fd = *sock; link->sock = link->net.fd; *sock = -1; ret = mbedtls_ssl_set_session(link->ssl, &g_https_data.mbedtls->saved_session); if (ret != 0) { con_dbg( "mbedtls_ssl_set_session error: -0x%x\n\n", -ret); } mbedtls_ssl_set_bio(link->ssl, &link->net, mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout); ret = mbedtls_ssl_handshake(link->ssl); if (ret != 0) { int lowlevel_err = -(-ret & 0x007F); int highlevel_err = -(-ret & 0x7F80); con_dbg("mbedtls_ssl_handshake error: -0x%x\n", -ret); /* Check out-of-memory cases. If we have run out memory or memory * has become too fragmented, device will be stuck in bad state. * In this case, it will be better to reset. * TODO: Should we add controlled reset? */ DEBUGASSERT(lowlevel_err != MBEDTLS_ERR_MPI_ALLOC_FAILED); DEBUGASSERT(lowlevel_err != MBEDTLS_ERR_ASN1_ALLOC_FAILED); DEBUGASSERT(highlevel_err != MBEDTLS_ERR_X509_ALLOC_FAILED); DEBUGASSERT(highlevel_err != MBEDTLS_ERR_DHM_ALLOC_FAILED); DEBUGASSERT(highlevel_err != MBEDTLS_ERR_PK_ALLOC_FAILED); DEBUGASSERT(highlevel_err != MBEDTLS_ERR_ECP_ALLOC_FAILED); DEBUGASSERT(highlevel_err != MBEDTLS_ERR_CIPHER_ALLOC_FAILED); DEBUGASSERT(highlevel_err != MBEDTLS_ERR_SSL_ALLOC_FAILED); goto err_close_tls; } con_dbg("%c[38;5;%d48;5;%dm" "HTTPS: TLS version is '%s'." "%c[0m\n", 0x1B, 0, 1, mbedtls_ssl_get_version(link->ssl), 0x1B); con_dbg("%c[38;5;%d48;5;%dm" "HTTPS: TLS cipher suite is '%s'." "%c[0m\n", 0x1B, 0, 1, mbedtls_ssl_get_ciphersuite(link->ssl), 0x1B); ret = mbedtls_ssl_get_session(link->ssl, &g_https_data.mbedtls->saved_session); if (ret != 0) { con_dbg( "mbedtls_ssl_get_session error: -0x%x\n\n", -ret); } return OK; err_close_tls: con_dbg_save_pos(); mbedtls_ssl_free(link->ssl); free(link->ssl); link->ssl = NULL; return ERROR; #endif #endif return ERROR; } }
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; }
static void *handle_ssl_connection( void *data ) { int ret, len; thread_info_t *thread_info = (thread_info_t *) data; mbedtls_net_context *client_fd = &thread_info->client_fd; long int thread_id = (long int) pthread_self(); unsigned char buf[1024]; mbedtls_ssl_context ssl; /* Make sure memory references are valid */ mbedtls_ssl_init( &ssl ); mbedtls_printf( " [ #%ld ] Setting up SSL/TLS data\n", thread_id ); /* * 4. Get the SSL context ready */ if( ( ret = mbedtls_ssl_setup( &ssl, thread_info->config ) ) != 0 ) { mbedtls_printf( " [ #%ld ] failed: mbedtls_ssl_setup returned -0x%04x\n", thread_id, -ret ); goto thread_exit; } mbedtls_ssl_set_bio( &ssl, client_fd, mbedtls_net_send, mbedtls_net_recv, NULL ); /* * 5. Handshake */ mbedtls_printf( " [ #%ld ] Performing the SSL/TLS handshake\n", thread_id ); while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 ) { if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) { mbedtls_printf( " [ #%ld ] failed: mbedtls_ssl_handshake returned -0x%04x\n", thread_id, -ret ); goto thread_exit; } } mbedtls_printf( " [ #%ld ] ok\n", thread_id ); /* * 6. Read the HTTP Request */ mbedtls_printf( " [ #%ld ] < Read from client\n", thread_id ); 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 <= 0 ) { switch( ret ) { case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: mbedtls_printf( " [ #%ld ] connection was closed gracefully\n", thread_id ); goto thread_exit; case MBEDTLS_ERR_NET_CONN_RESET: mbedtls_printf( " [ #%ld ] connection was reset by peer\n", thread_id ); goto thread_exit; default: mbedtls_printf( " [ #%ld ] mbedtls_ssl_read returned -0x%04x\n", thread_id, -ret ); goto thread_exit; } } len = ret; mbedtls_printf( " [ #%ld ] %d bytes read\n=====\n%s\n=====\n", thread_id, len, (char *) buf ); if( ret > 0 ) break; } while( 1 ); /* * 7. Write the 200 Response */ mbedtls_printf( " [ #%ld ] > Write to client:\n", thread_id ); len = sprintf( (char *) buf, HTTP_RESPONSE, mbedtls_ssl_get_ciphersuite( &ssl ) ); while( ( ret = mbedtls_ssl_write( &ssl, buf, len ) ) <= 0 ) { if( ret == MBEDTLS_ERR_NET_CONN_RESET ) { mbedtls_printf( " [ #%ld ] failed: peer closed the connection\n", thread_id ); goto thread_exit; } if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) { mbedtls_printf( " [ #%ld ] failed: mbedtls_ssl_write returned -0x%04x\n", thread_id, ret ); goto thread_exit; } } len = ret; mbedtls_printf( " [ #%ld ] %d bytes written\n=====\n%s\n=====\n", thread_id, len, (char *) buf ); mbedtls_printf( " [ #%ld ] . Closing the connection...", thread_id ); while( ( ret = mbedtls_ssl_close_notify( &ssl ) ) < 0 ) { if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) { mbedtls_printf( " [ #%ld ] failed: mbedtls_ssl_close_notify returned -0x%04x\n", thread_id, ret ); goto thread_exit; } } mbedtls_printf( " ok\n" ); ret = 0; thread_exit: #ifdef MBEDTLS_ERROR_C if( ret != 0 ) { char error_buf[100]; mbedtls_strerror( ret, error_buf, 100 ); mbedtls_printf(" [ #%ld ] Last error was: -0x%04x - %s\n\n", thread_id, -ret, error_buf ); } #endif mbedtls_net_free( client_fd ); mbedtls_ssl_free( &ssl ); thread_info->thread_complete = 1; return( NULL ); }
static void https_handler(struct http_client_ctx *ctx, struct k_sem *startup_sync) { struct tx_fifo_block *tx_data; struct http_client_request req; size_t len; int ret; /* First mbedtls specific initialization */ ret = https_init(ctx); k_sem_give(startup_sync); if (ret < 0) { return; } reset: http_parser_init(&ctx->parser, HTTP_RESPONSE); ctx->rsp.data_len = 0; /* Wait that the sender sends the data, and the peer to respond to. */ tx_data = k_fifo_get(&ctx->https.mbedtls.ssl_ctx.tx_fifo, K_FOREVER); if (tx_data) { /* Because the req pointer might disappear as it is controlled * by application, copy the data here. */ memcpy(&req, tx_data->req, sizeof(req)); } else { NET_ASSERT(tx_data); goto reset; } print_info(ctx, ctx->req.method); /* If the connection is not active, then re-connect */ ret = tcp_connect(ctx); if (ret < 0 && ret != -EALREADY) { k_sem_give(&ctx->req.wait); goto reset; } mbedtls_ssl_session_reset(&ctx->https.mbedtls.ssl); mbedtls_ssl_set_bio(&ctx->https.mbedtls.ssl, ctx, ssl_tx, ssl_rx, NULL); /* SSL handshake. The ssl_rx() function will be called next by * mbedtls library. The ssl_rx() will block and wait that data is * received by ssl_received() and passed to it via fifo. After * receiving the data, this function will then proceed with secure * connection establishment. */ /* Waiting SSL handshake */ do { ret = mbedtls_ssl_handshake(&ctx->https.mbedtls.ssl); if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { if (ret == MBEDTLS_ERR_SSL_CONN_EOF) { goto close; } if (ret < 0) { print_error("mbedtls_ssl_handshake returned " "-0x%x", ret); goto close; } } } while (ret != 0); ret = http_request(ctx, &req, BUF_ALLOC_TIMEOUT); k_mem_pool_free(&tx_data->block); if (ret < 0) { NET_DBG("Send error (%d)", ret); goto close; } NET_DBG("Read HTTPS response"); do { len = ctx->rsp.response_buf_len - 1; memset(ctx->rsp.response_buf, 0, ctx->rsp.response_buf_len); ret = mbedtls_ssl_read(&ctx->https.mbedtls.ssl, ctx->rsp.response_buf, len); if (ret == 0) { goto close; } if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) { continue; } if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { NET_DBG("Connection was closed gracefully"); goto close; } if (ret == MBEDTLS_ERR_NET_CONN_RESET) { NET_DBG("Connection was reset by peer"); goto close; } if (ret == -EIO) { NET_DBG("Response received, waiting another ctx %p", ctx); goto next; } if (ret < 0) { print_error("mbedtls_ssl_read returned -0x%x", ret); goto close; } /* The data_len will count how many bytes we have read, * this value is passed to user supplied response callback * by on_body() and on_message_complete() functions. */ ctx->rsp.data_len += ret; ret = http_parser_execute(&ctx->parser, &ctx->settings, ctx->rsp.response_buf, ret); if (!ret) { goto close; } ctx->rsp.data_len = 0; if (ret > 0) { /* Get more data */ ret = MBEDTLS_ERR_SSL_WANT_READ; } } while (ret < 0); close: /* If there is any pending data that have not been processed yet, * we need to free it here. */ if (ctx->https.mbedtls.ssl_ctx.rx_pkt) { net_pkt_unref(ctx->https.mbedtls.ssl_ctx.rx_pkt); ctx->https.mbedtls.ssl_ctx.rx_pkt = NULL; ctx->https.mbedtls.ssl_ctx.frag = NULL; } NET_DBG("Resetting HTTPS connection %p", ctx); tcp_disconnect(ctx); next: mbedtls_ssl_close_notify(&ctx->https.mbedtls.ssl); goto reset; }
int main( void ) { int ret = exit_ok; mbedtls_net_context server_fd; struct sockaddr_in addr; #if defined(MBEDTLS_X509_CRT_PARSE_C) mbedtls_x509_crt ca; #endif mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_ssl_context ssl; mbedtls_ssl_config conf; mbedtls_ctr_drbg_init( &ctr_drbg ); /* * 0. Initialize and setup stuff */ mbedtls_net_init( &server_fd ); mbedtls_ssl_init( &ssl ); mbedtls_ssl_config_init( &conf ); #if defined(MBEDTLS_X509_CRT_PARSE_C) mbedtls_x509_crt_init( &ca ); #endif mbedtls_entropy_init( &entropy ); if( mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) pers, strlen( pers ) ) != 0 ) { ret = ctr_drbg_seed_failed; goto exit; } if( mbedtls_ssl_config_defaults( &conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT ) != 0 ) { ret = ssl_config_defaults_failed; goto exit; } mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg ); #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) mbedtls_ssl_conf_psk( &conf, psk, sizeof( psk ), (const unsigned char *) psk_id, sizeof( psk_id ) - 1 ); #endif #if defined(MBEDTLS_X509_CRT_PARSE_C) if( mbedtls_x509_crt_parse_der( &ca, ca_cert, sizeof( ca_cert ) ) != 0 ) { ret = x509_crt_parse_failed; goto exit; } mbedtls_ssl_conf_ca_chain( &conf, &ca, NULL ); mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_REQUIRED ); #endif if( mbedtls_ssl_setup( &ssl, &conf ) != 0 ) { ret = ssl_setup_failed; goto exit; } #if defined(MBEDTLS_X509_CRT_PARSE_C) if( mbedtls_ssl_set_hostname( &ssl, HOSTNAME ) != 0 ) { ret = hostname_failed; goto exit; } #endif /* * 1. Start the connection */ memset( &addr, 0, sizeof( addr ) ); addr.sin_family = AF_INET; ret = 1; /* for endianness detection */ addr.sin_port = *((char *) &ret) == ret ? PORT_LE : PORT_BE; addr.sin_addr.s_addr = *((char *) &ret) == ret ? ADDR_LE : ADDR_BE; ret = 0; if( ( server_fd.fd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) { ret = socket_failed; goto exit; } if( connect( server_fd.fd, (const struct sockaddr *) &addr, sizeof( addr ) ) < 0 ) { ret = connect_failed; goto exit; } mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL ); if( mbedtls_ssl_handshake( &ssl ) != 0 ) { ret = ssl_handshake_failed; goto exit; } /* * 2. Write the GET request and close the connection */ if( mbedtls_ssl_write( &ssl, (const unsigned char *) GET_REQUEST, sizeof( GET_REQUEST ) - 1 ) <= 0 ) { ret = ssl_write_failed; goto exit; } mbedtls_ssl_close_notify( &ssl ); exit: mbedtls_net_free( &server_fd ); mbedtls_ssl_free( &ssl ); mbedtls_ssl_config_free( &conf ); mbedtls_ctr_drbg_free( &ctr_drbg ); mbedtls_entropy_free( &entropy ); #if defined(MBEDTLS_X509_CRT_PARSE_C) mbedtls_x509_crt_free( &ca ); #endif return( ret ); }
int ssl_connect(SSLConnection* conn, const char* host, int port) { int ret; char buffer[8]; ret = mbedtls_ctr_drbg_seed(&conn->drbg_ctx, mbedtls_entropy_func, &conn->entropy_ctx, (const unsigned char *) pers, strlen(pers)); if (ret < 0) { return -1; } ret = mbedtls_x509_crt_parse(&conn->ca_cert, (const unsigned char *) conn->ca_cert_str, strlen(conn->ca_cert_str) + 1); if (ret < 0) { return handle_error(ret); } ret = mbedtls_x509_crt_parse(&conn->client_cert, (const unsigned char *) conn->client_cert_str, strlen(conn->client_cert_str) + 1); if (ret < 0) { return handle_error(ret); } ret = mbedtls_pk_parse_key(&conn->client_key, (const unsigned char *) conn->client_key_str, strlen(conn->client_key_str) + 1, NULL, 0); if (ret != 0) { return handle_error(ret); } snprintf(buffer, sizeof(buffer), "%d", port); ret = mbedtls_net_connect(&conn->net_ctx, host, buffer, MBEDTLS_NET_PROTO_TCP); if (ret != 0) { return handle_error(ret); } ret = mbedtls_ssl_config_defaults(&conn->ssl_conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); if (ret != 0) { return handle_error(ret); } #ifdef MBEDTLS_DEBUG_C mbedtls_ssl_conf_dbg(&conn->ssl_conf, my_debug, stdout); mbedtls_debug_set_threshold(5); #endif mbedtls_ssl_conf_authmode(&conn->ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED); mbedtls_ssl_conf_rng(&conn->ssl_conf, mbedtls_ctr_drbg_random, &conn->drbg_ctx); mbedtls_ssl_conf_read_timeout(&conn->ssl_conf, SSL_READ_TIMEOUT_MS); mbedtls_ssl_conf_ca_chain(&conn->ssl_conf, &conn->ca_cert, NULL); ret = mbedtls_ssl_conf_own_cert(&conn->ssl_conf, &conn->client_cert, &conn->client_key); if (ret != 0) { return handle_error(ret); } ret = mbedtls_ssl_setup(&conn->ssl_ctx, &conn->ssl_conf); if (ret != 0) { return handle_error(ret); } ret = mbedtls_ssl_set_hostname(&conn->ssl_ctx, host); if (ret != 0) { return handle_error(ret); } mbedtls_ssl_set_bio(&conn->ssl_ctx, &conn->net_ctx, mbedtls_net_send, NULL, mbedtls_net_recv_timeout); while ((ret = mbedtls_ssl_handshake(&conn->ssl_ctx)) != 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) { return handle_error(ret); } } handle_error(ret); vTaskDelay(5000 / portTICK_PERIOD_MS); } mbedtls_ssl_get_record_expansion(&conn->ssl_ctx); ret = mbedtls_ssl_get_verify_result(&conn->ssl_ctx); if (ret != 0) { return handle_error(ret); } return ret; }
static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg, esp_tls_t *tls) { if (!tls) { ESP_LOGE(TAG, "empty esp_tls parameter"); return -1; } /* These states are used to keep a tab on connection progress in case of non-blocking connect, and in case of blocking connect these cases will get executed one after the other */ switch (tls->conn_state) { case ESP_TLS_INIT: ; int sockfd; int ret = esp_tcp_connect(hostname, hostlen, port, &sockfd, cfg); if (ret < 0) { return -1; } tls->sockfd = sockfd; if (!cfg) { tls->read = tcp_read; tls->write = tcp_write; ESP_LOGD(TAG, "non-tls connection established"); return 1; } if (cfg->non_block) { FD_ZERO(&tls->rset); FD_SET(tls->sockfd, &tls->rset); tls->wset = tls->rset; } tls->conn_state = ESP_TLS_CONNECTING; /* falls through */ case ESP_TLS_CONNECTING: if (cfg->non_block) { ESP_LOGD(TAG, "connecting..."); struct timeval tv; ms_to_timeval(cfg->timeout_ms, &tv); /* In case of non-blocking I/O, we use the select() API to check whether connection has been estbalished or not*/ if (select(tls->sockfd + 1, &tls->rset, &tls->wset, NULL, cfg->timeout_ms ? &tv : NULL) == 0) { ESP_LOGD(TAG, "select() timed out"); return 0; } if (FD_ISSET(tls->sockfd, &tls->rset) || FD_ISSET(tls->sockfd, &tls->wset)) { int error; unsigned int len = sizeof(error); /* pending error check */ if (getsockopt(tls->sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { ESP_LOGD(TAG, "Non blocking connect failed"); tls->conn_state = ESP_TLS_FAIL; return -1; } } } /* By now, the connection has been established */ ret = create_ssl_handle(tls, hostname, hostlen, cfg); if (ret != 0) { ESP_LOGD(TAG, "create_ssl_handshake failed"); tls->conn_state = ESP_TLS_FAIL; return -1; } tls->read = tls_read; tls->write = tls_write; tls->conn_state = ESP_TLS_HANDSHAKE; /* falls through */ case ESP_TLS_HANDSHAKE: ESP_LOGD(TAG, "handshake in progress..."); ret = mbedtls_ssl_handshake(&tls->ssl); if (ret == 0) { tls->conn_state = ESP_TLS_DONE; return 1; } else { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret); if (cfg->cacert_pem_buf != NULL || cfg->use_global_ca_store == true) { /* This is to check whether handshake failed due to invalid certificate*/ verify_certificate(tls); } tls->conn_state = ESP_TLS_FAIL; return -1; } /* Irrespective of blocking or non-blocking I/O, we return on getting MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE during handshake */ return 0; } break; case ESP_TLS_FAIL: ESP_LOGE(TAG, "failed to open a new connection");; break; default: ESP_LOGE(TAG, "invalid esp-tls state"); break; } return -1; }
int main( void ) { int ret, len, cnt = 0, pid; mbedtls_net_context listen_fd, client_fd; unsigned char buf[1024]; const char *pers = "ssl_fork_server"; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_ssl_context ssl; mbedtls_ssl_config conf; mbedtls_x509_crt srvcert; mbedtls_pk_context pkey; mbedtls_net_init( &listen_fd ); mbedtls_net_init( &client_fd ); mbedtls_ssl_init( &ssl ); mbedtls_ssl_config_init( &conf ); mbedtls_entropy_init( &entropy ); mbedtls_pk_init( &pkey ); mbedtls_x509_crt_init( &srvcert ); mbedtls_ctr_drbg_init( &ctr_drbg ); signal( SIGCHLD, SIG_IGN ); /* * 0. Initial seeding of the RNG */ mbedtls_printf( "\n . Initial seeding of the random generator..." ); fflush( stdout ); 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" ); /* * 1. Load the certificates and private RSA key */ 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; } mbedtls_printf( " ok\n" ); /* * 1b. Prepare SSL configuration */ mbedtls_printf( " . Configuring SSL..." ); fflush( stdout ); if( ( ret = mbedtls_ssl_config_defaults( &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( &conf, mbedtls_ctr_drbg_random, &ctr_drbg ); mbedtls_ssl_conf_dbg( &conf, my_debug, stdout ); mbedtls_ssl_conf_ca_chain( &conf, srvcert.next, NULL ); if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert, &pkey ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret ); goto exit; } mbedtls_printf( " ok\n" ); /* * 2. Setup the listening TCP socket */ mbedtls_printf( " . Bind on https://localhost:4433/ ..." ); fflush( stdout ); if( ( ret = mbedtls_net_bind( &listen_fd, NULL, "4433", MBEDTLS_NET_PROTO_TCP ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_net_bind returned %d\n\n", ret ); goto exit; } mbedtls_printf( " ok\n" ); while( 1 ) { /* * 3. Wait until a client connects */ mbedtls_net_init( &client_fd ); mbedtls_ssl_init( &ssl ); mbedtls_printf( " . Waiting for a remote connection ..." ); fflush( stdout ); 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; } mbedtls_printf( " ok\n" ); /* * 3.5. Forking server thread */ pid = fork(); mbedtls_printf( " . Forking to handle connection ..." ); fflush( stdout ); if( pid < 0 ) { mbedtls_printf(" failed\n ! fork returned %d\n\n", pid ); goto exit; } mbedtls_printf( " ok\n" ); if( pid != 0 ) { if( ( ret = mbedtls_ctr_drbg_reseed( &ctr_drbg, (const unsigned char *) "parent", 6 ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ctr_drbg_reseed returned %d\n", ret ); goto exit; } mbedtls_net_free( &client_fd ); continue; } mbedtls_net_free( &listen_fd ); /* * 4. Setup stuff */ mbedtls_printf( " . Setting up the SSL data...." ); fflush( stdout ); if( ( ret = mbedtls_ctr_drbg_reseed( &ctr_drbg, (const unsigned char *) "child", 5 ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ctr_drbg_reseed returned %d\n", ret ); goto exit; } if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_setup returned %d\n\n", ret ); goto exit; } mbedtls_ssl_set_bio( &ssl, &client_fd, mbedtls_net_send, mbedtls_net_recv, NULL ); mbedtls_printf( " ok\n" ); /* * 5. 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 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_handshake returned %d\n\n", ret ); goto exit; } } mbedtls_printf( " ok\n" ); /* * 6. Read the HTTP Request */ mbedtls_printf( " < Read from client:" ); fflush( stdout ); 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 <= 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 %d\n", ret ); break; } break; } len = ret; mbedtls_printf( " %d bytes read\n\n%s", len, (char *) buf ); if( ret > 0 ) break; } while( 1 ); /* * 7. Write the 200 Response */ mbedtls_printf( " > Write to client:" ); fflush( stdout ); len = sprintf( (char *) buf, HTTP_RESPONSE, mbedtls_ssl_get_ciphersuite( &ssl ) ); while( cnt++ < 100 ) { while( ( ret = mbedtls_ssl_write( &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; mbedtls_printf( " %d bytes written\n\n%s\n", len, (char *) buf ); mbedtls_net_usleep( 1000000 ); } mbedtls_ssl_close_notify( &ssl ); goto exit; } exit: mbedtls_net_free( &client_fd ); mbedtls_net_free( &listen_fd ); mbedtls_x509_crt_free( &srvcert ); mbedtls_pk_free( &pkey ); 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 return( ret ); }
STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { // Verify the socket object has the full stream protocol mp_get_stream_raise(sock, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); #if MICROPY_PY_USSL_FINALISER mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t); #else mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t); #endif o->base.type = &ussl_socket_type; o->sock = sock; int ret; mbedtls_ssl_init(&o->ssl); mbedtls_ssl_config_init(&o->conf); mbedtls_x509_crt_init(&o->cacert); mbedtls_x509_crt_init(&o->cert); mbedtls_pk_init(&o->pkey); mbedtls_ctr_drbg_init(&o->ctr_drbg); #ifdef MBEDTLS_DEBUG_C // Debug level (0-4) mbedtls_debug_set_threshold(0); #endif mbedtls_entropy_init(&o->entropy); const byte seed[] = "upy"; ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, mbedtls_entropy_func, &o->entropy, seed, sizeof(seed)); if (ret != 0) { goto cleanup; } ret = mbedtls_ssl_config_defaults(&o->conf, args->server_side.u_bool ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); if (ret != 0) { goto cleanup; } mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE); mbedtls_ssl_conf_rng(&o->conf, mbedtls_ctr_drbg_random, &o->ctr_drbg); #ifdef MBEDTLS_DEBUG_C mbedtls_ssl_conf_dbg(&o->conf, mbedtls_debug, NULL); #endif ret = mbedtls_ssl_setup(&o->ssl, &o->conf); if (ret != 0) { goto cleanup; } if (args->server_hostname.u_obj != mp_const_none) { const char *sni = mp_obj_str_get_str(args->server_hostname.u_obj); ret = mbedtls_ssl_set_hostname(&o->ssl, sni); if (ret != 0) { goto cleanup; } } mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL); if (args->key.u_obj != MP_OBJ_NULL) { size_t key_len; const byte *key = (const byte*)mp_obj_str_get_data(args->key.u_obj, &key_len); // len should include terminating null ret = mbedtls_pk_parse_key(&o->pkey, key, key_len + 1, NULL, 0); assert(ret == 0); size_t cert_len; const byte *cert = (const byte*)mp_obj_str_get_data(args->cert.u_obj, &cert_len); // len should include terminating null ret = mbedtls_x509_crt_parse(&o->cert, cert, cert_len + 1); assert(ret == 0); ret = mbedtls_ssl_conf_own_cert(&o->conf, &o->cert, &o->pkey); assert(ret == 0); } if (args->do_handshake.u_bool) { while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { printf("mbedtls_ssl_handshake error: -%x\n", -ret); goto cleanup; } } } return o; cleanup: mbedtls_pk_free(&o->pkey); mbedtls_x509_crt_free(&o->cert); mbedtls_x509_crt_free(&o->cacert); mbedtls_ssl_free(&o->ssl); mbedtls_ssl_config_free(&o->conf); mbedtls_ctr_drbg_free(&o->ctr_drbg); mbedtls_entropy_free(&o->entropy); if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) { mp_raise_OSError(MP_ENOMEM); } else { mp_raise_OSError(MP_EIO); } }
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( void ) { int ret, len; mbedtls_net_context listen_fd, client_fd; unsigned char buf[1024]; const char *pers = "dtls_server"; unsigned char client_ip[16] = { 0 }; size_t cliip_len; mbedtls_ssl_cookie_ctx cookie_ctx; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_ssl_context ssl; mbedtls_ssl_config conf; mbedtls_x509_crt srvcert; mbedtls_pk_context pkey; mbedtls_timing_delay_context timer; #if defined(MBEDTLS_SSL_CACHE_C) mbedtls_ssl_cache_context cache; #endif mbedtls_net_init( &listen_fd ); mbedtls_net_init( &client_fd ); mbedtls_ssl_init( &ssl ); mbedtls_ssl_config_init( &conf ); mbedtls_ssl_cookie_init( &cookie_ctx ); #if defined(MBEDTLS_SSL_CACHE_C) mbedtls_ssl_cache_init( &cache ); #endif mbedtls_x509_crt_init( &srvcert ); mbedtls_pk_init( &pkey ); mbedtls_entropy_init( &entropy ); mbedtls_ctr_drbg_init( &ctr_drbg ); #if defined(MBEDTLS_DEBUG_C) mbedtls_debug_set_threshold( DEBUG_LEVEL ); #endif /* * 1. Load the certificates and private RSA key */ printf( "\n . 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 ) { 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 ) { 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 ) { printf( " failed\n ! mbedtls_pk_parse_key returned %d\n\n", ret ); goto exit; } printf( " ok\n" ); /* * 2. Setup the "listening" UDP socket */ printf( " . Bind on udp/*/4433 ..." ); fflush( stdout ); if( ( ret = mbedtls_net_bind( &listen_fd, NULL, "4433", MBEDTLS_NET_PROTO_UDP ) ) != 0 ) { printf( " failed\n ! mbedtls_net_bind returned %d\n\n", ret ); goto exit; } printf( " ok\n" ); /* * 3. Seed the RNG */ printf( " . Seeding the random number generator..." ); fflush( stdout ); 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 ); goto exit; } printf( " ok\n" ); /* * 4. Setup stuff */ printf( " . Setting up the DTLS data..." ); fflush( stdout ); if( ( ret = mbedtls_ssl_config_defaults( &conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret ); goto exit; } mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg ); mbedtls_ssl_conf_dbg( &conf, my_debug, stdout ); #if defined(MBEDTLS_SSL_CACHE_C) mbedtls_ssl_conf_session_cache( &conf, &cache, mbedtls_ssl_cache_get, mbedtls_ssl_cache_set ); #endif mbedtls_ssl_conf_ca_chain( &conf, srvcert.next, NULL ); if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert, &pkey ) ) != 0 ) { printf( " failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret ); goto exit; } if( ( ret = mbedtls_ssl_cookie_setup( &cookie_ctx, mbedtls_ctr_drbg_random, &ctr_drbg ) ) != 0 ) { printf( " failed\n ! mbedtls_ssl_cookie_setup returned %d\n\n", ret ); goto exit; } mbedtls_ssl_conf_dtls_cookies( &conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, &cookie_ctx ); if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 ) { printf( " failed\n ! mbedtls_ssl_setup returned %d\n\n", ret ); goto exit; } mbedtls_ssl_set_timer_cb( &ssl, &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay ); printf( " ok\n" ); reset: #ifdef MBEDTLS_ERROR_C if( ret != 0 ) { char error_buf[100]; mbedtls_strerror( ret, error_buf, 100 ); printf("Last error was: %d - %s\n\n", ret, error_buf ); } #endif mbedtls_net_free( &client_fd ); mbedtls_ssl_session_reset( &ssl ); /* * 3. Wait until a client connects */ printf( " . Waiting for a remote connection ..." ); fflush( stdout ); if( ( ret = mbedtls_net_accept( &listen_fd, &client_fd, client_ip, sizeof( client_ip ), &cliip_len ) ) != 0 ) { printf( " failed\n ! mbedtls_net_accept returned %d\n\n", ret ); goto exit; } /* For HelloVerifyRequest cookies */ if( ( ret = mbedtls_ssl_set_client_transport_id( &ssl, client_ip, cliip_len ) ) != 0 ) { printf( " failed\n ! " "mbedtls_ssl_set_client_transport_id() returned -0x%x\n\n", -ret ); goto exit; } mbedtls_ssl_set_bio( &ssl, &client_fd, mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout ); printf( " ok\n" ); /* * 5. Handshake */ printf( " . Performing the DTLS handshake..." ); fflush( stdout ); do ret = mbedtls_ssl_handshake( &ssl ); while( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ); if( ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ) { printf( " hello verification requested\n" ); ret = 0; goto reset; } else if( ret != 0 ) { printf( " failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", -ret ); goto reset; } printf( " ok\n" ); /* * 6. Read the echo Request */ printf( " < Read from client:" ); 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: printf( " timeout\n\n" ); goto reset; case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: printf( " connection was closed gracefully\n" ); ret = 0; goto close_notify; default: printf( " mbedtls_ssl_read returned -0x%x\n\n", -ret ); goto reset; } } len = ret; printf( " %d bytes read\n\n%s\n\n", len, buf ); /* * 7. Write the 200 Response */ printf( " > Write to client:" ); fflush( stdout ); do ret = mbedtls_ssl_write( &ssl, buf, len ); while( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ); if( ret < 0 ) { printf( " failed\n ! mbedtls_ssl_write returned %d\n\n", ret ); goto exit; } len = ret; printf( " %d bytes written\n\n%s\n\n", len, buf ); /* * 8. Done, cleanly close the connection */ close_notify: 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; printf( " done\n" ); goto reset; /* * Final clean-ups and exit */ exit: #ifdef MBEDTLS_ERROR_C if( ret != 0 ) { char error_buf[100]; mbedtls_strerror( ret, error_buf, 100 ); printf( "Last error was: %d - %s\n\n", ret, error_buf ); } #endif mbedtls_net_free( &client_fd ); mbedtls_net_free( &listen_fd ); mbedtls_x509_crt_free( &srvcert ); mbedtls_pk_free( &pkey ); mbedtls_ssl_free( &ssl ); mbedtls_ssl_config_free( &conf ); mbedtls_ssl_cookie_free( &cookie_ctx ); #if defined(MBEDTLS_SSL_CACHE_C) mbedtls_ssl_cache_free( &cache ); #endif mbedtls_ctr_drbg_free( &ctr_drbg ); mbedtls_entropy_free( &entropy ); #if defined(_WIN32) 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 ssl_init_info(int *server_fd,ssl_info *sslinfo) { int ret; const char *pers = "ssl"; mbedtls_x509_crt_init(&sslinfo->cacert ); mbedtls_ctr_drbg_init(&sslinfo->ctr_drbg); mbedtls_entropy_init(&sslinfo->entropy ); if( mbedtls_ctr_drbg_seed( &sslinfo->ctr_drbg, mbedtls_entropy_func, &sslinfo->entropy, (const unsigned char *) pers, strlen( pers ) ) != 0 ) { return -1; } mbedtls_ssl_init( &sslinfo->ssl ); mbedtls_ssl_config_init( &sslinfo->conf ); if( ( ret = mbedtls_ssl_config_defaults( &sslinfo->conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 ) { echo( " failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret ); return -1; } mbedtls_ssl_conf_endpoint( &sslinfo->conf, MBEDTLS_SSL_IS_CLIENT ); mbedtls_ssl_conf_authmode( &sslinfo->conf, MBEDTLS_SSL_VERIFY_OPTIONAL ); mbedtls_ssl_conf_ca_chain( &sslinfo->conf, &sslinfo->cacert,NULL); mbedtls_ssl_conf_rng( &sslinfo->conf, mbedtls_ctr_drbg_random, &sslinfo->ctr_drbg ); if( ( ret = mbedtls_ssl_setup( &sslinfo->ssl, &sslinfo->conf ) ) != 0 ) { echo( " failed\n ! mbedtls_ssl_setup returned %d\n\n", ret ); return -1; } mbedtls_ssl_set_bio( &sslinfo->ssl, server_fd,mbedtls_net_send, mbedtls_net_recv,NULL ); mbedtls_ssl_set_session(&sslinfo->ssl, &ssn); while((ret = mbedtls_ssl_handshake(&sslinfo->ssl))!=0) { if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) { echo( " failed\n ! ssl_handshake returned -0x%x\n\n", -ret ); return -1; } //CPU sleep sleeps(1); } if((ret = mbedtls_ssl_get_verify_result( &sslinfo->ssl ) ) != 0 ) { // echo( "Verifying peer X.509 certificate...failed \r\n" ); } else { echo( " ok\n" ); } //保存session if( ( ret = mbedtls_ssl_get_session( &sslinfo->ssl, &ssn ) ) != 0 ) { //失败初始化 memset(&ssn, 0, sizeof(mbedtls_ssl_session)); } return 0; }
/** * @brief Start the SSL client. * @param[in] pssl: mbedtls ssl struct. * @param[in] psocket. The underlying file descriptor. * @param[in] server_addr. server address. * @param[in] custom_config: custome config. * @return The result. 0 is ok. */ static int nghttp2_ssl_start(mbedtls_ssl_context *pssl, mbedtls_net_context *psocket, http2_server_addr_t *server_addr, http2_ssl_custom_conf_t *custom_config) { /* * 0. Init */ int ret = -1; /* alpn */ const char *alpn_list[5]; char a[] = "http/1.1"; char b[] = "h2"; char c[] = "h2-14"; char d[] = "h2-16"; alpn_list[0] = b; alpn_list[1] = c; alpn_list[2] = d; alpn_list[3] = a; alpn_list[4] = NULL; if (0 != (ret = nghttp2_ssl_client_init(pssl, psocket, custom_config))) { NGHTTP2_DBG( " failed ! nghttp2_ssl_client_init returned -0x%04x", -ret ); return ret; } NGHTTP2_DBG(" . Connecting to tcp/%s/%4d...", server_addr->host, server_addr->port); /* * 1. Start the connection */ if (0 != (ret = mbedtls_net_connect(psocket, server_addr->host, "443", MBEDTLS_NET_PROTO_TCP))) { NGHTTP2_DBG(" failed ! net_connect returned -0x%04x", -ret); return ret; } NGHTTP2_DBG( " ok" ); /* * 2. Setup stuff */ NGHTTP2_DBG( " . Setting up the SSL/TLS structure..." ); if ( ( ret = mbedtls_ssl_config_defaults( &(custom_config->conf), MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 ) { NGHTTP2_DBG( " failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret ); return ret; } NGHTTP2_DBG( " ok" ); /* alpn */ if ((ret = mbedtls_ssl_conf_alpn_protocols(&(custom_config->conf), alpn_list)) != 0) { printf("mbedtls_ssl_conf_alpn_protocols failed ret = %d\r\n", ret); return ret; } /* OPTIONAL is not optimal for security, * but makes interop easier in this simplified example */ mbedtls_ssl_conf_authmode( &(custom_config->conf), custom_config->common_settings.authmode ); mbedtls_ssl_conf_ca_chain( &(custom_config->conf), &(custom_config->verify_source.cacertl), custom_config->verify_source.ca_crl ); mbedtls_ssl_conf_rng( &(custom_config->conf), custom_config->common_settings.f_random, &ctr_drbg ); mbedtls_ssl_conf_dbg( &(custom_config->conf), custom_config->common_settings.f_debug, NULL ); mbedtls_ssl_conf_cert_profile( &(custom_config->conf), &mbedtls_x509_crt_profile_myclient); mbedtls_ssl_conf_ciphersuites(&(custom_config->conf), (const int *)&nghttp2_ciphersuite); if ( ( ret = mbedtls_ssl_setup( pssl, &(custom_config->conf) ) ) != 0 ) { NGHTTP2_DBG( " failed\n ! mbedtls_ssl_setup returned %d\n\n", ret ); return ret; } /* * set host name, related with SNI */ if ( ( ret = mbedtls_ssl_set_hostname(pssl, server_addr->host) ) != 0 ) { printf( " failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret ); return ret; } mbedtls_ssl_set_bio( pssl, psocket, custom_config->common_settings.f_send, custom_config->common_settings.f_recv, mbedtls_net_recv_timeout ); mbedtls_ssl_conf_read_timeout(&(custom_config->conf), 10000); mbedtls_ssl_conf_min_version(&(custom_config->conf), MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); /* * 4. Handshake */ NGHTTP2_DBG(". Performing the SSL/TLS handshake..."); while ((ret = mbedtls_ssl_handshake(pssl)) != 0) { if ((ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) { NGHTTP2_DBG( " failed ! mbedtls_ssl_handshake returned -0x%04x", -ret); return ret; } } { /* you can check if alpn_str is "h2", if not, should fallback to http/1. */ const char *alpn_str = mbedtls_ssl_get_alpn_protocol(pssl); NGHTTP2_DBG("[ application layer protocol chosen is %s ]", alpn_str ? alpn_str : "(none)"); if (alpn_str == NULL) { ret = NOT_SUPPORT_H2; //you can define an value you know return ret; } } NGHTTP2_DBG( " ok" ); /* * 5. Verify the server certificate */ NGHTTP2_DBG(" Verifying peer X.509 certificate..."); http2_verify_source_t *verify_source = &custom_config->verify_source; if ((NULL != verify_source->f_confirm) && (0 != (ret = verify_source->f_confirm(mbedtls_ssl_get_verify_result(pssl))))) { NGHTTP2_DBG(" failed ! verify result not confirmed."); return ret; } return 0; }
static CURLcode mbed_connect_step2(struct connectdata *conn, int sockindex) { int ret; struct SessionHandle *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; const mbedtls_x509_crt *peercert; #ifdef HAS_ALPN const char* next_protocol; #endif char errorbuf[128]; errorbuf[0] = 0; conn->recv[sockindex] = mbed_recv; conn->send[sockindex] = mbed_send; ret = mbedtls_ssl_handshake(&connssl->ssl); if(ret == MBEDTLS_ERR_SSL_WANT_READ) { connssl->connecting_state = ssl_connect_2_reading; return CURLE_OK; } else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) { connssl->connecting_state = ssl_connect_2_writing; return CURLE_OK; } else if(ret) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* MBEDTLS_ERROR_C */ failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s", -ret, errorbuf); return CURLE_SSL_CONNECT_ERROR; } infof(data, "mbedTLS: Handshake complete, cipher is %s\n", mbedtls_ssl_get_ciphersuite(&conn->ssl[sockindex].ssl) ); ret = mbedtls_ssl_get_verify_result(&conn->ssl[sockindex].ssl); if(ret && data->set.ssl.verifypeer) { if(ret & MBEDTLS_X509_BADCERT_EXPIRED) failf(data, "Cert verify failed: BADCERT_EXPIRED"); if(ret & MBEDTLS_X509_BADCERT_REVOKED) { failf(data, "Cert verify failed: BADCERT_REVOKED"); return CURLE_SSL_CACERT; } if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH) failf(data, "Cert verify failed: BADCERT_CN_MISMATCH"); if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED) failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED"); return CURLE_PEER_FAILED_VERIFICATION; } peercert = mbedtls_ssl_get_peer_cert(&connssl->ssl); if(peercert && data->set.verbose) { const size_t bufsize = 16384; char *buffer = malloc(bufsize); if(!buffer) return CURLE_OUT_OF_MEMORY; if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0) infof(data, "Dumping cert info:\n%s\n", buffer); else infof(data, "Unable to dump certificate information.\n"); free(buffer); } if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { int size; CURLcode result; mbedtls_x509_crt *p; unsigned char pubkey[PUB_DER_MAX_BYTES]; if(!peercert || !peercert->raw.p || !peercert->raw.len) { failf(data, "Failed due to missing peer certificate"); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } p = calloc(1, sizeof(*p)); if(!p) return CURLE_OUT_OF_MEMORY; mbedtls_x509_crt_init(p); /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der needs a non-const key, for now. https://github.com/ARMmbed/mbedtls/issues/396 */ if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) { failf(data, "Failed copying peer certificate"); mbedtls_x509_crt_free(p); free(p); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES); if(size <= 0) { failf(data, "Failed copying public key from peer certificate"); mbedtls_x509_crt_free(p); free(p); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */ result = Curl_pin_peer_pubkey(data, data->set.str[STRING_SSL_PINNEDPUBLICKEY], &pubkey[PUB_DER_MAX_BYTES - size], size); if(result) { mbedtls_x509_crt_free(p); free(p); return result; } mbedtls_x509_crt_free(p); free(p); } #ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { next_protocol = mbedtls_ssl_get_alpn_protocol(&connssl->ssl); if(next_protocol) { infof(data, "ALPN, server accepted to use %s\n", next_protocol); #ifdef USE_NGHTTP2 if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN) && !next_protocol[NGHTTP2_PROTO_VERSION_ID_LEN]) { conn->negnpn = CURL_HTTP_VERSION_2; } else #endif if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH) && !next_protocol[ALPN_HTTP_1_1_LENGTH]) { conn->negnpn = CURL_HTTP_VERSION_1_1; } } else { infof(data, "ALPN, server did not agree to a protocol\n"); } } #endif connssl->connecting_state = ssl_connect_3; infof(data, "SSL connected\n"); return CURLE_OK; }
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!"); } }