Knight KE / Mbed OS Game_Master
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     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