Nicolas Borla / Mbed OS BBR_1Ebene
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 #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