int coap_security_handler_continue_connecting(coap_security_t *sec){ int ret = -1; while( ret != MBEDTLS_ERR_SSL_WANT_READ ){ ret = mbedtls_ssl_handshake_step( &sec->_ssl ); if( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED == ret){ mbedtls_ssl_session_reset(&sec->_ssl); #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, sec->_pw, sec->_pw_len) != 0 ){ return -1; } #endif return 1; } else if(ret && (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)){ return ret; } if( sec->_ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER ){ return 0; } } if(ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE){ return 1; } return -1; }
int coap_security_handler_configure_keys( coap_security_t *sec, coap_security_keys_t keys ) { int ret = -1; switch( sec->_conn_mode ){ case Certificate:{ #if defined(MBEDTLS_X509_CRT_PARSE_C) if( mbedtls_x509_crt_parse( &sec->_cacert, keys._server_cert, keys._server_cert_len ) < 0 ){ break; } if( mbedtls_x509_crt_parse( &sec->_owncert, keys._pub_cert_or_identifier, keys._pub_len ) < 0 ){ break; } if( mbedtls_pk_parse_key(&sec->_pkey, keys._priv, keys._priv_len, NULL, 0) < 0){ break; } //TODO: If needed in server mode, this won't work if( 0 != mbedtls_ssl_conf_own_cert(&sec->_conf, &sec->_owncert, &sec->_pkey) ){ break; } //TODO: use MBEDTLS_SSL_VERIFY_REQUIRED instead of optional mbedtls_ssl_conf_authmode( &sec->_conf, MBEDTLS_SSL_VERIFY_OPTIONAL ); mbedtls_ssl_conf_ca_chain( &sec->_conf, &sec->_cacert, NULL ); ret = 0; #endif break; } case PSK: { #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) if( 0 != mbedtls_ssl_conf_psk(&sec->_conf, keys._priv, keys._priv_len, keys._pub_cert_or_identifier, keys._pub_len) ){ break; } mbedtls_ssl_conf_ciphersuites(&sec->_conf, PSK_SUITES); ret = 0; #endif break; } case ECJPAKE: { #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, keys._priv, keys._priv_len) != 0 ){ return -1; } mbedtls_ssl_conf_ciphersuites(&sec->_conf, ECJPAKE_SUITES); //NOTE: If thread starts supporting PSK in other modes, then this will be needed! mbedtls_ssl_conf_export_keys_cb(&sec->_conf, export_key_block, &sec->_keyblk); ret = 0; #endif break; } default: break; } return ret; }
int coap_security_handler_connect(coap_security_t *sec, bool is_server, SecureSocketMode sock_mode, coap_security_keys_t keys){ int ret = -1; if( !sec ){ return ret; } sec->_is_blocking = true; int endpoint = MBEDTLS_SSL_IS_CLIENT; if( is_server ){ endpoint = MBEDTLS_SSL_IS_SERVER; } int mode = MBEDTLS_SSL_TRANSPORT_DATAGRAM; if( sock_mode == TLS ){ mode = MBEDTLS_SSL_TRANSPORT_STREAM; } if( ( mbedtls_ssl_config_defaults( &sec->_conf, endpoint, mode, 0 ) ) != 0 ) { return -1; } mbedtls_ssl_set_bio( &sec->_ssl, sec, f_send, f_recv, NULL ); mbedtls_ssl_set_timer_cb( &sec->_ssl, sec, set_timer, get_timer ); if( coap_security_handler_configure_keys( sec, keys ) != 0 ){ return -1; } #ifdef MBEDTLS_SSL_SRV_C mbedtls_ssl_conf_dtls_cookies(&sec->_conf, simple_cookie_write, simple_cookie_check, &sec->_cookie); #endif sec->_is_started = true; do { ret = mbedtls_ssl_handshake_step( &sec->_ssl ); if( ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ){ //cookie check failed if( is_server ){ mbedtls_ssl_session_reset(&sec->_ssl); #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, keys._priv, keys._priv_len) != 0 ){ return -1; } #endif ret = MBEDTLS_ERR_SSL_WANT_READ; //needed to keep doing }else{ ret = -1; } } }while( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ); if( ret != 0){ ret = -1; }else{ if( mbedtls_ssl_get_verify_result( &sec->_ssl ) != 0 ) { ret = -1; } } return 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(); } }
otError Dtls::Setup(bool aClient) { int rval; // do not handle new connection before guard time expired VerifyOrExit(mState == kStateOpen, rval = MBEDTLS_ERR_SSL_TIMEOUT); mState = kStateInitializing; mbedtls_ssl_init(&mSsl); mbedtls_ssl_config_init(&mConf); mbedtls_ctr_drbg_init(&mCtrDrbg); mbedtls_entropy_init(&mEntropy); #if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE #ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED mbedtls_x509_crt_init(&mCaChain); mbedtls_x509_crt_init(&mOwnCert); mbedtls_pk_init(&mPrivateKey); #endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED #endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE rval = mbedtls_entropy_add_source(&mEntropy, &Dtls::HandleMbedtlsEntropyPoll, NULL, MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_SOURCE_STRONG); VerifyOrExit(rval == 0); { otExtAddress eui64; otPlatRadioGetIeeeEui64(&GetInstance(), eui64.m8); rval = mbedtls_ctr_drbg_seed(&mCtrDrbg, mbedtls_entropy_func, &mEntropy, eui64.m8, sizeof(eui64)); VerifyOrExit(rval == 0); } rval = mbedtls_ssl_config_defaults(&mConf, aClient ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT); VerifyOrExit(rval == 0); #if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE if (mVerifyPeerCertificate && mCipherSuites[0] == MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8) { mbedtls_ssl_conf_authmode(&mConf, MBEDTLS_SSL_VERIFY_REQUIRED); } else { mbedtls_ssl_conf_authmode(&mConf, MBEDTLS_SSL_VERIFY_NONE); } #else OT_UNUSED_VARIABLE(mVerifyPeerCertificate); #endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE mbedtls_ssl_conf_rng(&mConf, mbedtls_ctr_drbg_random, &mCtrDrbg); mbedtls_ssl_conf_min_version(&mConf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); mbedtls_ssl_conf_max_version(&mConf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); mbedtls_ssl_conf_ciphersuites(&mConf, mCipherSuites); mbedtls_ssl_conf_export_keys_cb(&mConf, HandleMbedtlsExportKeys, this); mbedtls_ssl_conf_handshake_timeout(&mConf, 8000, 60000); mbedtls_ssl_conf_dbg(&mConf, HandleMbedtlsDebug, this); #if OPENTHREAD_ENABLE_BORDER_AGENT || OPENTHREAD_ENABLE_COMMISSIONER || OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE if (!aClient) { mbedtls_ssl_cookie_init(&mCookieCtx); rval = mbedtls_ssl_cookie_setup(&mCookieCtx, mbedtls_ctr_drbg_random, &mCtrDrbg); VerifyOrExit(rval == 0); mbedtls_ssl_conf_dtls_cookies(&mConf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, &mCookieCtx); } #endif // OPENTHREAD_ENABLE_BORDER_AGENT || OPENTHREAD_ENABLE_COMMISSIONER || OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE rval = mbedtls_ssl_setup(&mSsl, &mConf); VerifyOrExit(rval == 0); mbedtls_ssl_set_bio(&mSsl, this, &Dtls::HandleMbedtlsTransmit, HandleMbedtlsReceive, NULL); mbedtls_ssl_set_timer_cb(&mSsl, this, &Dtls::HandleMbedtlsSetTimer, HandleMbedtlsGetTimer); if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8) { rval = mbedtls_ssl_set_hs_ecjpake_password(&mSsl, mPsk, mPskLength); } #if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE else { rval = SetApplicationCoapSecureKeys(); } #endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE VerifyOrExit(rval == 0); mReceiveMessage = NULL; mMessageSubType = Message::kSubTypeNone; mState = kStateConnecting; if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8) { otLogInfoMeshCoP("DTLS started"); } #if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE else { otLogInfoCoap("Application Coap Secure DTLS started"); } #endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE mState = kStateConnecting; Process(); exit: if ((mState == kStateInitializing) && (rval != 0)) { mState = kStateOpen; FreeMbedtls(); } return MapError(rval); }
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); }