joey shelton / LED_Demo

Dependencies:   MAX44000 PWM_Tone_Library nexpaq_mdk

Fork of LED_Demo by Maxim nexpaq

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-2016 ARM Limited. All Rights Reserved.
00003  */
00004 
00005 #include <string.h>
00006 #include <time.h>
00007 #include <stdlib.h>
00008 
00009 #include "mbedtls/sha256.h"
00010 #include "mbedtls/error.h"
00011 #include "mbedtls/platform.h"
00012 #include "mbedtls/ssl_cookie.h"
00013 #include "mbedtls/entropy_poll.h"
00014 #include "mbedtls/ssl.h"
00015 #include "ns_trace.h"
00016 #include "nsdynmemLIB.h"
00017 #include "coap_connection_handler.h"
00018 #include "coap_security_handler.h"
00019 #include "randLIB.h"
00020 #include "mbedtls/ssl_ciphersuites.h"
00021 
00022 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
00023 const int ECJPAKE_SUITES[] = {
00024     MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8,
00025     0
00026 };
00027 #endif
00028 
00029 static const int PSK_SUITES[] = {
00030     MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256,
00031     MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8,
00032     MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8,
00033     0
00034 };
00035 
00036 
00037 static void set_timer( void *sec_obj, uint32_t int_ms, uint32_t fin_ms );
00038 static int get_timer( void *sec_obj );
00039 static int coap_security_handler_configure_keys( coap_security_t *sec, coap_security_keys_t keys );
00040 
00041 int entropy_poll( void *data, unsigned char *output, size_t len, size_t *olen );
00042 //Point these back to M2MConnectionHandler!!!
00043 int f_send( void *ctx, const unsigned char *buf, size_t len );
00044 int f_recv(void *ctx, unsigned char *buf, size_t len);
00045 
00046 static int coap_security_handler_init(coap_security_t *sec){
00047     const char *pers = "dtls_client";
00048     mbedtls_ssl_init( &sec->_ssl );
00049     mbedtls_ssl_config_init( &sec->_conf );
00050     mbedtls_ctr_drbg_init( &sec->_ctr_drbg );
00051     mbedtls_entropy_init( &sec->_entropy );
00052 
00053 #if defined(MBEDTLS_X509_CRT_PARSE_C)
00054     mbedtls_x509_crt_init( &sec->_cacert );
00055     mbedtls_x509_crt_init( &sec->_owncert );
00056 #endif
00057     mbedtls_pk_init( &sec->_pkey );
00058 
00059     memset(&sec->_cookie, 0, sizeof(simple_cookie_t));
00060     memset(&sec->_keyblk, 0, sizeof(key_block_t));
00061 
00062     sec->_is_started = false;
00063 
00064     //TODO: Must have at least 1 strong entropy source, otherwise DTLS will fail.
00065     //This is NOT strong even we say it is!
00066     if( mbedtls_entropy_add_source( &sec->_entropy, entropy_poll, NULL,
00067                                 128, 1 ) < 0 ){
00068         return -1;
00069     }
00070 
00071     if( ( mbedtls_ctr_drbg_seed( &sec->_ctr_drbg, mbedtls_entropy_func, &sec->_entropy,
00072                                (const unsigned char *) pers,
00073                                strlen( pers ) ) ) != 0 )
00074     {
00075         return -1;
00076     }
00077     return 0;
00078 }
00079 
00080 static void coap_security_handler_reset(coap_security_t *sec){
00081 #if defined(MBEDTLS_X509_CRT_PARSE_C)
00082     mbedtls_x509_crt_free(&sec->_cacert);
00083     mbedtls_x509_crt_free(&sec->_owncert);
00084 #endif
00085 
00086     mbedtls_pk_free(&sec->_pkey);
00087 
00088     mbedtls_entropy_free( &sec->_entropy );
00089     mbedtls_ctr_drbg_free( &sec->_ctr_drbg );
00090     mbedtls_ssl_config_free(&sec->_conf);
00091     mbedtls_ssl_free(&sec->_ssl);
00092 }
00093 
00094 
00095 coap_security_t *coap_security_create(int8_t socket_id, int8_t timer_id, uint8_t *address_ptr, uint16_t port, SecureConnectionMode mode,
00096                                           send_cb *send_cb,
00097                                           receive_cb *receive_cb,
00098                                           start_timer_cb *start_timer_cb,
00099                                           timer_status_cb *timer_status_cb)
00100 {
00101     if( !address_ptr || send_cb == NULL || receive_cb == NULL || start_timer_cb == NULL || timer_status_cb == NULL){
00102         return NULL;
00103     }
00104     coap_security_t *this = ns_dyn_mem_alloc(sizeof(coap_security_t));
00105     if( !this ){
00106         return NULL;
00107     }
00108     memset(this, 0, sizeof(coap_security_t));
00109     if( -1 == coap_security_handler_init(this) ){
00110         ns_dyn_mem_free(this);
00111         return NULL;
00112     }
00113     this->_remote_port = port;
00114     memcpy(this->_remote_address, address_ptr, 16);
00115     this->_conn_mode = mode;
00116     memset(this->_pw, 0, 64);
00117     this->_pw_len = 0;
00118     this->_socket_id = socket_id;
00119     this->_timer_id = timer_id;
00120     this->_send_cb = send_cb;
00121     this->_receive_cb = receive_cb;
00122     this->_start_timer_cb = start_timer_cb;
00123     this->_timer_status_cb = timer_status_cb;
00124 
00125     return this;
00126 }
00127 
00128 void coap_security_destroy(coap_security_t *sec){
00129     if( sec ){
00130         coap_security_handler_reset(sec);
00131         ns_dyn_mem_free(sec);
00132         sec = NULL;
00133     }
00134 }
00135 
00136 /**** Random number functions ****/
00137 
00138 /**
00139  * Get a random array of bytes.
00140  * Called back by mbedtls when it wants to fill a buffer with random data
00141  * Must return 0 on success.
00142  */
00143 static int get_random(void *ctx, unsigned char *buf, size_t len)
00144 {
00145     static int initialised = 0;
00146     uint32_t i;
00147 
00148     (void)ctx; /* No context */
00149 
00150     if (!initialised) {
00151         randLIB_seed_random();
00152         initialised = 1;
00153     }
00154 
00155     for (i = 0; i < len; i++) {
00156         buf[i] = (uint8_t)randLIB_get_8bit();
00157     }
00158     return 0; /* Success */
00159 }
00160 
00161 /**** Cookie functions ****/
00162 static int simple_cookie_write(void *ctx,
00163                                unsigned char **p, unsigned char *end,
00164                                const unsigned char *info, size_t ilen)
00165 {
00166     //TODO: As per RFC 6347 cookie must be stateless. This is not the case in here!
00167     //This should be fixed if we see that dos attack would be an issue.
00168     //this is proposed solution in RFC: Cookie = HMAC(Secret, Client-IP, Client-Parameters)
00169     //Secret is generated here and oftenly changed to prevent statistical attack
00170     simple_cookie_t *p_cookie = (simple_cookie_t *)ctx;
00171 
00172     /* Not using additional info */
00173     (void)info;
00174     (void)ilen;
00175 
00176     if ((size_t)(end - *p) < COOKIE_SIMPLE_LEN) {
00177         return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL;
00178     }
00179 
00180     /* Use a simple random number of length COOKIE_SIMPLE_LEN bytes */
00181     get_random(NULL, p_cookie->value, COOKIE_SIMPLE_LEN);
00182     memcpy(*p, p_cookie->value, COOKIE_SIMPLE_LEN);
00183     p_cookie->len = COOKIE_SIMPLE_LEN;
00184     *p += COOKIE_SIMPLE_LEN;
00185     return 0;
00186 }
00187 
00188 static int simple_cookie_check(void *ctx,
00189                                const unsigned char *cookie, size_t clen,
00190                                const unsigned char *info, size_t ilen)
00191 {
00192     simple_cookie_t *p_cookie = (simple_cookie_t *)ctx;
00193 
00194     /* Not using additional info */
00195     (void)info;
00196     (void)ilen;
00197 
00198     if ((p_cookie->len == 0) ||
00199         (clen != p_cookie->len) ||
00200         (memcmp(cookie, p_cookie->value, p_cookie->len) != 0)) {
00201         return -1; /* This is what it is in mbedtls... */
00202     }
00203     return 0;
00204 }
00205 
00206 /**** Key export function ****/
00207 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
00208 static int export_key_block(void *ctx,
00209                             const unsigned char *mk, const unsigned char *kb,
00210                             size_t maclen, size_t keylen, size_t ivlen)
00211 {
00212     key_block_t *p_key_block = (key_block_t *)ctx;
00213 
00214     /* Not using master key */
00215     (void)mk;
00216 
00217     /* Sanity check MAC and key lengths */
00218     if ((maclen != 0) || (((2 * keylen) + (2 * ivlen)) != KEY_BLOCK_LEN)) {
00219         return -1; /* Something seriously wrong! */
00220     }
00221 
00222     /* Copy the key block we are using */
00223     /* No need to skip over MAC keys, MAC len must be 0 if we are here */
00224     memcpy(p_key_block->value, kb /* + (2 * maclen)*/, (2 * keylen) + (2 * ivlen));
00225     return 0;
00226 }
00227 #endif
00228 
00229 int coap_security_handler_configure_keys( coap_security_t *sec, coap_security_keys_t keys )
00230 {
00231     int ret = -1;
00232     switch( sec->_conn_mode ){
00233         case Certificate:{
00234 #if defined(MBEDTLS_X509_CRT_PARSE_C)
00235         if(  mbedtls_x509_crt_parse( &sec->_cacert, keys._server_cert,
00236                                      keys._server_cert_len ) < 0 ){
00237             break;
00238         }
00239         if( mbedtls_x509_crt_parse( &sec->_owncert, keys._pub_cert_or_identifier,
00240                                     keys._pub_len ) < 0 ){
00241             break;
00242         }
00243         if( mbedtls_pk_parse_key(&sec->_pkey, keys._priv, keys._priv_len, NULL, 0) < 0){
00244             break;
00245         }
00246         //TODO: If needed in server mode, this won't work
00247         if( 0 != mbedtls_ssl_conf_own_cert(&sec->_conf, &sec->_owncert, &sec->_pkey) ){
00248             break;
00249         }
00250         //TODO: use MBEDTLS_SSL_VERIFY_REQUIRED instead of optional
00251         mbedtls_ssl_conf_authmode( &sec->_conf, MBEDTLS_SSL_VERIFY_OPTIONAL );
00252         mbedtls_ssl_conf_ca_chain( &sec->_conf, &sec->_cacert, NULL );
00253         ret = 0;
00254 #endif
00255         break;
00256         }
00257         case PSK: {
00258 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
00259         if( 0 != mbedtls_ssl_conf_psk(&sec->_conf, keys._priv, keys._priv_len, keys._pub_cert_or_identifier, keys._pub_len) ){
00260             break;
00261         }
00262         mbedtls_ssl_conf_ciphersuites(&sec->_conf, PSK_SUITES);
00263         ret = 0;
00264 #endif
00265         break;
00266         }
00267         case ECJPAKE: {
00268 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
00269             if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, keys._priv, keys._priv_len) != 0 ){
00270                 return -1;
00271             }
00272             mbedtls_ssl_conf_ciphersuites(&sec->_conf, ECJPAKE_SUITES);
00273 
00274             //NOTE: If thread starts supporting PSK in other modes, then this will be needed!
00275             mbedtls_ssl_conf_export_keys_cb(&sec->_conf,
00276                                             export_key_block,
00277                                             &sec->_keyblk);
00278         ret = 0;
00279 #endif
00280         break;
00281         }
00282 
00283         default:
00284         break;
00285     }
00286     return ret;
00287 }
00288 
00289 int coap_security_handler_connect(coap_security_t *sec, bool is_server, SecureSocketMode sock_mode, coap_security_keys_t keys){
00290     int ret = -1;
00291 
00292     if( !sec ){
00293         return ret;
00294     }
00295     sec->_is_blocking = true;
00296 
00297     int endpoint = MBEDTLS_SSL_IS_CLIENT;
00298     if( is_server ){
00299         endpoint = MBEDTLS_SSL_IS_SERVER;
00300     }
00301 
00302     int mode = MBEDTLS_SSL_TRANSPORT_DATAGRAM;
00303     if( sock_mode == TLS ){
00304         mode = MBEDTLS_SSL_TRANSPORT_STREAM;
00305     }
00306 
00307     if( ( mbedtls_ssl_config_defaults( &sec->_conf,
00308                        endpoint,
00309                        mode, 0 ) ) != 0 )
00310     {
00311         return -1;
00312     }
00313 
00314     mbedtls_ssl_set_bio( &sec->_ssl, sec,
00315                         f_send, f_recv, NULL );
00316 
00317     mbedtls_ssl_set_timer_cb( &sec->_ssl, sec, set_timer,
00318                                             get_timer );
00319 
00320     if( coap_security_handler_configure_keys( sec, keys ) != 0 ){
00321         return -1;
00322     }
00323 
00324     //TODO: Only needed for server type?
00325     mbedtls_ssl_conf_dtls_cookies(&sec->_conf, simple_cookie_write,
00326                                   simple_cookie_check,
00327                                   &sec->_cookie);
00328 
00329     sec->_is_started = true;
00330 
00331     do {
00332         ret = mbedtls_ssl_handshake_step( &sec->_ssl );
00333         if( ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ){ //cookie check failed
00334             if( is_server ){
00335                 mbedtls_ssl_session_reset(&sec->_ssl);
00336 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
00337                 if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, keys._priv, keys._priv_len) != 0 ){
00338                     return -1;
00339                 }
00340 #endif
00341                 ret = MBEDTLS_ERR_SSL_WANT_READ; //needed to keep doing
00342             }else{
00343                 ret = -1;
00344             }
00345         }
00346     }while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
00347            ret == MBEDTLS_ERR_SSL_WANT_WRITE );
00348 
00349     if( ret != 0){
00350         ret = -1;
00351     }else{
00352         if( mbedtls_ssl_get_verify_result( &sec->_ssl ) != 0 )
00353             {
00354                 ret = -1;
00355             }
00356     }
00357 
00358     return ret;
00359 }
00360 
00361 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)
00362 {
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     {
00383         return -1;
00384     }
00385 
00386     if(!timeout_max && !timeout_min){
00387         mbedtls_ssl_conf_handshake_timeout( &sec->_conf, DTLS_HANDSHAKE_TIMEOUT_MIN, DTLS_HANDSHAKE_TIMEOUT_MAX );
00388     }
00389     else{
00390         mbedtls_ssl_conf_handshake_timeout( &sec->_conf, timeout_min, timeout_max );
00391     }
00392 
00393     mbedtls_ssl_conf_rng( &sec->_conf, mbedtls_ctr_drbg_random, &sec->_ctr_drbg );
00394 
00395     if( ( mbedtls_ssl_setup( &sec->_ssl, &sec->_conf ) ) != 0 )
00396     {
00397        return -1;
00398     }
00399 
00400     mbedtls_ssl_set_bio( &sec->_ssl, sec,
00401                         f_send, f_recv, NULL );
00402 
00403     mbedtls_ssl_set_timer_cb( &sec->_ssl, sec, set_timer,
00404                                             get_timer );
00405 
00406 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
00407     //TODO: Figure out better way!!!
00408     //Password should never be stored in multiple places!!!
00409     if( is_server && keys._priv_len > 0){
00410         memcpy(sec->_pw, keys._priv, keys._priv_len);
00411         sec->_pw_len = keys._priv_len;
00412     }
00413 #endif
00414 
00415     if( coap_security_handler_configure_keys( sec, keys ) != 0 ){
00416         return -1;
00417     }
00418 
00419     //Only needed for server type?
00420     mbedtls_ssl_conf_dtls_cookies(&sec->_conf, simple_cookie_write,
00421                                   simple_cookie_check,
00422                                   &sec->_cookie);
00423 
00424     mbedtls_ssl_conf_min_version(&sec->_conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MAJOR_VERSION_3);
00425     mbedtls_ssl_conf_max_version(&sec->_conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MAJOR_VERSION_3);
00426     
00427     sec->_is_started = true;
00428 
00429     int ret = mbedtls_ssl_handshake_step( &sec->_ssl );
00430     if( ret == 0 ){
00431         ret = mbedtls_ssl_handshake_step( &sec->_ssl );
00432         if( is_server && 0 == ret){
00433             ret = coap_security_handler_continue_connecting( sec );
00434         }
00435     }
00436 
00437     if( ret >= 0){
00438         ret = 1;
00439     }else{
00440         ret = -1;
00441     }
00442     return ret;
00443 }
00444 
00445 int coap_security_handler_continue_connecting(coap_security_t *sec){
00446     int ret = -1;
00447 
00448     while( ret != MBEDTLS_ERR_SSL_WANT_READ ){
00449         ret = mbedtls_ssl_handshake_step( &sec->_ssl );
00450 
00451         if( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED == ret){
00452             mbedtls_ssl_session_reset(&sec->_ssl);
00453 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
00454             if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, sec->_pw, sec->_pw_len) != 0 ){
00455                 return -1;
00456             }
00457 #endif
00458             return 1;
00459         }
00460         else if(ret && (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)){
00461             return ret;
00462         }
00463 
00464         if( sec->_ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER ){
00465             return 0;
00466         }
00467     }
00468 
00469     if(ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE){
00470         return 1;
00471     }
00472 
00473     return -1;
00474 }
00475 
00476 
00477 int coap_security_handler_send_message(coap_security_t *sec, unsigned char *message, size_t len){
00478     int ret=-1;
00479 
00480     if( sec ){
00481         do 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     int ret=-1;
00503     int max_loops = 100;
00504 
00505     if( sec && buffer ){
00506         memset( buffer, 0, len );
00507         do {
00508             ret = mbedtls_ssl_read( &sec->_ssl, buffer, len );
00509         } while( (ret == MBEDTLS_ERR_SSL_WANT_READ ||
00510                   ret == MBEDTLS_ERR_SSL_WANT_WRITE)
00511                 && --max_loops);
00512     }
00513     return ret; //bytes read
00514 }
00515 
00516 /**** Timer functions ****/
00517 
00518 /**
00519  * Set timer function.
00520  * Called back by mbedtls when it wants to set a timer.
00521  * Accepts an intermediate and a final delay in milliseconds
00522  * If the final delay is 0, cancels the running timer.
00523  * TODO - might be better to use an event timer in conjunction with
00524  * CoAP tasklet
00525  */
00526 static void set_timer(void *sec_obj, uint32_t int_ms, uint32_t fin_ms)
00527 {
00528     coap_security_t *sec = (coap_security_t *)sec_obj;
00529     if( sec->_start_timer_cb ){
00530         sec->_start_timer_cb( sec->_timer_id, int_ms, fin_ms);
00531     }
00532 }
00533 
00534 /**
00535  * Get timer function.
00536  * Called back by mbedtls when it wants to get a timer state.
00537  * Returns the state of the current timer
00538  * TODO - might be better to use an event timer in conjunction with
00539  * CoAP tasklet
00540  */
00541 static int get_timer(void *sec_obj)
00542 {
00543     coap_security_t *sec = (coap_security_t *)sec_obj;
00544     if( sec->_timer_status_cb ){
00545         return sec->_timer_status_cb(sec->_timer_id);
00546     }
00547     return -1;
00548 }
00549 
00550 int f_send( void *ctx, const unsigned char *buf, size_t len){
00551     coap_security_t *sec = (coap_security_t *)ctx;
00552     return sec->_send_cb(sec->_socket_id, sec->_remote_address, sec->_remote_port, buf, len);
00553 }
00554 
00555 int f_recv(void *ctx, unsigned char *buf, size_t len){
00556     coap_security_t *sec = (coap_security_t *)ctx;
00557     return sec->_receive_cb(sec->_socket_id, buf, len);
00558 }
00559 
00560 int entropy_poll( void *ctx, unsigned char *output, size_t len,
00561                            size_t *olen )
00562 {
00563     (void)ctx;
00564     //TODO: change to more secure random
00565     randLIB_seed_random();
00566     char *c = (char*)ns_dyn_mem_temporary_alloc(len);
00567     if( !c ){
00568         return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
00569     }
00570     memset(c, 0, len);
00571     for(uint16_t i=0; i < len; i++){
00572         *(c + i) = (char)randLIB_get_8bit();
00573     }
00574     memmove(output, c, len);
00575     *olen = len;
00576 
00577     ns_dyn_mem_free(c);
00578     return( 0 );
00579 }