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.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
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 { 00098 const char *pers = "dtls_client"; 00099 #ifdef COAP_SERVICE_PROVIDE_STRONG_ENTROPY_SOURCE 00100 const int entropy_source_type = MBEDTLS_ENTROPY_SOURCE_STRONG; 00101 #else 00102 const int entropy_source_type = MBEDTLS_ENTROPY_SOURCE_WEAK; 00103 #endif 00104 00105 #if defined(MBEDTLS_PLATFORM_C) 00106 if (mbedtls_platform_setup(NULL) != 0) { 00107 return -1; 00108 } 00109 #endif /* MBEDTLS_PLATFORM_C */ 00110 00111 mbedtls_ssl_init(&sec->_ssl); 00112 mbedtls_ssl_config_init(&sec->_conf); 00113 mbedtls_ctr_drbg_init(&sec->_ctr_drbg); 00114 mbedtls_entropy_init(&sec->_entropy); 00115 00116 #if defined(MBEDTLS_X509_CRT_PARSE_C) 00117 mbedtls_x509_crt_init(&sec->_cacert); 00118 mbedtls_x509_crt_init(&sec->_owncert); 00119 mbedtls_pk_init(&sec->_pkey); 00120 #endif 00121 00122 memset(&sec->_cookie, 0, sizeof(simple_cookie_t)); 00123 memset(&sec->_keyblk, 0, sizeof(key_block_t)); 00124 00125 sec->_is_started = false; 00126 00127 if (mbedtls_entropy_add_source(&sec->_entropy, entropy_poll, NULL, 00128 128, entropy_source_type) < 0) { 00129 return -1; 00130 } 00131 00132 if ((mbedtls_ctr_drbg_seed(&sec->_ctr_drbg, mbedtls_entropy_func, &sec->_entropy, 00133 (const unsigned char *) pers, 00134 strlen(pers))) != 0) { 00135 return -1; 00136 } 00137 return 0; 00138 } 00139 00140 bool coap_security_handler_is_started(const coap_security_t *sec) 00141 { 00142 return sec->_is_started; 00143 } 00144 00145 const void *coap_security_handler_keyblock(const coap_security_t *sec) 00146 { 00147 return sec->_keyblk.value; 00148 } 00149 00150 static void coap_security_handler_reset(coap_security_t *sec) 00151 { 00152 #if defined(MBEDTLS_X509_CRT_PARSE_C) 00153 mbedtls_x509_crt_free(&sec->_cacert); 00154 mbedtls_x509_crt_free(&sec->_owncert); 00155 mbedtls_pk_free(&sec->_pkey); 00156 #endif 00157 00158 mbedtls_entropy_free(&sec->_entropy); 00159 mbedtls_ctr_drbg_free(&sec->_ctr_drbg); 00160 mbedtls_ssl_config_free(&sec->_conf); 00161 mbedtls_ssl_free(&sec->_ssl); 00162 #if defined(MBEDTLS_PLATFORM_C) 00163 mbedtls_platform_teardown(NULL); 00164 #endif /* MBEDTLS_PLATFORM_C */ 00165 } 00166 00167 00168 coap_security_t *coap_security_create(int8_t socket_id, int8_t timer_id, void *handle, SecureConnectionMode mode, 00169 send_cb *socket_cb, 00170 receive_cb *receive_data_cb, 00171 start_timer_cb *timer_start_cb, 00172 timer_status_cb *timer_stat_cb) 00173 { 00174 if (socket_cb == NULL || receive_data_cb == NULL || timer_start_cb == NULL || timer_stat_cb == NULL) { 00175 return NULL; 00176 } 00177 coap_security_t *this = ns_dyn_mem_alloc(sizeof(coap_security_t)); 00178 if (!this) { 00179 return NULL; 00180 } 00181 memset(this, 0, sizeof(coap_security_t)); 00182 if (-1 == coap_security_handler_init(this)) { 00183 ns_dyn_mem_free(this); 00184 return NULL; 00185 } 00186 this->_handle = handle; 00187 this->_conn_mode = mode; 00188 memset(this->_pw, 0, 64); 00189 this->_pw_len = 0; 00190 this->_socket_id = socket_id; 00191 this->_timer_id = timer_id; 00192 this->_send_cb = socket_cb; 00193 this->_receive_cb = receive_data_cb; 00194 this->_start_timer_cb = timer_start_cb; 00195 this->_timer_status_cb = timer_stat_cb; 00196 00197 return this; 00198 } 00199 00200 void coap_security_destroy(coap_security_t *sec) 00201 { 00202 if (sec) { 00203 coap_security_handler_reset(sec); 00204 ns_dyn_mem_free(sec); 00205 sec = NULL; 00206 } 00207 } 00208 00209 #ifdef MBEDTLS_SSL_SRV_C 00210 /**** Random number functions ****/ 00211 00212 /** 00213 * Get a random array of bytes. 00214 * Called back by mbedtls when it wants to fill a buffer with random data 00215 * Must return 0 on success. 00216 */ 00217 static int get_random(void *ctx, unsigned char *buf, size_t len) 00218 { 00219 static int initialised = 0; 00220 uint32_t i; 00221 00222 (void)ctx; /* No context */ 00223 00224 if (!initialised) { 00225 randLIB_seed_random(); 00226 initialised = 1; 00227 } 00228 00229 for (i = 0; i < len; i++) { 00230 buf[i] = (uint8_t)randLIB_get_8bit(); 00231 } 00232 return 0; /* Success */ 00233 } 00234 00235 /**** Cookie functions ****/ 00236 static int simple_cookie_write(void *ctx, 00237 unsigned char **p, unsigned char *end, 00238 const unsigned char *info, size_t ilen) 00239 { 00240 //TODO: As per RFC 6347 cookie must be stateless. This is not the case in here! 00241 //This should be fixed if we see that dos attack would be an issue. 00242 //this is proposed solution in RFC: Cookie = HMAC(Secret, Client-IP, Client-Parameters) 00243 //Secret is generated here and oftenly changed to prevent statistical attack 00244 simple_cookie_t *p_cookie = (simple_cookie_t *)ctx; 00245 00246 /* Not using additional info */ 00247 (void)info; 00248 (void)ilen; 00249 00250 if ((size_t)(end - *p) < COOKIE_SIMPLE_LEN) { 00251 return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL; 00252 } 00253 00254 /* Use a simple random number of length COOKIE_SIMPLE_LEN bytes */ 00255 get_random(NULL, p_cookie->value, COOKIE_SIMPLE_LEN); 00256 memcpy(*p, p_cookie->value, COOKIE_SIMPLE_LEN); 00257 p_cookie->len = COOKIE_SIMPLE_LEN; 00258 *p += COOKIE_SIMPLE_LEN; 00259 return 0; 00260 } 00261 00262 static int simple_cookie_check(void *ctx, 00263 const unsigned char *cookie, size_t clen, 00264 const unsigned char *info, size_t ilen) 00265 { 00266 simple_cookie_t *p_cookie = (simple_cookie_t *)ctx; 00267 00268 /* Not using additional info */ 00269 (void)info; 00270 (void)ilen; 00271 00272 if ((p_cookie->len == 0) || 00273 (clen != p_cookie->len) || 00274 (memcmp(cookie, p_cookie->value, p_cookie->len) != 0)) { 00275 return -1; /* This is what it is in mbedtls... */ 00276 } 00277 return 0; 00278 } 00279 #endif // MBEDTLS_SSL_SRV_C 00280 00281 /**** Key export function ****/ 00282 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) 00283 static int export_key_block(void *ctx, 00284 const unsigned char *mk, const unsigned char *kb, 00285 size_t maclen, size_t keylen, size_t ivlen) 00286 { 00287 key_block_t *p_key_block = (key_block_t *)ctx; 00288 00289 /* Not using master key */ 00290 (void)mk; 00291 00292 /* Sanity check MAC and key lengths */ 00293 if ((maclen != 0) || (((2 * keylen) + (2 * ivlen)) != KEY_BLOCK_LEN)) { 00294 return -1; /* Something seriously wrong! */ 00295 } 00296 00297 /* Copy the key block we are using */ 00298 /* No need to skip over MAC keys, MAC len must be 0 if we are here */ 00299 memcpy(p_key_block->value, kb /* + (2 * maclen)*/, (2 * keylen) + (2 * ivlen)); 00300 return 0; 00301 } 00302 #endif 00303 00304 static int coap_security_handler_configure_keys(coap_security_t *sec, coap_security_keys_t keys, bool is_server) 00305 { 00306 (void) is_server; 00307 00308 int ret = -1; 00309 switch (sec->_conn_mode) { 00310 case CERTIFICATE: { 00311 #if defined(MBEDTLS_X509_CRT_PARSE_C) 00312 if (keys._cert && mbedtls_x509_crt_parse(&sec->_owncert, keys._cert, keys._cert_len) < 0) { 00313 break; 00314 } 00315 00316 if (mbedtls_pk_parse_key(&sec->_pkey, keys._priv_key, keys._priv_key_len, NULL, 0) < 0) { 00317 break; 00318 } 00319 00320 if (0 != mbedtls_ssl_conf_own_cert(&sec->_conf, &sec->_owncert, &sec->_pkey)) { 00321 break; 00322 } 00323 00324 mbedtls_ssl_conf_authmode(&sec->_conf, MBEDTLS_SSL_VERIFY_NONE); 00325 mbedtls_ssl_conf_ca_chain(&sec->_conf, &sec->_owncert, NULL); 00326 ret = 0; 00327 #endif 00328 break; 00329 } 00330 case PSK: { 00331 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) 00332 if (0 != mbedtls_ssl_conf_psk(&sec->_conf, keys._priv_key, keys._priv_key_len, keys._cert, keys._cert_len)) { 00333 break; 00334 } 00335 mbedtls_ssl_conf_ciphersuites(&sec->_conf, PSK_SUITES); 00336 ret = 0; 00337 #endif 00338 break; 00339 } 00340 case ECJPAKE: { 00341 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) 00342 if (mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, keys._key, keys._key_len) != 0) { 00343 return -1; 00344 } 00345 mbedtls_ssl_conf_ciphersuites(&sec->_conf, ECJPAKE_SUITES); 00346 00347 //NOTE: If thread starts supporting PSK in other modes, then this will be needed! 00348 mbedtls_ssl_conf_export_keys_cb(&sec->_conf, 00349 export_key_block, 00350 &sec->_keyblk); 00351 ret = 0; 00352 #endif 00353 break; 00354 } 00355 00356 default: 00357 break; 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 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 return -1; 00383 } 00384 00385 if (!timeout_max && !timeout_min) { 00386 mbedtls_ssl_conf_handshake_timeout(&sec->_conf, DTLS_HANDSHAKE_TIMEOUT_MIN, DTLS_HANDSHAKE_TIMEOUT_MAX); 00387 } else { 00388 mbedtls_ssl_conf_handshake_timeout(&sec->_conf, timeout_min, timeout_max); 00389 } 00390 00391 mbedtls_ssl_conf_rng(&sec->_conf, mbedtls_ctr_drbg_random, &sec->_ctr_drbg); 00392 00393 if ((mbedtls_ssl_setup(&sec->_ssl, &sec->_conf)) != 0) { 00394 return -1; 00395 } 00396 00397 mbedtls_ssl_set_bio(&sec->_ssl, sec, 00398 f_send, f_recv, NULL); 00399 00400 mbedtls_ssl_set_timer_cb(&sec->_ssl, sec, set_timer, 00401 get_timer); 00402 00403 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) 00404 //TODO: Figure out better way!!! 00405 //Password should never be stored in multiple places!!! 00406 if ((sec->_conn_mode == ECJPAKE) && is_server && keys._key_len > 0) { 00407 memcpy(sec->_pw, keys._key, keys._key_len); 00408 sec->_pw_len = keys._key_len; 00409 } 00410 #endif 00411 00412 if (coap_security_handler_configure_keys(sec, keys, is_server) != 0) { 00413 tr_debug("security credential configure failed"); 00414 return -1; 00415 } 00416 00417 #ifdef MBEDTLS_SSL_SRV_C 00418 mbedtls_ssl_conf_dtls_cookies(&sec->_conf, simple_cookie_write, 00419 simple_cookie_check, 00420 &sec->_cookie); 00421 #endif 00422 00423 mbedtls_ssl_conf_min_version(&sec->_conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MAJOR_VERSION_3); 00424 mbedtls_ssl_conf_max_version(&sec->_conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MAJOR_VERSION_3); 00425 00426 sec->_is_started = true; 00427 00428 int ret = mbedtls_ssl_handshake_step(&sec->_ssl); 00429 if (ret == 0) { 00430 ret = mbedtls_ssl_handshake_step(&sec->_ssl); 00431 if (is_server && 0 == ret) { 00432 ret = coap_security_handler_continue_connecting(sec); 00433 } 00434 } 00435 00436 if (ret >= 0) { 00437 ret = 1; 00438 } else { 00439 ret = -1; 00440 } 00441 return ret; 00442 } 00443 00444 int coap_security_handler_continue_connecting(coap_security_t *sec) 00445 { 00446 int ret = -1; 00447 00448 while (ret != MBEDTLS_ERR_SSL_WANT_READ) { 00449 ret = mbedtls_ssl_handshake_step(&sec->_ssl); 00450 if (MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED == ret) { 00451 mbedtls_ssl_session_reset(&sec->_ssl); 00452 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) 00453 if (mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, sec->_pw, sec->_pw_len) != 0) { 00454 return -1; 00455 } 00456 #endif 00457 return 1; 00458 } else if (ret && (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)) { 00459 return ret; 00460 } 00461 00462 if (sec->_ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER) { 00463 return 0; 00464 } 00465 } 00466 00467 if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) { 00468 return 1; 00469 } 00470 00471 return -1; 00472 } 00473 00474 00475 int coap_security_handler_send_message(coap_security_t *sec, unsigned char *message, size_t len) 00476 { 00477 int ret = -1; 00478 00479 if (sec) { 00480 do { 00481 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 { 00503 int ret = -1; 00504 int max_loops = 100; 00505 00506 if (sec && buffer) { 00507 memset(buffer, 0, len); 00508 do { 00509 ret = mbedtls_ssl_read(&sec->_ssl, buffer, len); 00510 } while ((ret == MBEDTLS_ERR_SSL_WANT_READ || 00511 ret == MBEDTLS_ERR_SSL_WANT_WRITE) 00512 && --max_loops); 00513 } 00514 return ret; //bytes read 00515 } 00516 00517 /**** Timer functions ****/ 00518 00519 /** 00520 * Set timer function. 00521 * Called back by mbedtls when it wants to set a timer. 00522 * Accepts an intermediate and a final delay in milliseconds 00523 * If the final delay is 0, cancels the running timer. 00524 * TODO - might be better to use an event timer in conjunction with 00525 * CoAP tasklet 00526 */ 00527 static void set_timer(void *sec_obj, uint32_t int_ms, uint32_t fin_ms) 00528 { 00529 coap_security_t *sec = (coap_security_t *)sec_obj; 00530 if (sec->_start_timer_cb) { 00531 sec->_start_timer_cb(sec->_timer_id, int_ms, fin_ms); 00532 } 00533 } 00534 00535 /** 00536 * Get timer function. 00537 * Called back by mbedtls when it wants to get a timer state. 00538 * Returns the state of the current timer 00539 * TODO - might be better to use an event timer in conjunction with 00540 * CoAP tasklet 00541 */ 00542 static int get_timer(void *sec_obj) 00543 { 00544 coap_security_t *sec = (coap_security_t *)sec_obj; 00545 if (sec->_timer_status_cb) { 00546 return sec->_timer_status_cb(sec->_timer_id); 00547 } 00548 return -1; 00549 } 00550 00551 int f_send(void *ctx, const unsigned char *buf, size_t len) 00552 { 00553 coap_security_t *sec = (coap_security_t *)ctx; 00554 return sec->_send_cb(sec->_socket_id, sec->_handle, buf, len); 00555 } 00556 00557 int f_recv(void *ctx, unsigned char *buf, size_t len) 00558 { 00559 coap_security_t *sec = (coap_security_t *)ctx; 00560 return sec->_receive_cb(sec->_socket_id, buf, len); 00561 } 00562 00563 int entropy_poll(void *ctx, unsigned char *output, size_t len, 00564 size_t *olen) 00565 { 00566 (void)ctx; 00567 //TODO: change to more secure random 00568 randLIB_seed_random(); 00569 char *c = (char *)ns_dyn_mem_temporary_alloc(len); 00570 if (!c) { 00571 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 00572 } 00573 memset(c, 0, len); 00574 for (uint16_t i = 0; i < len; i++) { 00575 *(c + i) = (char)randLIB_get_8bit(); 00576 } 00577 memmove(output, c, len); 00578 *olen = len; 00579 00580 ns_dyn_mem_free(c); 00581 return (0); 00582 } 00583 00584 #endif // COAP_SECURITY_AVAILABLE
Generated on Tue Jul 12 2022 13:54:12 by
1.7.2