Ram Gandikota
/
metronome
FRDM K64F Metronome
mbed-client/mbed-client-mbed-tls/source/m2mconnectionsecuritypimpl.cpp
- Committer:
- ram54288
- Date:
- 2017-05-14
- Revision:
- 0:a2cb7295a1f7
File content as of revision 0:a2cb7295a1f7:
/* * Copyright (c) 2015 ARM Limited. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mbed-client/m2mconnectionhandler.h" #include "mbed-client-mbedtls/m2mconnectionsecuritypimpl.h" #include "mbed-client/m2mtimer.h" #include "mbed-client/m2msecurity.h" #include "mbed-trace/mbed_trace.h" #include "mbedtls/debug.h" #include <string.h> #define TRACE_GROUP "mClt" void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms ); int mbedtls_timing_get_delay( void *data ); int entropy_poll( void *data, unsigned char *output, size_t len, size_t *olen ); //Point these back to M2MConnectionHandler!!! int f_send( void *ctx, const unsigned char *buf, size_t len ); int f_recv(void *ctx, unsigned char *buf, size_t len); int f_recv_timeout(void *ctx, unsigned char *buf, size_t len, uint32_t some); bool cancelled; random_number_cb __random_number_callback; entropy_cb __entropy_callback; //Comment out following define to enable tracing from mbedtls //#define ENABLE_MBED_CLIENT_MBED_TLS_DEBUGS #ifdef ENABLE_MBED_CLIENT_MBED_TLS_DEBUGS static void mbedtls_debug( void *ctx, int level, const char *file, int line, const char *str ) { ((void) level); tr_debug("%s", str); } static int verify_cert_chains(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) { char buf[1024]; (void) data; printf("\nVerifying certificate at depth %d:\n", depth); mbedtls_x509_crt_info(buf, sizeof (buf) - 1, " ", crt); printf("%s", buf); if (*flags == 0) printf("No verification issue for this certificate\n"); else { mbedtls_x509_crt_verify_info(buf, sizeof (buf), " ! ", *flags); printf("%s\n", buf); } return 0; } #endif M2MConnectionSecurityPimpl::M2MConnectionSecurityPimpl(M2MConnectionSecurity::SecurityMode mode) : _flags(0), _sec_mode(mode) { _init_done = false; cancelled = true; _timer = new M2MTimer(*this); mbedtls_ssl_init( &_ssl ); mbedtls_ssl_config_init( &_conf ); mbedtls_x509_crt_init( &_cacert ); mbedtls_x509_crt_init(&_owncert); mbedtls_pk_init(&_pkey); mbedtls_ctr_drbg_init( &_ctr_drbg ); mbedtls_entropy_init( &_entropy ); } M2MConnectionSecurityPimpl::~M2MConnectionSecurityPimpl(){ mbedtls_ssl_config_free(&_conf); mbedtls_ssl_free(&_ssl); mbedtls_x509_crt_free(&_cacert); mbedtls_x509_crt_free(&_owncert); mbedtls_pk_free(&_pkey); mbedtls_ctr_drbg_free( &_ctr_drbg ); mbedtls_entropy_free( &_entropy ); delete _timer; } void M2MConnectionSecurityPimpl::timer_expired(M2MTimerObserver::Type type){ tr_debug("M2MConnectionSecurityPimpl::timer_expired"); if(type == M2MTimerObserver::Dtls && !cancelled){ int error = continue_connecting(); if(MBEDTLS_ERR_SSL_TIMEOUT == error || error == -1) { tr_error("M2MConnectionSecurityPimpl::timer_expired - handshake timeout"); if(_ssl.p_bio) { M2MConnectionHandler* ptr = (M2MConnectionHandler*)_ssl.p_bio; ptr->handle_connection_error(M2MConnectionHandler::SSL_HANDSHAKE_ERROR); } reset(); } } } void M2MConnectionSecurityPimpl::reset(){ _init_done = false; cancelled = true; mbedtls_ssl_config_free(&_conf); mbedtls_ssl_free(&_ssl); mbedtls_x509_crt_free(&_cacert); mbedtls_x509_crt_free(&_owncert); mbedtls_pk_free(&_pkey); mbedtls_ctr_drbg_free( &_ctr_drbg ); mbedtls_entropy_free( &_entropy ); _timer->stop_timer(); } int M2MConnectionSecurityPimpl::init(const M2MSecurity *security) { tr_debug("M2MConnectionSecurityPimpl::init"); int ret = -1; if (security != NULL) { const char *pers = "dtls_client"; mbedtls_ssl_init( &_ssl ); mbedtls_ssl_config_init( &_conf ); mbedtls_x509_crt_init( &_cacert ); mbedtls_x509_crt_init(&_owncert); mbedtls_pk_init(&_pkey); mbedtls_ctr_drbg_init( &_ctr_drbg ); mbedtls_entropy_init( &_entropy ); int mode = MBEDTLS_SSL_TRANSPORT_DATAGRAM; if( _sec_mode == M2MConnectionSecurity::TLS ){ mode = MBEDTLS_SSL_TRANSPORT_STREAM; } if( mbedtls_entropy_add_source( &_entropy, entropy_poll, NULL, 128, 0 ) < 0 ){ return -1; } if(__entropy_callback.entropy_source_ptr) { if( mbedtls_entropy_add_source( &_entropy, __entropy_callback.entropy_source_ptr, __entropy_callback.p_source,__entropy_callback.threshold, __entropy_callback.strong ) < 0 ){ return -1; } } if( mbedtls_ctr_drbg_seed( &_ctr_drbg, mbedtls_entropy_func, &_entropy, (const unsigned char *) pers, strlen( pers ) ) != 0 ) { return -1; } if( mbedtls_ssl_config_defaults( &_conf, MBEDTLS_SSL_IS_CLIENT, mode, 0 ) != 0 ) { return -1; } M2MSecurity::SecurityModeType cert_mode = (M2MSecurity::SecurityModeType)security->resource_value_int(M2MSecurity::SecurityMode); // Note: these are relatively large buffers, no point to make copy of them here as mbedtls will make a copy of them. const uint8_t *srv_public_key = NULL; const uint8_t *public_key = NULL; const uint8_t *sec_key = NULL; uint32_t srv_public_key_size = security->resource_value_buffer(M2MSecurity::ServerPublicKey, srv_public_key); uint32_t public_key_size = security->resource_value_buffer(M2MSecurity::PublicKey, public_key); uint32_t sec_key_size = security->resource_value_buffer(M2MSecurity::Secretkey, sec_key); if( srv_public_key == NULL || public_key == NULL || sec_key == NULL || srv_public_key_size == 0 || public_key_size == 0 || sec_key_size == 0 ){ return -1; } if( cert_mode == M2MSecurity::Certificate ){ if ( mbedtls_x509_crt_parse( &_cacert, (const unsigned char *) srv_public_key, srv_public_key_size + 1) < 0 || mbedtls_x509_crt_parse( &_owncert, (const unsigned char *) public_key, public_key_size + 1) < 0 || mbedtls_pk_parse_key(&_pkey, (const unsigned char *) sec_key, sec_key_size + 1, NULL, 0 ) < 0 ) { ret = -1; } else { ret = 0; } if ( ret == 0 ) { mbedtls_ssl_conf_own_cert(&_conf, &_owncert, &_pkey); mbedtls_ssl_conf_authmode( &_conf, MBEDTLS_SSL_VERIFY_REQUIRED ); mbedtls_ssl_conf_ca_chain( &_conf, &_cacert, NULL ); } } else if ( cert_mode == M2MSecurity::Psk ){ if (mbedtls_ssl_conf_psk(&_conf, sec_key, sec_key_size, public_key, public_key_size) == 0) { ret = 0; } mbedtls_ssl_conf_ciphersuites(&_conf, PSK_SUITES); } else { ret = -1; } #ifdef ENABLE_MBED_CLIENT_MBED_TLS_DEBUGS mbedtls_ssl_conf_dbg( &_conf, mbedtls_debug, stdout ); mbedtls_debug_set_threshold(5); mbedtls_ssl_conf_verify(&_conf, verify_cert_chains, NULL); #endif } if( ret == 0 ){ _init_done = true; } tr_debug("M2MConnectionSecurityPimpl::init - ret %d", ret); return ret; } int M2MConnectionSecurityPimpl::start_handshake(){ tr_debug("M2MConnectionSecurityPimpl::start_handshake"); int ret = -1; do { ret = mbedtls_ssl_handshake( &_ssl ); } while( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE); if( ret != 0 ) { ret = -1; }else { if( ( _flags = mbedtls_ssl_get_verify_result( &_ssl ) ) != 0 ) { ret = -1; } } tr_debug("M2MConnectionSecurityPimpl::start_handshake - OUT"); return ret; } int M2MConnectionSecurityPimpl::connect(M2MConnectionHandler* connHandler){ tr_debug("M2MConnectionSecurityPimpl::connect"); int ret=-1; if(!_init_done){ return ret; } mbedtls_ssl_conf_rng( &_conf, mbedtls_ctr_drbg_random, &_ctr_drbg ); if( ( ret = mbedtls_ssl_setup( &_ssl, &_conf ) ) != 0 ) { return -1; } mbedtls_ssl_set_bio( &_ssl, connHandler, f_send, f_recv, f_recv_timeout ); mbedtls_ssl_set_timer_cb( &_ssl, _timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay ); ret = start_handshake(); _timer->stop_timer(); tr_debug("M2MConnectionSecurityPimpl::connect - handshake ret: %d, ssl state: %d", ret, _ssl.state); return ret; } int M2MConnectionSecurityPimpl::start_connecting_non_blocking(M2MConnectionHandler* connHandler) { tr_debug("M2MConnectionSecurityPimpl::start_connecting_non_blocking"); int ret=-1; if(!_init_done){ return ret; } int mode = MBEDTLS_SSL_TRANSPORT_DATAGRAM; if( _sec_mode == M2MConnectionSecurity::TLS ){ mode = MBEDTLS_SSL_TRANSPORT_STREAM; } if( ( ret = mbedtls_ssl_config_defaults( &_conf, MBEDTLS_SSL_IS_CLIENT, mode, 0 ) ) != 0 ) { return -1; } // This is for non-blocking sockets total timeout is 1+2+4+8+16+29=60 seconds mbedtls_ssl_conf_handshake_timeout( &_conf, 10000, 29000 ); mbedtls_ssl_conf_rng( &_conf, mbedtls_ctr_drbg_random, &_ctr_drbg ); if( ( ret = mbedtls_ssl_setup( &_ssl, &_conf ) ) != 0 ) { return -1; } mbedtls_ssl_set_bio( &_ssl, connHandler, f_send, f_recv, f_recv_timeout ); mbedtls_ssl_set_timer_cb( &_ssl, _timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay ); ret = mbedtls_ssl_handshake_step( &_ssl ); if( ret == 0 ){ ret = mbedtls_ssl_handshake_step( &_ssl ); } if( ret >= 0){ ret = 1; } else { ret = -1; } tr_debug("M2MConnectionSecurityPimpl::start_connecting_non_blocking - handshake ret: %d, ssl state: %d", ret, _ssl.state); return ret; } int M2MConnectionSecurityPimpl::continue_connecting() { tr_debug("M2MConnectionSecurityPimpl::continue_connecting"); int ret=-1; while( ret != M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ ){ ret = mbedtls_ssl_handshake_step( &_ssl ); if( MBEDTLS_ERR_SSL_WANT_READ == ret ){ ret = M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ; } else if (ret != 0) { break; } if( _ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER ){ return 0; } } tr_debug("M2MConnectionSecurityPimpl::continue_connecting, ret: %d", ret); return ret; } int M2MConnectionSecurityPimpl::send_message(unsigned char *message, int len){ tr_debug("M2MConnectionSecurityPimpl::send_message"); int ret=-1; if(!_init_done){ return ret; } do ret = mbedtls_ssl_write( &_ssl, (unsigned char *) message, len ); while( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ); tr_debug("M2MConnectionSecurityPimpl::send_message - ret: %d", ret); return ret; //bytes written } int M2MConnectionSecurityPimpl::read(unsigned char* buffer, uint16_t len){ int ret=-1; if(!_init_done){ tr_error("M2MConnectionSecurityPimpl::read - init not done!"); return ret; } memset( buffer, 0, len ); do ret = mbedtls_ssl_read( &_ssl, buffer, len-1 ); while( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ); return ret; //bytes read } int f_send( void *ctx, const unsigned char *buf, size_t len){ M2MConnectionHandler* handler = ((M2MConnectionHandler *) ctx); return handler->send_to_socket(buf, len); } int f_recv(void *ctx, unsigned char *buf, size_t len){ M2MConnectionHandler* handler = ((M2MConnectionHandler *) ctx); return handler->receive_from_socket(buf, len); } int f_recv_timeout(void *ctx, unsigned char *buf, size_t len, uint32_t /*some*/){ return f_recv(ctx, buf, len); } int entropy_poll( void *, unsigned char *output, size_t len, size_t *olen ) { uint32_t rdm = 0; if(__random_number_callback) { rdm = __random_number_callback(); } else { rdm = time(NULL); } for(uint16_t i=0; i < len; i++){ srand(rdm); output[i] = rand() % 256; } *olen = len; return( 0 ); } void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms ){ tr_debug("mbedtls_timing_set_delay - intermediate: %d", int_ms); tr_debug("mbedtls_timing_set_delay - final: %d", fin_ms); M2MTimer* timer = static_cast<M2MTimer*> (data); if(!timer) { return; } if( int_ms > 0 && fin_ms > 0 ){ tr_debug("mbedtls_timing_set_delay - start"); cancelled = false; timer->stop_timer(); timer->start_dtls_timer(int_ms, fin_ms); }else{ tr_debug("mbedtls_timing_set_delay - stop"); cancelled = true; timer->stop_timer(); } } int mbedtls_timing_get_delay( void *data ){ tr_debug("mbedtls_timing_get_delay"); M2MTimer* timer = static_cast<M2MTimer*> (data); if(!timer){ return 0; } if(true == cancelled) { tr_debug("mbedtls_timing_get_delay - ret -1"); return -1; } else if( timer->is_total_interval_passed() ){ tr_debug("mbedtls_timing_get_delay - ret 2"); return 2; }else if( timer->is_intermediate_interval_passed() ){ tr_debug("mbedtls_timing_get_delay - ret 1"); return 1; }else{ tr_debug("mbedtls_timing_get_delay - ret 0"); return 0; } } void M2MConnectionSecurityPimpl::set_random_number_callback(random_number_cb callback) { __random_number_callback = callback; } void M2MConnectionSecurityPimpl::set_entropy_callback(entropy_cb callback) { __entropy_callback = callback; }