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 #endif 00055 mbedtls_pk_context _pkey; 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 #endif 00113 mbedtls_pk_init( &sec->_pkey ); 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 #endif 00149 00150 mbedtls_pk_free(&sec->_pkey); 00151 00152 mbedtls_entropy_free( &sec->_entropy ); 00153 mbedtls_ctr_drbg_free( &sec->_ctr_drbg ); 00154 mbedtls_ssl_config_free(&sec->_conf); 00155 mbedtls_ssl_free(&sec->_ssl); 00156 } 00157 00158 00159 coap_security_t *coap_security_create(int8_t socket_id, int8_t timer_id, void *handle, SecureConnectionMode mode, 00160 send_cb *socket_cb, 00161 receive_cb *receive_data_cb, 00162 start_timer_cb *timer_start_cb, 00163 timer_status_cb *timer_stat_cb) 00164 { 00165 if (socket_cb == NULL || receive_data_cb == NULL || timer_start_cb == NULL || timer_stat_cb == NULL) { 00166 return NULL; 00167 } 00168 coap_security_t *this = ns_dyn_mem_alloc(sizeof(coap_security_t)); 00169 if( !this ){ 00170 return NULL; 00171 } 00172 memset(this, 0, sizeof(coap_security_t)); 00173 if (-1 == coap_security_handler_init(this)) { 00174 ns_dyn_mem_free(this); 00175 return NULL; 00176 } 00177 this->_handle = handle; 00178 this->_conn_mode = mode; 00179 memset(this->_pw, 0, 64); 00180 this->_pw_len = 0; 00181 this->_socket_id = socket_id; 00182 this->_timer_id = timer_id; 00183 this->_send_cb = socket_cb; 00184 this->_receive_cb = receive_data_cb; 00185 this->_start_timer_cb = timer_start_cb; 00186 this->_timer_status_cb = timer_stat_cb; 00187 00188 return this; 00189 } 00190 00191 void coap_security_destroy(coap_security_t *sec){ 00192 if( sec ){ 00193 coap_security_handler_reset(sec); 00194 ns_dyn_mem_free(sec); 00195 sec = NULL; 00196 } 00197 } 00198 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 00269 /**** Key export function ****/ 00270 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) 00271 static int export_key_block(void *ctx, 00272 const unsigned char *mk, const unsigned char *kb, 00273 size_t maclen, size_t keylen, size_t ivlen) 00274 { 00275 key_block_t *p_key_block = (key_block_t *)ctx; 00276 00277 /* Not using master key */ 00278 (void)mk; 00279 00280 /* Sanity check MAC and key lengths */ 00281 if ((maclen != 0) || (((2 * keylen) + (2 * ivlen)) != KEY_BLOCK_LEN)) { 00282 return -1; /* Something seriously wrong! */ 00283 } 00284 00285 /* Copy the key block we are using */ 00286 /* No need to skip over MAC keys, MAC len must be 0 if we are here */ 00287 memcpy(p_key_block->value, kb /* + (2 * maclen)*/, (2 * keylen) + (2 * ivlen)); 00288 return 0; 00289 } 00290 #endif 00291 00292 static int coap_security_handler_configure_keys (coap_security_t *sec, coap_security_keys_t keys, bool is_server) 00293 { 00294 (void) is_server; 00295 00296 int ret = -1; 00297 switch( sec->_conn_mode ){ 00298 case CERTIFICATE:{ 00299 #if defined(MBEDTLS_X509_CRT_PARSE_C) 00300 if( keys._cert && mbedtls_x509_crt_parse( &sec->_owncert, keys._cert, keys._cert_len ) < 0 ){ 00301 break; 00302 } 00303 00304 if( mbedtls_pk_parse_key(&sec->_pkey, keys._priv_key, keys._priv_key_len, NULL, 0) < 0){ 00305 break; 00306 } 00307 00308 if (0 != mbedtls_ssl_conf_own_cert(&sec->_conf, &sec->_owncert, &sec->_pkey)) { 00309 break; 00310 } 00311 00312 mbedtls_ssl_conf_authmode( &sec->_conf, MBEDTLS_SSL_VERIFY_NONE ); 00313 mbedtls_ssl_conf_ca_chain( &sec->_conf, &sec->_owncert, NULL ); 00314 ret = 0; 00315 #endif 00316 break; 00317 } 00318 case PSK: { 00319 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) 00320 if( 0 != mbedtls_ssl_conf_psk(&sec->_conf, keys._priv_key, keys._priv_key_len, keys._cert, keys._cert_len) ){ 00321 break; 00322 } 00323 mbedtls_ssl_conf_ciphersuites(&sec->_conf, PSK_SUITES); 00324 ret = 0; 00325 #endif 00326 break; 00327 } 00328 case ECJPAKE: { 00329 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) 00330 if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, keys._key, keys._key_len) != 0 ){ 00331 return -1; 00332 } 00333 mbedtls_ssl_conf_ciphersuites(&sec->_conf, ECJPAKE_SUITES); 00334 00335 //NOTE: If thread starts supporting PSK in other modes, then this will be needed! 00336 mbedtls_ssl_conf_export_keys_cb(&sec->_conf, 00337 export_key_block, 00338 &sec->_keyblk); 00339 ret = 0; 00340 #endif 00341 break; 00342 } 00343 00344 default: 00345 break; 00346 } 00347 return ret; 00348 } 00349 00350 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) 00351 { 00352 if( !sec ){ 00353 return -1; 00354 } 00355 sec->_is_blocking = false; 00356 00357 int endpoint = MBEDTLS_SSL_IS_CLIENT; 00358 if( is_server ){ 00359 endpoint = MBEDTLS_SSL_IS_SERVER; 00360 } 00361 00362 int mode = MBEDTLS_SSL_TRANSPORT_DATAGRAM; 00363 if( sock_mode == TLS ){ 00364 mode = MBEDTLS_SSL_TRANSPORT_STREAM; 00365 } 00366 00367 if( ( mbedtls_ssl_config_defaults( &sec->_conf, 00368 endpoint, 00369 mode, 0 ) ) != 0 ) 00370 { 00371 return -1; 00372 } 00373 00374 if(!timeout_max && !timeout_min){ 00375 mbedtls_ssl_conf_handshake_timeout( &sec->_conf, DTLS_HANDSHAKE_TIMEOUT_MIN, DTLS_HANDSHAKE_TIMEOUT_MAX ); 00376 } 00377 else{ 00378 mbedtls_ssl_conf_handshake_timeout( &sec->_conf, timeout_min, timeout_max ); 00379 } 00380 00381 mbedtls_ssl_conf_rng( &sec->_conf, mbedtls_ctr_drbg_random, &sec->_ctr_drbg ); 00382 00383 if( ( mbedtls_ssl_setup( &sec->_ssl, &sec->_conf ) ) != 0 ) 00384 { 00385 return -1; 00386 } 00387 00388 mbedtls_ssl_set_bio( &sec->_ssl, sec, 00389 f_send, f_recv, NULL ); 00390 00391 mbedtls_ssl_set_timer_cb( &sec->_ssl, sec, set_timer, 00392 get_timer ); 00393 00394 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) 00395 //TODO: Figure out better way!!! 00396 //Password should never be stored in multiple places!!! 00397 if ((sec->_conn_mode == ECJPAKE) && is_server && keys._key_len > 0){ 00398 memcpy(sec->_pw, keys._key, keys._key_len); 00399 sec->_pw_len = keys._key_len; 00400 } 00401 #endif 00402 00403 if (coap_security_handler_configure_keys(sec, keys, is_server) != 0) { 00404 tr_debug("security credential configure failed"); 00405 return -1; 00406 } 00407 00408 #ifdef MBEDTLS_SSL_SRV_C 00409 mbedtls_ssl_conf_dtls_cookies(&sec->_conf, simple_cookie_write, 00410 simple_cookie_check, 00411 &sec->_cookie); 00412 #endif 00413 00414 mbedtls_ssl_conf_min_version(&sec->_conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MAJOR_VERSION_3); 00415 mbedtls_ssl_conf_max_version(&sec->_conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MAJOR_VERSION_3); 00416 00417 sec->_is_started = true; 00418 00419 int ret = mbedtls_ssl_handshake_step( &sec->_ssl ); 00420 if( ret == 0 ){ 00421 ret = mbedtls_ssl_handshake_step( &sec->_ssl ); 00422 if( is_server && 0 == ret){ 00423 ret = coap_security_handler_continue_connecting( sec ); 00424 } 00425 } 00426 00427 if( ret >= 0){ 00428 ret = 1; 00429 }else{ 00430 ret = -1; 00431 } 00432 return ret; 00433 } 00434 00435 int coap_security_handler_continue_connecting(coap_security_t *sec){ 00436 int ret = -1; 00437 00438 while( ret != MBEDTLS_ERR_SSL_WANT_READ ){ 00439 ret = mbedtls_ssl_handshake_step( &sec->_ssl ); 00440 if( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED == ret){ 00441 mbedtls_ssl_session_reset(&sec->_ssl); 00442 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) 00443 if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, sec->_pw, sec->_pw_len) != 0 ){ 00444 return -1; 00445 } 00446 #endif 00447 return 1; 00448 } 00449 else if(ret && (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)){ 00450 return ret; 00451 } 00452 00453 if( sec->_ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER ){ 00454 return 0; 00455 } 00456 } 00457 00458 if(ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE){ 00459 return 1; 00460 } 00461 00462 return -1; 00463 } 00464 00465 00466 int coap_security_handler_send_message(coap_security_t *sec, unsigned char *message, size_t len){ 00467 int ret=-1; 00468 00469 if( sec ){ 00470 do ret = mbedtls_ssl_write( &sec->_ssl, (unsigned char *) message, len ); 00471 while( ret == MBEDTLS_ERR_SSL_WANT_READ || 00472 ret == MBEDTLS_ERR_SSL_WANT_WRITE ); 00473 } 00474 00475 return ret; //bytes written 00476 } 00477 00478 int coap_security_send_close_alert(coap_security_t *sec) 00479 { 00480 if( !sec ){ 00481 return -1; 00482 } 00483 00484 if(!mbedtls_ssl_close_notify(&sec->_ssl)){ 00485 return 0; 00486 } 00487 return -1; 00488 } 00489 00490 int coap_security_handler_read(coap_security_t *sec, unsigned char* buffer, size_t len){ 00491 int ret=-1; 00492 int max_loops = 100; 00493 00494 if( sec && buffer ){ 00495 memset( buffer, 0, len ); 00496 do { 00497 ret = mbedtls_ssl_read( &sec->_ssl, buffer, len ); 00498 } while( (ret == MBEDTLS_ERR_SSL_WANT_READ || 00499 ret == MBEDTLS_ERR_SSL_WANT_WRITE) 00500 && --max_loops); 00501 } 00502 return ret; //bytes read 00503 } 00504 00505 /**** Timer functions ****/ 00506 00507 /** 00508 * Set timer function. 00509 * Called back by mbedtls when it wants to set a timer. 00510 * Accepts an intermediate and a final delay in milliseconds 00511 * If the final delay is 0, cancels the running timer. 00512 * TODO - might be better to use an event timer in conjunction with 00513 * CoAP tasklet 00514 */ 00515 static void set_timer(void *sec_obj, uint32_t int_ms, uint32_t fin_ms) 00516 { 00517 coap_security_t *sec = (coap_security_t *)sec_obj; 00518 if( sec->_start_timer_cb ){ 00519 sec->_start_timer_cb( sec->_timer_id, int_ms, fin_ms); 00520 } 00521 } 00522 00523 /** 00524 * Get timer function. 00525 * Called back by mbedtls when it wants to get a timer state. 00526 * Returns the state of the current timer 00527 * TODO - might be better to use an event timer in conjunction with 00528 * CoAP tasklet 00529 */ 00530 static int get_timer(void *sec_obj) 00531 { 00532 coap_security_t *sec = (coap_security_t *)sec_obj; 00533 if( sec->_timer_status_cb ){ 00534 return sec->_timer_status_cb(sec->_timer_id); 00535 } 00536 return -1; 00537 } 00538 00539 int f_send( void *ctx, const unsigned char *buf, size_t len){ 00540 coap_security_t *sec = (coap_security_t *)ctx; 00541 return sec->_send_cb(sec->_socket_id, sec->_handle, buf, len); 00542 } 00543 00544 int f_recv(void *ctx, unsigned char *buf, size_t len){ 00545 coap_security_t *sec = (coap_security_t *)ctx; 00546 return sec->_receive_cb(sec->_socket_id, buf, len); 00547 } 00548 00549 int entropy_poll( void *ctx, unsigned char *output, size_t len, 00550 size_t *olen ) 00551 { 00552 (void)ctx; 00553 //TODO: change to more secure random 00554 randLIB_seed_random(); 00555 char *c = (char*)ns_dyn_mem_temporary_alloc(len); 00556 if( !c ){ 00557 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 00558 } 00559 memset(c, 0, len); 00560 for(uint16_t i=0; i < len; i++){ 00561 *(c + i) = (char)randLIB_get_8bit(); 00562 } 00563 memmove(output, c, len); 00564 *olen = len; 00565 00566 ns_dyn_mem_free(c); 00567 return( 0 ); 00568 } 00569 00570 #endif // COAP_SECURITY_AVAILABLE
Generated on Tue Jul 12 2022 18:18:29 by
