Mbed Cloud example program for workshop in W27 2018.

Dependencies:   MMA7660 LM75B

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pal_plat_TLS.c Source File

pal_plat_TLS.c

00001 /*
00002 * Copyright (c) 2016 ARM Limited. All rights reserved.
00003 * SPDX-License-Identifier: Apache-2.0
00004 * Licensed under the Apache License, Version 2.0 (the License); you may
00005 * not use this file except in compliance with the License.
00006 * You may obtain a copy of the License at
00007 *
00008 * http://www.apache.org/licenses/LICENSE-2.0
00009 *
00010 * Unless required by applicable law or agreed to in writing, software
00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013 * See the License for the specific language governing permissions and
00014 * limitations under the License.
00015 */
00016 
00017 #include "pal.h"
00018 #include "pal_plat_TLS.h"
00019 #include "mbedtls/ssl.h"
00020 #include "mbedtls/entropy.h"
00021 #include "mbedtls/ctr_drbg.h"
00022 #include "stdlib.h"
00023 #include "string.h"
00024 
00025 #define SSL_LIB_SUCCESS 0
00026 PAL_PRIVATE PAL_INLINE palStatus_t translateTLSErrToPALError(int32_t error) 
00027 {
00028     palStatus_t status;
00029     switch(error) 
00030     {
00031         case SSL_LIB_SUCCESS: 
00032             status = PAL_ERR_END_OF_FILE ;
00033             break;
00034         case MBEDTLS_ERR_SSL_WANT_READ:
00035             status = PAL_ERR_TLS_WANT_READ;
00036             break;
00037         case MBEDTLS_ERR_SSL_WANT_WRITE:
00038             status = PAL_ERR_TLS_WANT_WRITE;
00039             break;
00040         case MBEDTLS_ERR_SSL_TIMEOUT:
00041             status = PAL_ERR_TIMEOUT_EXPIRED ;
00042             break;
00043         case MBEDTLS_ERR_SSL_BAD_INPUT_DATA:
00044             status = PAL_ERR_TLS_BAD_INPUT_DATA;
00045             break;
00046         case MBEDTLS_ERR_SSL_CLIENT_RECONNECT:
00047             status = PAL_ERR_TLS_CLIENT_RECONNECT;
00048             break;
00049         case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
00050             status = PAL_ERR_TLS_PEER_CLOSE_NOTIFY;
00051             break;
00052         case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:
00053             status = PAL_ERR_X509_CERT_VERIFY_FAILED;
00054             break;
00055         default:
00056             {
00057                 status = PAL_ERR_GENERIC_FAILURE;
00058             }
00059     };
00060     return status;
00061 
00062 }
00063     
00064 
00065 #if defined(MBEDTLS_DEBUG_C)
00066 //! Add forward declaration for the function from mbedTLS
00067 void mbedtls_debug_set_threshold( int threshold );
00068 #endif
00069 
00070 typedef mbedtls_ssl_context platTlsContext;
00071 typedef mbedtls_ssl_config platTlsConfiguraionContext;
00072 
00073 PAL_PRIVATE mbedtls_entropy_context *g_entropy = NULL;
00074 PAL_PRIVATE bool g_entropyInitiated = false;
00075 
00076 typedef struct palTimingDelayContext
00077 {
00078     uint64_t                        start_ticks;
00079     uint32_t                        int_ms;
00080     uint32_t                        fin_ms;
00081 } palTimingDelayContext_t;
00082 
00083 //! the full structures will be defined later in the implemetation.
00084 typedef struct palTLSConf{
00085     platTlsConfiguraionContext*  confCtx;
00086     palTLSSocketHandle_t palIOCtx; // which will be used as bio context for mbedTLS
00087     uint32_t tlsIndex; // to help us to get the index of the containing palTLS_t in the array. will be updated in the init
00088                        // maybe we need to make this an array, since index can be shared for more than one TLS context
00089     mbedtls_ctr_drbg_context ctrDrbg;
00090     palTimingDelayContext_t timerCtx;
00091     mbedtls_x509_crt owncert;
00092     mbedtls_pk_context pkey;
00093     mbedtls_x509_crt cacert;  
00094     bool hasKeys;
00095     bool hasChain;
00096     int cipherSuites[PAL_MAX_ALLOWED_CIPHER_SUITES+1];  // The +1 is for the Zero Termination required by mbedTLS
00097 }palTLSConf_t;
00098 
00099 //! the full structures will be defined later in the implemetation.
00100 typedef struct palTLS{
00101     platTlsContext tlsCtx;
00102     palTLSConf_t* palConfCtx;
00103     bool tlsInit;
00104     uint32_t tlsIndex;
00105     char* psk; //NULL terminated
00106     char* identity; //NULL terminated
00107     bool wantReadOrWrite;
00108 }palTLS_t;
00109 
00110 //! Forward declaration
00111 PAL_PRIVATE int palBIORecv_timeout(palTLSSocketHandle_t socket, unsigned char *buf, size_t len, uint32_t timeout);
00112 PAL_PRIVATE int palBIORecv(palTLSSocketHandle_t socket, unsigned char *buf, size_t len);
00113 PAL_PRIVATE int palBIOSend(palTLSSocketHandle_t socket, const unsigned char *buf, size_t len);
00114 PAL_PRIVATE void palDebug(void *ctx, int debugLevel, const char *fileName, int line, const char *message);
00115 int pal_plat_entropySourceTLS( void *data, unsigned char *output, size_t len, size_t *olen );
00116 PAL_PRIVATE int palTimingGetDelay( void *data );
00117 PAL_PRIVATE void palTimingSetDelay( void *data, uint32_t intMs, uint32_t finMs );
00118 //! This is the array to hold the TLS context
00119 PAL_PRIVATE palTLS_t *g_palTLSContext = NULL;
00120 
00121 palStatus_t pal_plat_initTLSLibrary (void)
00122 {
00123     palStatus_t status = PAL_SUCCESS;
00124 
00125     g_palTLSContext = NULL;
00126 
00127     g_entropy = (mbedtls_entropy_context*)malloc(sizeof(mbedtls_entropy_context));
00128     if (NULL == g_entropy)
00129     {
00130         status = PAL_ERR_NO_MEMORY ;
00131     }
00132     else
00133     {
00134         mbedtls_entropy_init(g_entropy);
00135         g_entropyInitiated = false;
00136     }
00137 
00138     return status;
00139 }
00140 
00141 
00142 palStatus_t pal_plat_cleanupTLS (void)
00143 {
00144     mbedtls_entropy_free(g_entropy);
00145     g_entropyInitiated = false;
00146     free(g_entropy);
00147     g_entropy = NULL;
00148     if (g_palTLSContext)
00149     {
00150         free((void*)g_palTLSContext);
00151         g_palTLSContext = NULL;
00152     }
00153     return PAL_SUCCESS;
00154 }
00155 
00156 
00157 palStatus_t pal_plat_addEntropySource (palEntropySource_f entropyCallback)
00158 {
00159     palStatus_t status = PAL_SUCCESS;
00160     int32_t platStatus = SSL_LIB_SUCCESS;
00161 
00162     if (NULL == entropyCallback)
00163     {
00164         return PAL_ERR_INVALID_ARGUMENT ;
00165     }
00166 
00167     if (!g_entropyInitiated)
00168     {
00169         platStatus = mbedtls_entropy_add_source(g_entropy, entropyCallback, NULL, PAL_INITIAL_RANDOM_SIZE, MBEDTLS_ENTROPY_SOURCE_STRONG );
00170         if (SSL_LIB_SUCCESS != platStatus)
00171         {
00172             status = PAL_ERR_TLS_CONFIG_INIT;
00173         }
00174         else
00175         {
00176             g_entropyInitiated = true;
00177         }
00178         
00179     }
00180 
00181     return status;
00182 }
00183 
00184 
00185 palStatus_t pal_plat_initTLSConf (palTLSConfHandle_t* palConfCtx, palTLSTransportMode_t transportVersion, palDTLSSide_t methodType)
00186 {
00187     palStatus_t status = PAL_SUCCESS;
00188     palTLSConf_t* localConfigCtx = NULL;
00189     int32_t platStatus = SSL_LIB_SUCCESS;
00190     int32_t endpoint = 0;
00191     int32_t transport = 0;
00192 
00193     if (NULLPTR == palConfCtx)
00194     {
00195         return PAL_ERR_INVALID_ARGUMENT ;
00196     }
00197 
00198     localConfigCtx = (palTLSConf_t*)malloc(sizeof(palTLSConf_t));
00199     if (NULL == localConfigCtx)
00200     {
00201         status = PAL_ERR_NO_MEMORY ;
00202         goto finish;
00203     }
00204 
00205     localConfigCtx->confCtx = (platTlsConfiguraionContext*)malloc(sizeof(platTlsConfiguraionContext));
00206     if (NULL == localConfigCtx->confCtx)
00207     {
00208         status = PAL_ERR_NO_MEMORY ;
00209         goto finish;
00210     }
00211     localConfigCtx->tlsIndex = 0;
00212     localConfigCtx->hasKeys = false;
00213     localConfigCtx->hasChain = false;
00214     memset(localConfigCtx->cipherSuites, 0,(sizeof(int)* (PAL_MAX_ALLOWED_CIPHER_SUITES+1)) );  
00215     mbedtls_ssl_config_init(localConfigCtx->confCtx);
00216 
00217     if (PAL_TLS_IS_CLIENT == methodType)
00218     {
00219         endpoint = MBEDTLS_SSL_IS_CLIENT;
00220     }
00221     else
00222     {
00223         endpoint = MBEDTLS_SSL_IS_SERVER;
00224     }
00225 
00226     if (PAL_TLS_MODE == transportVersion)
00227     {
00228         transport = MBEDTLS_SSL_TRANSPORT_STREAM;
00229     }
00230     else
00231     {
00232         transport = MBEDTLS_SSL_TRANSPORT_DATAGRAM;
00233     }
00234     platStatus = mbedtls_ssl_config_defaults(localConfigCtx->confCtx, endpoint, transport, MBEDTLS_SSL_PRESET_DEFAULT);
00235     if (SSL_LIB_SUCCESS != platStatus)
00236     {
00237         PAL_LOG(ERR, "TLS Init conf status %" PRId32 ".", platStatus);
00238         status = PAL_ERR_TLS_CONFIG_INIT;
00239         goto finish;
00240     }                               
00241 
00242     mbedtls_ctr_drbg_init(&localConfigCtx->ctrDrbg);
00243     status = pal_plat_addEntropySource (pal_plat_entropySourceTLS);
00244     if (PAL_SUCCESS != status)
00245     {
00246         goto finish;
00247     }                               
00248 
00249     platStatus = mbedtls_ctr_drbg_seed(&localConfigCtx->ctrDrbg, mbedtls_entropy_func, g_entropy, NULL, 0); //Custom data can be defined in 
00250                                                                                           //pal_TLS.h header and to be defined by 
00251                                                                                           //Service code. But we need to check if other platform support this 
00252                                                                                           //input!
00253     if (SSL_LIB_SUCCESS != platStatus)
00254     {
00255         status = PAL_ERR_TLS_CONFIG_INIT;
00256         goto finish;
00257     }
00258     
00259     mbedtls_ssl_conf_rng(localConfigCtx->confCtx, mbedtls_ctr_drbg_random, &localConfigCtx->ctrDrbg);
00260     *palConfCtx = (uintptr_t)localConfigCtx;
00261     
00262 finish: 
00263     if (PAL_SUCCESS != status && NULL != localConfigCtx)
00264     {
00265         if (NULL != localConfigCtx->confCtx)
00266         {
00267             free(localConfigCtx->confCtx);          
00268         }
00269         free(localConfigCtx);
00270         *palConfCtx = NULLPTR;
00271     }
00272     return status;
00273 }
00274 
00275 
00276 palStatus_t pal_plat_tlsConfigurationFree (palTLSConfHandle_t* palTLSConf)
00277 {
00278     palStatus_t status = PAL_SUCCESS;
00279     palTLSConf_t* localConfigCtx = NULL;
00280 
00281     if (NULLPTR == palTLSConf || NULLPTR == *palTLSConf)
00282     {
00283         return PAL_ERR_INVALID_ARGUMENT ;
00284     }
00285 
00286     localConfigCtx = (palTLSConf_t*)*palTLSConf;
00287 
00288     if (true == localConfigCtx->hasKeys)
00289     {
00290         mbedtls_pk_free(&localConfigCtx->pkey);
00291         mbedtls_x509_crt_free(&localConfigCtx->owncert);
00292     }
00293 
00294     if (true == localConfigCtx->hasChain)
00295     {
00296         mbedtls_x509_crt_free(&localConfigCtx->cacert);
00297     }
00298 
00299     mbedtls_ssl_config_free(localConfigCtx->confCtx);
00300     mbedtls_ctr_drbg_free(&localConfigCtx->ctrDrbg);
00301 
00302     free(localConfigCtx->confCtx);
00303 
00304     memset(localConfigCtx, 0, sizeof(palTLSConf_t));
00305     free(localConfigCtx);
00306     *palTLSConf = NULLPTR;
00307     return status;
00308 }
00309 
00310 
00311 palStatus_t pal_plat_initTLS (palTLSConfHandle_t palTLSConf, palTLSHandle_t* palTLSHandle)
00312 {
00313     palStatus_t status = PAL_SUCCESS;
00314     uint32_t firstAvailableCtxIndex = PAL_MAX_NUM_OF_TLS_CTX;
00315     palTLSConf_t* localConfigCtx = (palTLSConf_t*)palTLSConf;
00316     
00317 
00318     if (NULLPTR == palTLSConf || NULLPTR == palTLSHandle)
00319     {
00320         return PAL_ERR_INVALID_ARGUMENT ;
00321     }
00322     
00323     if (NULL == g_palTLSContext) //We allocate the entire array only for the first time
00324     {
00325         g_palTLSContext = (palTLS_t*)malloc(PAL_MAX_NUM_OF_TLS_CTX * sizeof(palTLS_t));
00326         if (NULL == g_palTLSContext)
00327         {
00328             status = PAL_ERR_TLS_RESOURCE;
00329             goto finish;
00330         }
00331         memset((void*)g_palTLSContext, 0 ,PAL_MAX_NUM_OF_TLS_CTX * sizeof(palTLS_t));
00332     }
00333 
00334     for (uint32_t i=0 ; i < PAL_MAX_NUM_OF_TLS_CTX ; ++i)
00335     {
00336         if (false == g_palTLSContext[i].tlsInit)
00337         {
00338             firstAvailableCtxIndex = i;
00339             break;
00340         }
00341     }
00342 
00343     if (firstAvailableCtxIndex >= PAL_MAX_NUM_OF_TLS_CTX)
00344     {
00345         status = PAL_ERR_TLS_RESOURCE;
00346         goto finish;
00347     }
00348     memset(&g_palTLSContext[firstAvailableCtxIndex], 0 , sizeof(palTLS_t));
00349     mbedtls_ssl_init(&g_palTLSContext[firstAvailableCtxIndex].tlsCtx);
00350     localConfigCtx->tlsIndex = firstAvailableCtxIndex;
00351     g_palTLSContext[firstAvailableCtxIndex].palConfCtx = localConfigCtx;
00352     g_palTLSContext[firstAvailableCtxIndex].tlsIndex = firstAvailableCtxIndex;
00353     g_palTLSContext[firstAvailableCtxIndex].tlsInit = true;
00354     mbedtls_ssl_set_timer_cb(&g_palTLSContext[firstAvailableCtxIndex].tlsCtx, &localConfigCtx->timerCtx, palTimingSetDelay, palTimingGetDelay);
00355     *palTLSHandle = (palTLSHandle_t)&g_palTLSContext[firstAvailableCtxIndex];
00356 
00357 finish:
00358     return status;
00359 }
00360 
00361 
00362 palStatus_t pal_plat_freeTLS (palTLSHandle_t* palTLSHandle)
00363 {
00364     palStatus_t status = PAL_SUCCESS;
00365     palTLS_t* localTLSCtx = NULL;
00366     bool foundActiveTLSCtx = false;
00367     
00368     if (NULLPTR == palTLSHandle || NULLPTR == *palTLSHandle)
00369     {
00370         return PAL_ERR_INVALID_ARGUMENT ;
00371     }
00372 
00373     localTLSCtx = (palTLS_t*)*palTLSHandle;
00374     if (false == localTLSCtx->tlsInit)
00375     {
00376         status = PAL_ERR_TLS_CONTEXT_NOT_INITIALIZED;
00377         goto finish;
00378     }
00379 
00380     g_palTLSContext[localTLSCtx->tlsIndex].tlsInit = false;
00381 
00382     mbedtls_ssl_free(&localTLSCtx->tlsCtx);
00383     memset(localTLSCtx, 0, sizeof(palTLS_t));
00384     *palTLSHandle = NULLPTR;
00385 
00386     for (uint32_t i=0 ; i < PAL_MAX_NUM_OF_TLS_CTX ; ++i) //lets see if we need to release the global array
00387     {
00388         if (true == g_palTLSContext[i].tlsInit)
00389         {
00390             foundActiveTLSCtx = true;
00391             break;
00392         }
00393     }   
00394 
00395     if (false == foundActiveTLSCtx) // no more contexts, no need to hold the entire ctx array
00396     {
00397         free((void*)g_palTLSContext);
00398         g_palTLSContext = NULL;
00399     }
00400     
00401 finish:
00402     return status;
00403 }
00404 
00405 
00406 palStatus_t pal_plat_setAuthenticationMode (palTLSConfHandle_t sslConf, palTLSAuthMode_t authMode)
00407 {
00408     palStatus_t status = PAL_SUCCESS;
00409     int32_t platAuthMode;
00410     palTLSConf_t* localConfigCtx = (palTLSConf_t*)sslConf;
00411 
00412     if (NULLPTR == sslConf)
00413     {
00414         return PAL_ERR_INVALID_ARGUMENT ;
00415     }
00416 
00417     switch(authMode)
00418     {
00419         case PAL_TLS_VERIFY_NONE:
00420             platAuthMode = MBEDTLS_SSL_VERIFY_NONE;
00421             break;          
00422         case PAL_TLS_VERIFY_OPTIONAL:
00423             platAuthMode = MBEDTLS_SSL_VERIFY_OPTIONAL;
00424             break;          
00425         case PAL_TLS_VERIFY_REQUIRED:
00426             platAuthMode = MBEDTLS_SSL_VERIFY_REQUIRED;
00427             break;          
00428         default:
00429             status = PAL_ERR_INVALID_ARGUMENT ;
00430             goto finish;
00431     };
00432     mbedtls_ssl_conf_authmode(localConfigCtx->confCtx, platAuthMode );
00433 
00434 finish:
00435     return status;  
00436 }
00437 
00438 palStatus_t pal_plat_setCipherSuites (palTLSConfHandle_t sslConf, palTLSSuites_t palSuite)
00439 {
00440     palStatus_t status = PAL_SUCCESS;
00441     palTLSConf_t* localConfigCtx = (palTLSConf_t*)sslConf;
00442 
00443     if (NULLPTR == sslConf)
00444     {
00445         return PAL_ERR_INVALID_ARGUMENT ;
00446     }
00447 
00448     switch(palSuite)
00449     {
00450         case PAL_TLS_PSK_WITH_AES_128_CBC_SHA256:
00451             localConfigCtx->cipherSuites[0] = MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256;
00452             break;
00453         case PAL_TLS_PSK_WITH_AES_128_CCM_8:
00454             localConfigCtx->cipherSuites[0] = MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8;
00455             break;
00456         case PAL_TLS_PSK_WITH_AES_256_CCM_8:
00457             localConfigCtx->cipherSuites[0] = MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8;
00458             break;
00459         case PAL_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
00460             localConfigCtx->cipherSuites[0] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8;
00461             break;
00462         case PAL_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
00463             localConfigCtx->cipherSuites[0] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
00464             break;
00465         case PAL_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
00466             localConfigCtx->cipherSuites[0] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
00467             break;
00468         default:
00469             localConfigCtx->cipherSuites[0] = 0;
00470             status = PAL_ERR_TLS_INVALID_CIPHER;
00471             goto finish;
00472     }
00473 
00474     mbedtls_ssl_conf_ciphersuites(localConfigCtx->confCtx, localConfigCtx->cipherSuites);
00475 finish:
00476     return status;
00477 }
00478 
00479 
00480 palStatus_t pal_plat_sslGetVerifyResult (palTLSHandle_t palTLSHandle)
00481 {
00482     palStatus_t status = PAL_SUCCESS;
00483     palTLS_t* localTLSCtx = (palTLS_t*)palTLSHandle;
00484     int32_t platStatus = SSL_LIB_SUCCESS;
00485 
00486     if (NULLPTR == palTLSHandle)
00487     {
00488         return PAL_ERR_INVALID_ARGUMENT ;
00489     }
00490     
00491     platStatus = mbedtls_ssl_get_verify_result(&localTLSCtx->tlsCtx);
00492     if (SSL_LIB_SUCCESS != platStatus)
00493     {
00494         //This errors handling must be expanded to all possible 
00495         //return values from the mbedtls_ssl_get_verify_result()
00496         PAL_LOG(ERR, "SSL Verify result error %" PRId32 ".", platStatus);
00497         status = PAL_ERR_GENERIC_FAILURE;
00498     }
00499     return status;
00500 }
00501 
00502 
00503 palStatus_t pal_plat_sslRead (palTLSHandle_t palTLSHandle, void *buffer, uint32_t len, uint32_t* actualLen)
00504 {
00505     palStatus_t status = PAL_SUCCESS;
00506     int32_t platStatus = SSL_LIB_SUCCESS;
00507     palTLS_t* localTLSCtx = (palTLS_t*)palTLSHandle;
00508 
00509     if (NULLPTR == palTLSHandle || NULL == buffer || NULL == actualLen)
00510     {
00511         return PAL_ERR_INVALID_ARGUMENT ;
00512     }
00513 
00514     platStatus = mbedtls_ssl_read(&localTLSCtx->tlsCtx, (unsigned char*)buffer, len);
00515     if (platStatus > SSL_LIB_SUCCESS)
00516     {
00517         *actualLen = platStatus;
00518     }
00519     else
00520     {
00521         status = translateTLSErrToPALError(platStatus);
00522         PAL_LOG(ERR, "SSL Read return code %" PRId32 ".", platStatus);
00523     }
00524         
00525     return status;
00526 }
00527 
00528 
00529 palStatus_t pal_plat_sslWrite (palTLSHandle_t palTLSHandle, const void *buffer, uint32_t len, uint32_t *bytesWritten)
00530 {
00531     palStatus_t status = PAL_SUCCESS;
00532     int32_t platStatus = SSL_LIB_SUCCESS;
00533     palTLS_t* localTLSCtx = (palTLS_t*)palTLSHandle;
00534 
00535     if (NULLPTR == palTLSHandle || NULL == buffer || NULL == bytesWritten)
00536     {
00537         return PAL_ERR_INVALID_ARGUMENT ;
00538     }
00539 
00540     platStatus = mbedtls_ssl_write(&localTLSCtx->tlsCtx, (unsigned char*)buffer, len);
00541     if (platStatus > SSL_LIB_SUCCESS)
00542     {
00543         *bytesWritten = platStatus;
00544     }
00545     else
00546     {
00547         status = translateTLSErrToPALError(platStatus);
00548         PAL_LOG(ERR, "SSL Write platform return code %" PRId32 ".", platStatus);
00549     }
00550 
00551     return status;
00552 }
00553 
00554 
00555 palStatus_t pal_plat_setHandShakeTimeOut (palTLSConfHandle_t palTLSConf, uint32_t timeoutInMilliSec)
00556 {
00557     palTLSConf_t* localConfigCtx = (palTLSConf_t*)palTLSConf;
00558     uint32_t minTimeout = PAL_DTLS_PEER_MIN_TIMEOUT;
00559     uint32_t maxTimeout = timeoutInMilliSec >> 1; //! faster dividing by 2
00560     //! Since mbedTLS algorithm for UDP handshake algorithm is as follow:
00561     //! wait 'minTimeout' ..=> 'minTimeout = 2*minTimeout' while 'minTimeout < maxTimeout'
00562     //! if 'minTimeout >= maxTimeout' them wait 'maxTimeout'.
00563     //! The whole waiting time is the sum of the different intervals waited.
00564     //! Therefore we need divide the 'timeoutInMilliSec' by 2 to give a close approximation of the desired 'timeoutInMilliSec'
00565     //! 1 + 2 + ... + 'timeoutInMilliSec/2' ~= 'timeoutInMilliSec'
00566 
00567     if (NULLPTR == palTLSConf || 0 == timeoutInMilliSec)
00568     {
00569         return PAL_ERR_INVALID_ARGUMENT ;
00570     }
00571 
00572     if (maxTimeout < PAL_DTLS_PEER_MIN_TIMEOUT)
00573     {
00574         minTimeout = (timeoutInMilliSec+1) >> 1; //to prevent 'minTimeout == 0'
00575         maxTimeout = timeoutInMilliSec;
00576     }
00577 
00578     mbedtls_ssl_conf_handshake_timeout(localConfigCtx->confCtx, minTimeout, maxTimeout);
00579 
00580     return PAL_SUCCESS;
00581 }
00582 
00583 
00584 palStatus_t pal_plat_sslSetup (palTLSHandle_t palTLSHandle, palTLSConfHandle_t palTLSConf)
00585 {
00586     palStatus_t status = PAL_SUCCESS;
00587     palTLS_t* localTLSCtx = (palTLS_t*)palTLSHandle;
00588     palTLSConf_t* localConfigCtx = (palTLSConf_t*)palTLSConf;
00589     int32_t platStatus = SSL_LIB_SUCCESS;
00590 
00591     if (NULLPTR == palTLSConf || NULLPTR == palTLSHandle)
00592     {
00593         return PAL_ERR_INVALID_ARGUMENT ;
00594     }
00595 
00596     if (!localTLSCtx->wantReadOrWrite)
00597     {
00598         platStatus = mbedtls_ssl_setup(&localTLSCtx->tlsCtx, localConfigCtx->confCtx);
00599         if (SSL_LIB_SUCCESS != platStatus)
00600         {
00601             if (MBEDTLS_ERR_SSL_ALLOC_FAILED == platStatus)
00602             {
00603                 status = PAL_ERR_NO_MEMORY ;
00604                 goto finish;
00605             }
00606             PAL_LOG(ERR, "SSL setup return code %" PRId32 ".", platStatus);
00607             status = PAL_ERR_GENERIC_FAILURE;
00608             goto finish;
00609         }
00610 
00611         localTLSCtx->palConfCtx = localConfigCtx;
00612         localConfigCtx->tlsIndex = localTLSCtx->tlsIndex;       
00613     }
00614 finish:
00615     return status;
00616 }
00617 
00618 
00619 palStatus_t pal_plat_handShake (palTLSHandle_t palTLSHandle)
00620 {
00621     palStatus_t status = PAL_SUCCESS;
00622     palTLS_t* localTLSCtx = (palTLS_t*)palTLSHandle;
00623     int32_t platStatus = SSL_LIB_SUCCESS;
00624 
00625     if (NULLPTR == palTLSHandle)
00626     {
00627         return PAL_ERR_INVALID_ARGUMENT ;
00628     }
00629     
00630     platStatus = mbedtls_ssl_handshake(&localTLSCtx->tlsCtx);
00631     switch(platStatus)
00632     {
00633         case SSL_LIB_SUCCESS:
00634             status = PAL_SUCCESS;
00635             localTLSCtx->wantReadOrWrite = false;
00636             break;
00637         case MBEDTLS_ERR_SSL_WANT_READ:
00638             status = PAL_ERR_TLS_WANT_READ;
00639             localTLSCtx->wantReadOrWrite = true;
00640             break;
00641         case MBEDTLS_ERR_SSL_WANT_WRITE:
00642             status = PAL_ERR_TLS_WANT_WRITE;
00643             localTLSCtx->wantReadOrWrite = true;
00644             break;
00645         case MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED:
00646             status = PAL_ERR_TLS_HELLO_VERIFY_REQUIRED;
00647             break;
00648         case MBEDTLS_ERR_SSL_TIMEOUT:
00649             status = PAL_ERR_TIMEOUT_EXPIRED ;
00650             break;
00651         case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
00652             status = PAL_ERR_TLS_PEER_CLOSE_NOTIFY;
00653             break;
00654         case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:
00655             status = PAL_ERR_X509_CERT_VERIFY_FAILED;
00656             break;
00657         default:
00658             {
00659                 PAL_LOG(ERR, "SSL handshake return code %" PRId32 ".", platStatus);
00660                 status = PAL_ERR_GENERIC_FAILURE;
00661             }
00662     };
00663 
00664     return status;
00665 }
00666 
00667 
00668 palStatus_t pal_plat_setOwnCertAndPrivateKey (palTLSConfHandle_t palTLSConf, palX509_t* ownCert, palPrivateKey_t* privateKey)
00669 {
00670     palStatus_t status = PAL_SUCCESS;
00671     palTLSConf_t* localConfigCtx = (palTLSConf_t*)palTLSConf;
00672     int32_t platStatus = SSL_LIB_SUCCESS;
00673 
00674 
00675     if (NULLPTR == palTLSConf || NULL == ownCert || NULL == ownCert)
00676     {
00677         return PAL_ERR_INVALID_ARGUMENT ;
00678     }
00679 
00680     mbedtls_x509_crt_init(&localConfigCtx->owncert);
00681     mbedtls_pk_init(&localConfigCtx->pkey);
00682 
00683     
00684     platStatus = mbedtls_x509_crt_parse_der(&localConfigCtx->owncert, (const unsigned char *)ownCert->buffer, ownCert->size);
00685     if (SSL_LIB_SUCCESS != platStatus)
00686     {
00687         status = PAL_ERR_TLS_FAILED_TO_PARSE_CERT;
00688         goto finish;
00689     }
00690 
00691     platStatus = mbedtls_pk_parse_key(&localConfigCtx->pkey, (const unsigned char *)privateKey->buffer, privateKey->size, NULL, 0 );
00692     if (SSL_LIB_SUCCESS != platStatus)
00693     {
00694         status = PAL_ERR_TLS_FAILED_TO_PARSE_KEY;
00695         goto finish;
00696     }
00697 
00698     platStatus = mbedtls_ssl_conf_own_cert(localConfigCtx->confCtx, &localConfigCtx->owncert, &localConfigCtx->pkey); 
00699     if (SSL_LIB_SUCCESS != platStatus)
00700     {
00701         status = PAL_ERR_TLS_FAILED_TO_SET_CERT;
00702     }
00703 
00704     localConfigCtx->hasKeys = true;
00705 
00706 finish:
00707     PAL_LOG(DBG, "TLS set and parse status %" PRIu32 ".", platStatus);
00708     return status;
00709 }
00710 
00711 
00712 palStatus_t pal_plat_setCAChain (palTLSConfHandle_t palTLSConf, palX509_t* caChain, palX509CRL_t* caCRL)
00713 {
00714     palStatus_t status = PAL_SUCCESS;
00715     palTLSConf_t* localConfigCtx = (palTLSConf_t*)palTLSConf;
00716     int32_t platStatus = SSL_LIB_SUCCESS;
00717 
00718     if (NULLPTR == palTLSConf || NULL == caChain)
00719     {
00720         return PAL_ERR_INVALID_ARGUMENT ;
00721     }
00722 
00723     mbedtls_x509_crt_init(&localConfigCtx->cacert);
00724 
00725     platStatus = mbedtls_x509_crt_parse_der(&localConfigCtx->cacert, (const unsigned char *)caChain->buffer, caChain->size);
00726     if (SSL_LIB_SUCCESS != platStatus)
00727     {
00728         PAL_LOG(ERR, "TLS CA chain status %" PRId32 ".", platStatus);
00729         status = PAL_ERR_GENERIC_FAILURE;
00730         goto finish;
00731     }
00732     mbedtls_ssl_conf_ca_chain(localConfigCtx->confCtx, &localConfigCtx->cacert, NULL );
00733 
00734     localConfigCtx->hasChain = true;
00735 finish:
00736     return status;
00737 }
00738 
00739 palStatus_t pal_plat_setPSK (palTLSConfHandle_t palTLSConf, const unsigned char *identity, uint32_t maxIdentityLenInBytes, const unsigned char *psk, uint32_t maxPskLenInBytes)
00740 {
00741     palStatus_t status = PAL_SUCCESS;
00742     palTLSConf_t* localConfigCtx = (palTLSConf_t*)palTLSConf;
00743     int32_t platStatus = SSL_LIB_SUCCESS;
00744 
00745     if (NULLPTR == palTLSConf || NULL == identity || NULL == psk)
00746     {
00747         return PAL_ERR_INVALID_ARGUMENT ;
00748     }
00749 
00750     platStatus = mbedtls_ssl_conf_psk(localConfigCtx->confCtx, psk, maxPskLenInBytes, identity, maxIdentityLenInBytes);
00751     if (SSL_LIB_SUCCESS != platStatus)
00752     {
00753         if (MBEDTLS_ERR_SSL_ALLOC_FAILED == platStatus)
00754         {
00755             status = PAL_ERR_TLS_INIT;
00756             goto finish;
00757         }
00758         PAL_LOG(ERR, "TLS set psk status %" PRId32 ".", platStatus);
00759         status = PAL_ERR_GENERIC_FAILURE;
00760     }
00761 finish:
00762     return status;
00763 }
00764 
00765 palStatus_t pal_plat_tlsSetSocket (palTLSConfHandle_t palTLSConf, palTLSSocket_t* socket)
00766 {
00767     palStatus_t status = PAL_SUCCESS;
00768 
00769     if (NULLPTR == palTLSConf || NULL == socket)
00770     {
00771         return PAL_ERR_INVALID_ARGUMENT ;
00772     }
00773 
00774     status = pal_plat_sslSetIOCallBacks (palTLSConf, socket, palBIOSend, palBIORecv);
00775     return status;
00776 }
00777 
00778 palStatus_t pal_plat_sslSetIOCallBacks (palTLSConfHandle_t palTLSConf, palTLSSocket_t* palIOCtx, palBIOSend_f palBIOSend, palBIORecv_f palBIORecv)
00779 {
00780     palStatus_t status = PAL_SUCCESS;
00781     palTLSConf_t* localConfigCtx = (palTLSConf_t*)palTLSConf;
00782     bool isNonBlocking = false;
00783 
00784     if (NULLPTR == palTLSConf || NULL == palBIOSend || NULL == palBIORecv)
00785     {
00786         return PAL_ERR_INVALID_ARGUMENT ;
00787     }
00788     localConfigCtx->palIOCtx = palIOCtx;
00789 
00790     status = pal_isNonBlocking(palIOCtx->socket, &isNonBlocking);
00791     if (PAL_SUCCESS != status)
00792     {
00793         return status;
00794     }
00795 
00796     if (isNonBlocking)
00797     {
00798         mbedtls_ssl_set_bio(&g_palTLSContext[localConfigCtx->tlsIndex].tlsCtx, palIOCtx, palBIOSend, palBIORecv, NULL);
00799     }
00800     else
00801     {
00802         mbedtls_ssl_set_bio(&g_palTLSContext[localConfigCtx->tlsIndex].tlsCtx, palIOCtx, palBIOSend, NULL, palBIORecv_timeout);
00803     }
00804 
00805     return PAL_SUCCESS;
00806 }
00807 
00808 palStatus_t pal_plat_sslDebugging (uint8_t turnOn)
00809 {
00810     palStatus_t status = PAL_SUCCESS;
00811     palLogFunc_f func = NULL;
00812 #if defined(MBEDTLS_DEBUG_C)    
00813     mbedtls_debug_set_threshold(PAL_TLS_DEBUG_THRESHOLD);
00814 #endif
00815 
00816     if (turnOn)
00817     {
00818         func = palDebug;
00819     }
00820 
00821     for (int i=0 ; i < PAL_MAX_NUM_OF_TLS_CTX ; ++i )
00822     {
00823         if ((g_palTLSContext != NULL) && (g_palTLSContext[i].tlsInit))
00824         {
00825             status = pal_plat_SetLoggingCb ((palTLSConfHandle_t)g_palTLSContext[i].palConfCtx, func, NULL);
00826         }
00827     }
00828 
00829     return status;
00830 }
00831 
00832 palStatus_t pal_plat_SetLoggingCb (palTLSConfHandle_t palTLSConf, palLogFunc_f palLogFunction, void *logContext)
00833 {
00834     palTLSConf_t* localConfigCtx = (palTLSConf_t*)palTLSConf;
00835     
00836     mbedtls_ssl_conf_dbg(localConfigCtx->confCtx, palLogFunction, logContext);
00837     return PAL_SUCCESS;
00838 }
00839 
00840 PAL_PRIVATE uint64_t palTimingGetTimer(uint64_t *start_ticks, int reset)
00841 {
00842     uint64_t delta_ms;
00843     uint64_t ticks = pal_osKernelSysTick();
00844 
00845     if (reset)
00846     {
00847         *start_ticks = ticks;
00848         delta_ms = 0;
00849     }
00850     else
00851     {
00852         delta_ms = pal_osKernelSysMilliSecTick(ticks - *start_ticks);
00853     }
00854 
00855     return delta_ms;
00856 }
00857 
00858 
00859 /*
00860  * Set delays to watch
00861  */
00862 PAL_PRIVATE void palTimingSetDelay( void *data, uint32_t intMs, uint32_t finMs )
00863 {
00864 
00865     palTimingDelayContext_t *ctx = data;
00866 
00867     ctx->int_ms = intMs;
00868     ctx->fin_ms = finMs;
00869 
00870     if( finMs != 0 )
00871     {
00872         (void) palTimingGetTimer( &ctx->start_ticks, 1 );
00873     }
00874 }
00875 
00876 /*
00877  * Get number of delays expired
00878  */
00879 PAL_PRIVATE int palTimingGetDelay( void *data )
00880 {
00881     int result = 0;
00882     palTimingDelayContext_t *ctx = data;
00883     uint64_t elapsed_ms;
00884 
00885     if( ctx->fin_ms == 0 )
00886     {
00887         result = -1;
00888         goto finish;
00889     }
00890 
00891     elapsed_ms = palTimingGetTimer( &ctx->start_ticks, 0 );
00892 
00893     if( elapsed_ms >= ctx->fin_ms )
00894     {
00895         result = 2;
00896         goto finish;
00897     }
00898 
00899     if( elapsed_ms >= ctx->int_ms )
00900     {
00901         result = 1;
00902         goto finish;
00903     }
00904 
00905 finish:
00906     return result;
00907 }
00908 
00909 
00910 int pal_plat_entropySourceTLS( void *data, unsigned char *output, size_t len, size_t *olen )
00911 {
00912     palStatus_t status = PAL_SUCCESS;
00913     (void)data;
00914 
00915     status = pal_osRandomBuffer((uint8_t*) output, len);
00916     if (PAL_SUCCESS == status)
00917     {
00918         if (NULL != olen)
00919         {
00920             *olen = len;
00921         }
00922         return 0;
00923     }
00924     else
00925     {
00926         return -1;
00927     }
00928 }
00929 
00930 PAL_PRIVATE int palBIOSend(palTLSSocketHandle_t socket, const unsigned char *buf, size_t len)
00931 {
00932     palStatus_t status = PAL_SUCCESS;
00933     size_t sentDataSize = 0;
00934     palTLSSocket_t* localSocket = (palTLSSocket_t*)socket;
00935 
00936     if (NULLPTR == socket)
00937     {
00938         status = -1;
00939         goto finish;
00940     }
00941 
00942     if (PAL_TLS_MODE == localSocket->transportationMode)
00943     {
00944         status = pal_send(localSocket->socket, buf, len, &sentDataSize);
00945     }
00946     else if (PAL_DTLS_MODE == localSocket->transportationMode)
00947     {
00948         status = pal_sendTo(localSocket->socket, buf, len, localSocket->socketAddress, localSocket->addressLength, &sentDataSize);
00949     }
00950     else
00951     {
00952         PAL_LOG(ERR, "TLS BIO send error");
00953         status = PAL_ERR_GENERIC_FAILURE;
00954     }
00955     if (PAL_SUCCESS == status || PAL_ERR_NO_MEMORY  == status || PAL_ERR_SOCKET_WOULD_BLOCK  == status)
00956     {
00957         if (0 != sentDataSize)
00958         {
00959             status = sentDataSize;
00960         }
00961         else
00962         {
00963             status = MBEDTLS_ERR_SSL_WANT_WRITE;
00964         }
00965     }
00966 finish:
00967     return status;
00968 }
00969 
00970 PAL_PRIVATE int palBIORecv(palTLSSocketHandle_t socket, unsigned char *buf, size_t len)
00971 {
00972     palStatus_t status = PAL_SUCCESS;
00973     size_t recievedDataSize = 0;
00974     palTLSSocket_t* localSocket = (palTLSSocket_t*)socket;
00975 
00976     if (NULLPTR == socket)
00977     {
00978         status = -1;
00979         goto finish;
00980     }
00981 
00982     if (PAL_TLS_MODE == localSocket->transportationMode)
00983     {
00984         status = pal_recv(localSocket->socket, buf, len, &recievedDataSize);
00985         if (PAL_SUCCESS == status)
00986         {
00987             status = recievedDataSize;
00988         }
00989         else if (PAL_ERR_SOCKET_WOULD_BLOCK  == status)
00990         {
00991             status = MBEDTLS_ERR_SSL_WANT_READ;
00992         }
00993     }
00994     else if (PAL_DTLS_MODE == localSocket->transportationMode)
00995     {
00996         status = pal_receiveFrom(localSocket->socket, buf, len, localSocket->socketAddress, &localSocket->addressLength, &recievedDataSize);
00997         if (PAL_SUCCESS == status)
00998         {
00999             if (0 != recievedDataSize)
01000             {
01001                 status = recievedDataSize;
01002             }
01003             else
01004             {
01005                 status = MBEDTLS_ERR_SSL_WANT_READ;
01006             }
01007         }
01008         else if (PAL_ERR_SOCKET_WOULD_BLOCK  == status)
01009         {
01010             status = MBEDTLS_ERR_SSL_WANT_READ;
01011         }
01012     }
01013     else
01014     {
01015         PAL_LOG(ERR, "TLS BIO recv error");
01016         status = PAL_ERR_GENERIC_FAILURE;
01017     }
01018 
01019 finish:
01020     return status;
01021 }
01022 
01023 PAL_PRIVATE int palBIORecv_timeout(palTLSSocketHandle_t socket, unsigned char *buf, size_t len, uint32_t timeout)
01024 {   
01025     palStatus_t status = PAL_SUCCESS;
01026     size_t recievedDataSize = 0;
01027     uint32_t localTimeOut = timeout;
01028     palTLSSocket_t* localSocket = (palTLSSocket_t*)socket;
01029     bool isNonBlocking = false;
01030 
01031     if (NULLPTR == socket)
01032     {
01033         status = -1;
01034         goto finish;
01035     }
01036     
01037     status = pal_isNonBlocking(localSocket->socket, &isNonBlocking);
01038     if (PAL_SUCCESS != status)
01039     {
01040         goto finish;
01041     }
01042 
01043     if (PAL_TLS_MODE == localSocket->transportationMode)
01044     {
01045         status = pal_recv(localSocket->socket, buf, len, &recievedDataSize);
01046         if (PAL_SUCCESS == status)
01047         {
01048             status = recievedDataSize;
01049         }
01050         else if (PAL_ERR_SOCKET_WOULD_BLOCK  == status)
01051         {
01052             status = MBEDTLS_ERR_SSL_WANT_READ;
01053         }
01054     }
01055     else if (PAL_DTLS_MODE == localSocket->transportationMode)
01056     {
01057         if (false == isNonBlocking) // timeout is relevant only if socket is blocking
01058         {
01059             status = pal_setSocketOptions(localSocket->socket, PAL_SO_RCVTIMEO , &localTimeOut, sizeof(localTimeOut));
01060             if (PAL_SUCCESS != status)
01061             {
01062                 goto finish;
01063             }
01064         }
01065 
01066         status = pal_receiveFrom(localSocket->socket, buf, len, localSocket->socketAddress, &localSocket->addressLength, &recievedDataSize);
01067         
01068         if (PAL_SUCCESS == status)
01069         {
01070             if (0 != recievedDataSize)
01071             {
01072                 status = recievedDataSize;
01073             }
01074             else
01075             {
01076                 status = MBEDTLS_ERR_SSL_WANT_READ;
01077             }
01078         }
01079         else if (PAL_ERR_SOCKET_WOULD_BLOCK  == status)
01080         {
01081             status = MBEDTLS_ERR_SSL_TIMEOUT;
01082         }
01083     }
01084     else
01085     {
01086         PAL_LOG(ERR, "TLS BIO recv timeout error");
01087         status = PAL_ERR_GENERIC_FAILURE;
01088     }
01089 
01090 finish:
01091     return status;
01092 }
01093 
01094 PAL_PRIVATE void palDebug(void *ctx, int debugLevel, const char *fileName, int line, const char *message)
01095 {
01096     (void)ctx;
01097     DEBUG_PRINT("%s: %d: %s\r\n", fileName, line, message);
01098 }
01099