Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-os by
coap_security_handler.c
00001 /* 00002 * Copyright (c) 2015-2016 ARM Limited. All Rights Reserved. 00003 */ 00004 00005 #include <string.h> 00006 #include <time.h> 00007 #include <stdlib.h> 00008 00009 #include "mbedtls/sha256.h" 00010 #include "mbedtls/error.h" 00011 #include "mbedtls/platform.h" 00012 #include "mbedtls/ssl_cookie.h" 00013 #include "mbedtls/entropy_poll.h" 00014 #include "mbedtls/ssl.h" 00015 #include "ns_trace.h" 00016 #include "nsdynmemLIB.h" 00017 #include "coap_connection_handler.h" 00018 #include "coap_security_handler.h" 00019 #include "randLIB.h" 00020 #include "mbedtls/ssl_ciphersuites.h" 00021 00022 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) 00023 const int ECJPAKE_SUITES[] = { 00024 MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8, 00025 0 00026 }; 00027 #endif 00028 00029 static const int PSK_SUITES[] = { 00030 MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256, 00031 MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8, 00032 MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8, 00033 0 00034 }; 00035 00036 00037 static void set_timer( void *sec_obj, uint32_t int_ms, uint32_t fin_ms ); 00038 static int get_timer( void *sec_obj ); 00039 static int coap_security_handler_configure_keys( coap_security_t *sec, coap_security_keys_t keys ); 00040 00041 int entropy_poll( void *data, unsigned char *output, size_t len, size_t *olen ); 00042 //Point these back to M2MConnectionHandler!!! 00043 int f_send( void *ctx, const unsigned char *buf, size_t len ); 00044 int f_recv(void *ctx, unsigned char *buf, size_t len); 00045 00046 static int coap_security_handler_init(coap_security_t *sec){ 00047 const char *pers = "dtls_client"; 00048 mbedtls_ssl_init( &sec->_ssl ); 00049 mbedtls_ssl_config_init( &sec->_conf ); 00050 mbedtls_ctr_drbg_init( &sec->_ctr_drbg ); 00051 mbedtls_entropy_init( &sec->_entropy ); 00052 00053 #if defined(MBEDTLS_X509_CRT_PARSE_C) 00054 mbedtls_x509_crt_init( &sec->_cacert ); 00055 mbedtls_x509_crt_init( &sec->_owncert ); 00056 #endif 00057 mbedtls_pk_init( &sec->_pkey ); 00058 00059 memset(&sec->_cookie, 0, sizeof(simple_cookie_t)); 00060 memset(&sec->_keyblk, 0, sizeof(key_block_t)); 00061 00062 sec->_is_started = false; 00063 00064 //TODO: Must have at least 1 strong entropy source, otherwise DTLS will fail. 00065 //This is NOT strong even we say it is! 00066 if( mbedtls_entropy_add_source( &sec->_entropy, entropy_poll, NULL, 00067 128, 1 ) < 0 ){ 00068 return -1; 00069 } 00070 00071 if( ( mbedtls_ctr_drbg_seed( &sec->_ctr_drbg, mbedtls_entropy_func, &sec->_entropy, 00072 (const unsigned char *) pers, 00073 strlen( pers ) ) ) != 0 ) 00074 { 00075 return -1; 00076 } 00077 return 0; 00078 } 00079 00080 static void coap_security_handler_reset(coap_security_t *sec){ 00081 #if defined(MBEDTLS_X509_CRT_PARSE_C) 00082 mbedtls_x509_crt_free(&sec->_cacert); 00083 mbedtls_x509_crt_free(&sec->_owncert); 00084 #endif 00085 00086 mbedtls_pk_free(&sec->_pkey); 00087 00088 mbedtls_entropy_free( &sec->_entropy ); 00089 mbedtls_ctr_drbg_free( &sec->_ctr_drbg ); 00090 mbedtls_ssl_config_free(&sec->_conf); 00091 mbedtls_ssl_free(&sec->_ssl); 00092 } 00093 00094 00095 coap_security_t *coap_security_create(int8_t socket_id, int8_t timer_id, uint8_t *address_ptr, uint16_t port, SecureConnectionMode mode, 00096 send_cb *send_cb, 00097 receive_cb *receive_cb, 00098 start_timer_cb *start_timer_cb, 00099 timer_status_cb *timer_status_cb) 00100 { 00101 if( !address_ptr || send_cb == NULL || receive_cb == NULL || start_timer_cb == NULL || timer_status_cb == NULL){ 00102 return NULL; 00103 } 00104 coap_security_t *this = ns_dyn_mem_alloc(sizeof(coap_security_t)); 00105 if( !this ){ 00106 return NULL; 00107 } 00108 memset(this, 0, sizeof(coap_security_t)); 00109 if( -1 == coap_security_handler_init(this) ){ 00110 ns_dyn_mem_free(this); 00111 return NULL; 00112 } 00113 this->_remote_port = port; 00114 memcpy(this->_remote_address, address_ptr, 16); 00115 this->_conn_mode = mode; 00116 memset(this->_pw, 0, 64); 00117 this->_pw_len = 0; 00118 this->_socket_id = socket_id; 00119 this->_timer_id = timer_id; 00120 this->_send_cb = send_cb; 00121 this->_receive_cb = receive_cb; 00122 this->_start_timer_cb = start_timer_cb; 00123 this->_timer_status_cb = timer_status_cb; 00124 00125 return this; 00126 } 00127 00128 void coap_security_destroy(coap_security_t *sec){ 00129 if( sec ){ 00130 coap_security_handler_reset(sec); 00131 ns_dyn_mem_free(sec); 00132 sec = NULL; 00133 } 00134 } 00135 00136 /**** Random number functions ****/ 00137 00138 /** 00139 * Get a random array of bytes. 00140 * Called back by mbedtls when it wants to fill a buffer with random data 00141 * Must return 0 on success. 00142 */ 00143 static int get_random(void *ctx, unsigned char *buf, size_t len) 00144 { 00145 static int initialised = 0; 00146 uint32_t i; 00147 00148 (void)ctx; /* No context */ 00149 00150 if (!initialised) { 00151 randLIB_seed_random(); 00152 initialised = 1; 00153 } 00154 00155 for (i = 0; i < len; i++) { 00156 buf[i] = (uint8_t)randLIB_get_8bit(); 00157 } 00158 return 0; /* Success */ 00159 } 00160 00161 /**** Cookie functions ****/ 00162 static int simple_cookie_write(void *ctx, 00163 unsigned char **p, unsigned char *end, 00164 const unsigned char *info, size_t ilen) 00165 { 00166 //TODO: As per RFC 6347 cookie must be stateless. This is not the case in here! 00167 //This should be fixed if we see that dos attack would be an issue. 00168 //this is proposed solution in RFC: Cookie = HMAC(Secret, Client-IP, Client-Parameters) 00169 //Secret is generated here and oftenly changed to prevent statistical attack 00170 simple_cookie_t *p_cookie = (simple_cookie_t *)ctx; 00171 00172 /* Not using additional info */ 00173 (void)info; 00174 (void)ilen; 00175 00176 if ((size_t)(end - *p) < COOKIE_SIMPLE_LEN) { 00177 return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL; 00178 } 00179 00180 /* Use a simple random number of length COOKIE_SIMPLE_LEN bytes */ 00181 get_random(NULL, p_cookie->value, COOKIE_SIMPLE_LEN); 00182 memcpy(*p, p_cookie->value, COOKIE_SIMPLE_LEN); 00183 p_cookie->len = COOKIE_SIMPLE_LEN; 00184 *p += COOKIE_SIMPLE_LEN; 00185 return 0; 00186 } 00187 00188 static int simple_cookie_check(void *ctx, 00189 const unsigned char *cookie, size_t clen, 00190 const unsigned char *info, size_t ilen) 00191 { 00192 simple_cookie_t *p_cookie = (simple_cookie_t *)ctx; 00193 00194 /* Not using additional info */ 00195 (void)info; 00196 (void)ilen; 00197 00198 if ((p_cookie->len == 0) || 00199 (clen != p_cookie->len) || 00200 (memcmp(cookie, p_cookie->value, p_cookie->len) != 0)) { 00201 return -1; /* This is what it is in mbedtls... */ 00202 } 00203 return 0; 00204 } 00205 00206 /**** Key export function ****/ 00207 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) 00208 static int export_key_block(void *ctx, 00209 const unsigned char *mk, const unsigned char *kb, 00210 size_t maclen, size_t keylen, size_t ivlen) 00211 { 00212 key_block_t *p_key_block = (key_block_t *)ctx; 00213 00214 /* Not using master key */ 00215 (void)mk; 00216 00217 /* Sanity check MAC and key lengths */ 00218 if ((maclen != 0) || (((2 * keylen) + (2 * ivlen)) != KEY_BLOCK_LEN)) { 00219 return -1; /* Something seriously wrong! */ 00220 } 00221 00222 /* Copy the key block we are using */ 00223 /* No need to skip over MAC keys, MAC len must be 0 if we are here */ 00224 memcpy(p_key_block->value, kb /* + (2 * maclen)*/, (2 * keylen) + (2 * ivlen)); 00225 return 0; 00226 } 00227 #endif 00228 00229 int coap_security_handler_configure_keys( coap_security_t *sec, coap_security_keys_t keys ) 00230 { 00231 int ret = -1; 00232 switch( sec->_conn_mode ){ 00233 case Certificate:{ 00234 #if defined(MBEDTLS_X509_CRT_PARSE_C) 00235 if( mbedtls_x509_crt_parse( &sec->_cacert, keys._server_cert, 00236 keys._server_cert_len ) < 0 ){ 00237 break; 00238 } 00239 if( mbedtls_x509_crt_parse( &sec->_owncert, keys._pub_cert_or_identifier, 00240 keys._pub_len ) < 0 ){ 00241 break; 00242 } 00243 if( mbedtls_pk_parse_key(&sec->_pkey, keys._priv, keys._priv_len, NULL, 0) < 0){ 00244 break; 00245 } 00246 //TODO: If needed in server mode, this won't work 00247 if( 0 != mbedtls_ssl_conf_own_cert(&sec->_conf, &sec->_owncert, &sec->_pkey) ){ 00248 break; 00249 } 00250 //TODO: use MBEDTLS_SSL_VERIFY_REQUIRED instead of optional 00251 mbedtls_ssl_conf_authmode( &sec->_conf, MBEDTLS_SSL_VERIFY_OPTIONAL ); 00252 mbedtls_ssl_conf_ca_chain( &sec->_conf, &sec->_cacert, NULL ); 00253 ret = 0; 00254 #endif 00255 break; 00256 } 00257 case PSK: { 00258 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) 00259 if( 0 != mbedtls_ssl_conf_psk(&sec->_conf, keys._priv, keys._priv_len, keys._pub_cert_or_identifier, keys._pub_len) ){ 00260 break; 00261 } 00262 mbedtls_ssl_conf_ciphersuites(&sec->_conf, PSK_SUITES); 00263 ret = 0; 00264 #endif 00265 break; 00266 } 00267 case ECJPAKE: { 00268 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) 00269 if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, keys._priv, keys._priv_len) != 0 ){ 00270 return -1; 00271 } 00272 mbedtls_ssl_conf_ciphersuites(&sec->_conf, ECJPAKE_SUITES); 00273 00274 //NOTE: If thread starts supporting PSK in other modes, then this will be needed! 00275 mbedtls_ssl_conf_export_keys_cb(&sec->_conf, 00276 export_key_block, 00277 &sec->_keyblk); 00278 ret = 0; 00279 #endif 00280 break; 00281 } 00282 00283 default: 00284 break; 00285 } 00286 return ret; 00287 } 00288 00289 int coap_security_handler_connect(coap_security_t *sec, bool is_server, SecureSocketMode sock_mode, coap_security_keys_t keys){ 00290 int ret = -1; 00291 00292 if( !sec ){ 00293 return ret; 00294 } 00295 sec->_is_blocking = true; 00296 00297 int endpoint = MBEDTLS_SSL_IS_CLIENT; 00298 if( is_server ){ 00299 endpoint = MBEDTLS_SSL_IS_SERVER; 00300 } 00301 00302 int mode = MBEDTLS_SSL_TRANSPORT_DATAGRAM; 00303 if( sock_mode == TLS ){ 00304 mode = MBEDTLS_SSL_TRANSPORT_STREAM; 00305 } 00306 00307 if( ( mbedtls_ssl_config_defaults( &sec->_conf, 00308 endpoint, 00309 mode, 0 ) ) != 0 ) 00310 { 00311 return -1; 00312 } 00313 00314 mbedtls_ssl_set_bio( &sec->_ssl, sec, 00315 f_send, f_recv, NULL ); 00316 00317 mbedtls_ssl_set_timer_cb( &sec->_ssl, sec, set_timer, 00318 get_timer ); 00319 00320 if( coap_security_handler_configure_keys( sec, keys ) != 0 ){ 00321 return -1; 00322 } 00323 00324 #ifdef MBEDTLS_SSL_SRV_C 00325 mbedtls_ssl_conf_dtls_cookies(&sec->_conf, simple_cookie_write, 00326 simple_cookie_check, 00327 &sec->_cookie); 00328 #endif 00329 00330 sec->_is_started = true; 00331 00332 do { 00333 ret = mbedtls_ssl_handshake_step( &sec->_ssl ); 00334 if( ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ){ //cookie check failed 00335 if( is_server ){ 00336 mbedtls_ssl_session_reset(&sec->_ssl); 00337 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) 00338 if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, keys._priv, keys._priv_len) != 0 ){ 00339 return -1; 00340 } 00341 #endif 00342 ret = MBEDTLS_ERR_SSL_WANT_READ; //needed to keep doing 00343 }else{ 00344 ret = -1; 00345 } 00346 } 00347 }while( ret == MBEDTLS_ERR_SSL_WANT_READ || 00348 ret == MBEDTLS_ERR_SSL_WANT_WRITE ); 00349 00350 if( ret != 0){ 00351 ret = -1; 00352 }else{ 00353 if( mbedtls_ssl_get_verify_result( &sec->_ssl ) != 0 ) 00354 { 00355 ret = -1; 00356 } 00357 } 00358 00359 return ret; 00360 } 00361 00362 int coap_security_handler_connect_non_blocking(coap_security_t *sec, bool is_server, SecureSocketMode sock_mode, coap_security_keys_t keys, uint32_t timeout_min, uint32_t timeout_max) 00363 { 00364 00365 if( !sec ){ 00366 return -1; 00367 } 00368 sec->_is_blocking = false; 00369 00370 int endpoint = MBEDTLS_SSL_IS_CLIENT; 00371 if( is_server ){ 00372 endpoint = MBEDTLS_SSL_IS_SERVER; 00373 } 00374 00375 int mode = MBEDTLS_SSL_TRANSPORT_DATAGRAM; 00376 if( sock_mode == TLS ){ 00377 mode = MBEDTLS_SSL_TRANSPORT_STREAM; 00378 } 00379 00380 if( ( mbedtls_ssl_config_defaults( &sec->_conf, 00381 endpoint, 00382 mode, 0 ) ) != 0 ) 00383 { 00384 return -1; 00385 } 00386 00387 if(!timeout_max && !timeout_min){ 00388 mbedtls_ssl_conf_handshake_timeout( &sec->_conf, DTLS_HANDSHAKE_TIMEOUT_MIN, DTLS_HANDSHAKE_TIMEOUT_MAX ); 00389 } 00390 else{ 00391 mbedtls_ssl_conf_handshake_timeout( &sec->_conf, timeout_min, timeout_max ); 00392 } 00393 00394 mbedtls_ssl_conf_rng( &sec->_conf, mbedtls_ctr_drbg_random, &sec->_ctr_drbg ); 00395 00396 if( ( mbedtls_ssl_setup( &sec->_ssl, &sec->_conf ) ) != 0 ) 00397 { 00398 return -1; 00399 } 00400 00401 mbedtls_ssl_set_bio( &sec->_ssl, sec, 00402 f_send, f_recv, NULL ); 00403 00404 mbedtls_ssl_set_timer_cb( &sec->_ssl, sec, set_timer, 00405 get_timer ); 00406 00407 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) 00408 //TODO: Figure out better way!!! 00409 //Password should never be stored in multiple places!!! 00410 if( is_server && keys._priv_len > 0){ 00411 memcpy(sec->_pw, keys._priv, keys._priv_len); 00412 sec->_pw_len = keys._priv_len; 00413 } 00414 #endif 00415 00416 if( coap_security_handler_configure_keys( sec, keys ) != 0 ){ 00417 return -1; 00418 } 00419 00420 #ifdef MBEDTLS_SSL_SRV_C 00421 mbedtls_ssl_conf_dtls_cookies(&sec->_conf, simple_cookie_write, 00422 simple_cookie_check, 00423 &sec->_cookie); 00424 #endif 00425 00426 mbedtls_ssl_conf_min_version(&sec->_conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MAJOR_VERSION_3); 00427 mbedtls_ssl_conf_max_version(&sec->_conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MAJOR_VERSION_3); 00428 00429 sec->_is_started = true; 00430 00431 int ret = mbedtls_ssl_handshake_step( &sec->_ssl ); 00432 if( ret == 0 ){ 00433 ret = mbedtls_ssl_handshake_step( &sec->_ssl ); 00434 if( is_server && 0 == ret){ 00435 ret = coap_security_handler_continue_connecting( sec ); 00436 } 00437 } 00438 00439 if( ret >= 0){ 00440 ret = 1; 00441 }else{ 00442 ret = -1; 00443 } 00444 return ret; 00445 } 00446 00447 int coap_security_handler_continue_connecting(coap_security_t *sec){ 00448 int ret = -1; 00449 00450 while( ret != MBEDTLS_ERR_SSL_WANT_READ ){ 00451 ret = mbedtls_ssl_handshake_step( &sec->_ssl ); 00452 00453 if( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED == ret){ 00454 mbedtls_ssl_session_reset(&sec->_ssl); 00455 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) 00456 if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, sec->_pw, sec->_pw_len) != 0 ){ 00457 return -1; 00458 } 00459 #endif 00460 return 1; 00461 } 00462 else if(ret && (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)){ 00463 return ret; 00464 } 00465 00466 if( sec->_ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER ){ 00467 return 0; 00468 } 00469 } 00470 00471 if(ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE){ 00472 return 1; 00473 } 00474 00475 return -1; 00476 } 00477 00478 00479 int coap_security_handler_send_message(coap_security_t *sec, unsigned char *message, size_t len){ 00480 int ret=-1; 00481 00482 if( sec ){ 00483 do ret = mbedtls_ssl_write( &sec->_ssl, (unsigned char *) message, len ); 00484 while( ret == MBEDTLS_ERR_SSL_WANT_READ || 00485 ret == MBEDTLS_ERR_SSL_WANT_WRITE ); 00486 } 00487 00488 return ret; //bytes written 00489 } 00490 00491 int coap_security_send_close_alert(coap_security_t *sec) 00492 { 00493 if( !sec ){ 00494 return -1; 00495 } 00496 00497 if(!mbedtls_ssl_close_notify(&sec->_ssl)){ 00498 return 0; 00499 } 00500 return -1; 00501 } 00502 00503 int coap_security_handler_read(coap_security_t *sec, unsigned char* buffer, size_t len){ 00504 int ret=-1; 00505 int max_loops = 100; 00506 00507 if( sec && buffer ){ 00508 memset( buffer, 0, len ); 00509 do { 00510 ret = mbedtls_ssl_read( &sec->_ssl, buffer, len ); 00511 } while( (ret == MBEDTLS_ERR_SSL_WANT_READ || 00512 ret == MBEDTLS_ERR_SSL_WANT_WRITE) 00513 && --max_loops); 00514 } 00515 return ret; //bytes read 00516 } 00517 00518 /**** Timer functions ****/ 00519 00520 /** 00521 * Set timer function. 00522 * Called back by mbedtls when it wants to set a timer. 00523 * Accepts an intermediate and a final delay in milliseconds 00524 * If the final delay is 0, cancels the running timer. 00525 * TODO - might be better to use an event timer in conjunction with 00526 * CoAP tasklet 00527 */ 00528 static void set_timer(void *sec_obj, uint32_t int_ms, uint32_t fin_ms) 00529 { 00530 coap_security_t *sec = (coap_security_t *)sec_obj; 00531 if( sec->_start_timer_cb ){ 00532 sec->_start_timer_cb( sec->_timer_id, int_ms, fin_ms); 00533 } 00534 } 00535 00536 /** 00537 * Get timer function. 00538 * Called back by mbedtls when it wants to get a timer state. 00539 * Returns the state of the current timer 00540 * TODO - might be better to use an event timer in conjunction with 00541 * CoAP tasklet 00542 */ 00543 static int get_timer(void *sec_obj) 00544 { 00545 coap_security_t *sec = (coap_security_t *)sec_obj; 00546 if( sec->_timer_status_cb ){ 00547 return sec->_timer_status_cb(sec->_timer_id); 00548 } 00549 return -1; 00550 } 00551 00552 int f_send( void *ctx, const unsigned char *buf, size_t len){ 00553 coap_security_t *sec = (coap_security_t *)ctx; 00554 return sec->_send_cb(sec->_socket_id, sec->_remote_address, sec->_remote_port, buf, len); 00555 } 00556 00557 int f_recv(void *ctx, unsigned char *buf, size_t len){ 00558 coap_security_t *sec = (coap_security_t *)ctx; 00559 return sec->_receive_cb(sec->_socket_id, buf, len); 00560 } 00561 00562 int entropy_poll( void *ctx, unsigned char *output, size_t len, 00563 size_t *olen ) 00564 { 00565 (void)ctx; 00566 //TODO: change to more secure random 00567 randLIB_seed_random(); 00568 char *c = (char*)ns_dyn_mem_temporary_alloc(len); 00569 if( !c ){ 00570 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 00571 } 00572 memset(c, 0, len); 00573 for(uint16_t i=0; i < len; i++){ 00574 *(c + i) = (char)randLIB_get_8bit(); 00575 } 00576 memmove(output, c, len); 00577 *olen = len; 00578 00579 ns_dyn_mem_free(c); 00580 return( 0 ); 00581 }
Generated on Tue Jul 12 2022 13:15:38 by
