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