Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers coap_security_handler.c Source File

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