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.
Dependencies: MAX44000 PWM_Tone_Library nexpaq_mdk
Fork of LED_Demo 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 //TODO: Only needed for server type? 00325 mbedtls_ssl_conf_dtls_cookies(&sec->_conf, simple_cookie_write, 00326 simple_cookie_check, 00327 &sec->_cookie); 00328 00329 sec->_is_started = true; 00330 00331 do { 00332 ret = mbedtls_ssl_handshake_step( &sec->_ssl ); 00333 if( ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ){ //cookie check failed 00334 if( is_server ){ 00335 mbedtls_ssl_session_reset(&sec->_ssl); 00336 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) 00337 if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, keys._priv, keys._priv_len) != 0 ){ 00338 return -1; 00339 } 00340 #endif 00341 ret = MBEDTLS_ERR_SSL_WANT_READ; //needed to keep doing 00342 }else{ 00343 ret = -1; 00344 } 00345 } 00346 }while( ret == MBEDTLS_ERR_SSL_WANT_READ || 00347 ret == MBEDTLS_ERR_SSL_WANT_WRITE ); 00348 00349 if( ret != 0){ 00350 ret = -1; 00351 }else{ 00352 if( mbedtls_ssl_get_verify_result( &sec->_ssl ) != 0 ) 00353 { 00354 ret = -1; 00355 } 00356 } 00357 00358 return ret; 00359 } 00360 00361 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) 00362 { 00363 00364 if( !sec ){ 00365 return -1; 00366 } 00367 sec->_is_blocking = false; 00368 00369 int endpoint = MBEDTLS_SSL_IS_CLIENT; 00370 if( is_server ){ 00371 endpoint = MBEDTLS_SSL_IS_SERVER; 00372 } 00373 00374 int mode = MBEDTLS_SSL_TRANSPORT_DATAGRAM; 00375 if( sock_mode == TLS ){ 00376 mode = MBEDTLS_SSL_TRANSPORT_STREAM; 00377 } 00378 00379 if( ( mbedtls_ssl_config_defaults( &sec->_conf, 00380 endpoint, 00381 mode, 0 ) ) != 0 ) 00382 { 00383 return -1; 00384 } 00385 00386 if(!timeout_max && !timeout_min){ 00387 mbedtls_ssl_conf_handshake_timeout( &sec->_conf, DTLS_HANDSHAKE_TIMEOUT_MIN, DTLS_HANDSHAKE_TIMEOUT_MAX ); 00388 } 00389 else{ 00390 mbedtls_ssl_conf_handshake_timeout( &sec->_conf, timeout_min, timeout_max ); 00391 } 00392 00393 mbedtls_ssl_conf_rng( &sec->_conf, mbedtls_ctr_drbg_random, &sec->_ctr_drbg ); 00394 00395 if( ( mbedtls_ssl_setup( &sec->_ssl, &sec->_conf ) ) != 0 ) 00396 { 00397 return -1; 00398 } 00399 00400 mbedtls_ssl_set_bio( &sec->_ssl, sec, 00401 f_send, f_recv, NULL ); 00402 00403 mbedtls_ssl_set_timer_cb( &sec->_ssl, sec, set_timer, 00404 get_timer ); 00405 00406 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) 00407 //TODO: Figure out better way!!! 00408 //Password should never be stored in multiple places!!! 00409 if( is_server && keys._priv_len > 0){ 00410 memcpy(sec->_pw, keys._priv, keys._priv_len); 00411 sec->_pw_len = keys._priv_len; 00412 } 00413 #endif 00414 00415 if( coap_security_handler_configure_keys( sec, keys ) != 0 ){ 00416 return -1; 00417 } 00418 00419 //Only needed for server type? 00420 mbedtls_ssl_conf_dtls_cookies(&sec->_conf, simple_cookie_write, 00421 simple_cookie_check, 00422 &sec->_cookie); 00423 00424 mbedtls_ssl_conf_min_version(&sec->_conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MAJOR_VERSION_3); 00425 mbedtls_ssl_conf_max_version(&sec->_conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MAJOR_VERSION_3); 00426 00427 sec->_is_started = true; 00428 00429 int ret = mbedtls_ssl_handshake_step( &sec->_ssl ); 00430 if( ret == 0 ){ 00431 ret = mbedtls_ssl_handshake_step( &sec->_ssl ); 00432 if( is_server && 0 == ret){ 00433 ret = coap_security_handler_continue_connecting( sec ); 00434 } 00435 } 00436 00437 if( ret >= 0){ 00438 ret = 1; 00439 }else{ 00440 ret = -1; 00441 } 00442 return ret; 00443 } 00444 00445 int coap_security_handler_continue_connecting(coap_security_t *sec){ 00446 int ret = -1; 00447 00448 while( ret != MBEDTLS_ERR_SSL_WANT_READ ){ 00449 ret = mbedtls_ssl_handshake_step( &sec->_ssl ); 00450 00451 if( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED == ret){ 00452 mbedtls_ssl_session_reset(&sec->_ssl); 00453 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) 00454 if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, sec->_pw, sec->_pw_len) != 0 ){ 00455 return -1; 00456 } 00457 #endif 00458 return 1; 00459 } 00460 else if(ret && (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)){ 00461 return ret; 00462 } 00463 00464 if( sec->_ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER ){ 00465 return 0; 00466 } 00467 } 00468 00469 if(ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE){ 00470 return 1; 00471 } 00472 00473 return -1; 00474 } 00475 00476 00477 int coap_security_handler_send_message(coap_security_t *sec, unsigned char *message, size_t len){ 00478 int ret=-1; 00479 00480 if( sec ){ 00481 do ret = mbedtls_ssl_write( &sec->_ssl, (unsigned char *) message, len ); 00482 while( ret == MBEDTLS_ERR_SSL_WANT_READ || 00483 ret == MBEDTLS_ERR_SSL_WANT_WRITE ); 00484 } 00485 00486 return ret; //bytes written 00487 } 00488 00489 int coap_security_send_close_alert(coap_security_t *sec) 00490 { 00491 if( !sec ){ 00492 return -1; 00493 } 00494 00495 if(!mbedtls_ssl_close_notify(&sec->_ssl)){ 00496 return 0; 00497 } 00498 return -1; 00499 } 00500 00501 int coap_security_handler_read(coap_security_t *sec, unsigned char* buffer, size_t len){ 00502 int ret=-1; 00503 int max_loops = 100; 00504 00505 if( sec && buffer ){ 00506 memset( buffer, 0, len ); 00507 do { 00508 ret = mbedtls_ssl_read( &sec->_ssl, buffer, len ); 00509 } while( (ret == MBEDTLS_ERR_SSL_WANT_READ || 00510 ret == MBEDTLS_ERR_SSL_WANT_WRITE) 00511 && --max_loops); 00512 } 00513 return ret; //bytes read 00514 } 00515 00516 /**** Timer functions ****/ 00517 00518 /** 00519 * Set timer function. 00520 * Called back by mbedtls when it wants to set a timer. 00521 * Accepts an intermediate and a final delay in milliseconds 00522 * If the final delay is 0, cancels the running timer. 00523 * TODO - might be better to use an event timer in conjunction with 00524 * CoAP tasklet 00525 */ 00526 static void set_timer(void *sec_obj, uint32_t int_ms, uint32_t fin_ms) 00527 { 00528 coap_security_t *sec = (coap_security_t *)sec_obj; 00529 if( sec->_start_timer_cb ){ 00530 sec->_start_timer_cb( sec->_timer_id, int_ms, fin_ms); 00531 } 00532 } 00533 00534 /** 00535 * Get timer function. 00536 * Called back by mbedtls when it wants to get a timer state. 00537 * Returns the state of the current timer 00538 * TODO - might be better to use an event timer in conjunction with 00539 * CoAP tasklet 00540 */ 00541 static int get_timer(void *sec_obj) 00542 { 00543 coap_security_t *sec = (coap_security_t *)sec_obj; 00544 if( sec->_timer_status_cb ){ 00545 return sec->_timer_status_cb(sec->_timer_id); 00546 } 00547 return -1; 00548 } 00549 00550 int f_send( void *ctx, const unsigned char *buf, size_t len){ 00551 coap_security_t *sec = (coap_security_t *)ctx; 00552 return sec->_send_cb(sec->_socket_id, sec->_remote_address, sec->_remote_port, buf, len); 00553 } 00554 00555 int f_recv(void *ctx, unsigned char *buf, size_t len){ 00556 coap_security_t *sec = (coap_security_t *)ctx; 00557 return sec->_receive_cb(sec->_socket_id, buf, len); 00558 } 00559 00560 int entropy_poll( void *ctx, unsigned char *output, size_t len, 00561 size_t *olen ) 00562 { 00563 (void)ctx; 00564 //TODO: change to more secure random 00565 randLIB_seed_random(); 00566 char *c = (char*)ns_dyn_mem_temporary_alloc(len); 00567 if( !c ){ 00568 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 00569 } 00570 memset(c, 0, len); 00571 for(uint16_t i=0; i < len; i++){ 00572 *(c + i) = (char)randLIB_get_8bit(); 00573 } 00574 memmove(output, c, len); 00575 *olen = len; 00576 00577 ns_dyn_mem_free(c); 00578 return( 0 ); 00579 }
Generated on Tue Jul 12 2022 12:28:28 by
