Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pal_plat_drbg_sotp.c Source File

pal_plat_drbg_sotp.c

00001 /*******************************************************************************
00002  * Copyright 2016-2018 ARM Ltd.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may 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,
00012  * WITHOUT 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 // This file is compiled when using ESFS and SOTP
00018 #if !defined(MBED_CONF_MBED_CLOUD_CLIENT_EXTERNAL_SST_SUPPORT)
00019 
00020 
00021 #include "pal.h"
00022 #include "pal_plat_drbg.h"
00023 #include "pal_plat_drbg_noise.h"
00024 #include "sotp.h"
00025 
00026 #include <stdlib.h>
00027 
00028 #define TRACE_GROUP "PAL"
00029 
00030 
00031 //! static variables for Random functionality.
00032 //! CTR-DRBG context to be used for generating random numbers from given seed
00033 static palCtrDrbgCtxHandle_t s_ctrDRBGCtx = NULLPTR;
00034 
00035 PAL_PRIVATE bool g_palDRBGInitialized = false;
00036 
00037 palStatus_t pal_plat_DRBGInit(void)
00038 {
00039     palStatus_t status = PAL_SUCCESS;
00040     if (g_palDRBGInitialized)
00041     {
00042         return status;
00043     }
00044     status = pal_plat_noiseInit();
00045     if (PAL_SUCCESS != status)
00046     {
00047         PAL_LOG_ERR("pal_plat_DRBGInit: pal_plat_NoiseInit failed, status=%" PRIx32 "\n", status);
00048     }
00049 
00050     g_palDRBGInitialized = true;
00051 
00052     return status;
00053 }
00054 
00055 palStatus_t pal_plat_DRBGDestroy(void)
00056 {
00057     palStatus_t status = PAL_ERR_NOT_INITIALIZED ;
00058     if (!g_palDRBGInitialized)
00059     {
00060         return status;
00061     }
00062 
00063 #if PAL_USE_HW_TRNG
00064     if (PAL_SUCCESS != pal_plat_noiseDestroy())
00065     {
00066         PAL_LOG_ERR("pal_DRBGDestroy: failed to terminate trng noise thread\n");
00067         // FIXME: return error status?
00068     }
00069 #endif 
00070     if (NULLPTR != s_ctrDRBGCtx)
00071     {
00072         status = pal_CtrDRBGFree(&s_ctrDRBGCtx);
00073         if (PAL_SUCCESS != status)
00074         {
00075             PAL_LOG_ERR("pal_DRBGDestroy: pal_CtrDRBGFree failed, status=%" PRIx32 "\n", status);
00076         }
00077     }
00078 
00079     g_palDRBGInitialized = false;
00080     return status;
00081 }
00082 
00083 
00084 palStatus_t pal_plat_osRandomBuffer_blocking(uint8_t *randomBuf, size_t bufSizeBytes)
00085 {
00086     PAL_VALIDATE_ARGUMENTS (NULL == randomBuf);
00087 
00088     palStatus_t status = PAL_ERR_GENERIC_FAILURE ;
00089     if (g_palDRBGInitialized == true)
00090     {
00091         if (NULLPTR == s_ctrDRBGCtx)
00092         {
00093             // XXX: move this to pal_plat_DRBGInit(), no point to do lazy initializations as it is
00094             // better to fail early on init phase than unexpectedly on a call to pal_osRandomBuffer().
00095             uint32_t sotpCounter = 0;
00096             uint8_t buf[(PAL_INITIAL_RANDOM_SIZE * 2 + sizeof(sotpCounter))] PAL_PTR_ADDR_ALIGN_UINT8_TO_UINT32 = { 0 }; // space for 48 bytes short term + 48 bytes long term + 4 counter bytes (note this buffer will also be used to collect TRNG noise)
00097             const uint16_t sotpLenBytes = PAL_INITIAL_RANDOM_SIZE + sizeof(sotpCounter); // the max number of bytes expected to be read/written form/to sotp, note that sotpCounter will probably be empty the 1st time data is read from sotp
00098             uint32_t* ptrSotpRead = (uint32_t*)&buf; // pointer to the memory address in buf which will point to the data that will be read from sotp
00099             uint32_t* ptrSotpWrite = (uint32_t*)&buf[PAL_INITIAL_RANDOM_SIZE]; // pointer to the memory address in buf which will point to the data which needs to be written back to sotp
00100             uint32_t* ptrSotpCounterRead = ptrSotpWrite; // pointer to the memory address in buf which will point to the counter read from sotp
00101             uint32_t* ptrSotpCounterWrite = (uint32_t*)&buf[PAL_INITIAL_RANDOM_SIZE * 2]; // pointer to the memory address in buf which will point to the incremented counter which will be written back to sotp
00102             uint16_t sotpBytesRead = 0, noiseBitsWrittern = 0;
00103             size_t trngBytesRead = 0;
00104             palCtrDrbgCtxHandle_t longCtrDRBGCtx = NULLPTR; // long term drbg context            
00105             palStatus_t tmpStatus;
00106             sotp_result_e sotpResult = sotp_get(SOTP_TYPE_RANDOM_SEED, sotpLenBytes, ptrSotpRead, &sotpBytesRead); // read 48 drbg bytes + 4 counter bytes
00107             if (SOTP_SUCCESS == sotpResult)
00108             {
00109                 if ((PAL_INITIAL_RANDOM_SIZE != sotpBytesRead) && (sotpLenBytes != sotpBytesRead))
00110                 {
00111                     status = PAL_ERR_RTOS_RECEIVED_LENGTH_IS_TOO_SHORT ;
00112                     PAL_LOG_ERR("Invalid number of bytes read from SOTP, bytes read=%" PRIu16, sotpBytesRead);
00113                     goto finish;
00114                 }
00115                 status = pal_CtrDRBGInit(&longCtrDRBGCtx, ptrSotpRead, PAL_INITIAL_RANDOM_SIZE); // initialize long term drbg with the seed that was read from sotp
00116                 if (PAL_SUCCESS != status)
00117                 {
00118                     PAL_LOG_ERR("Failed to initialize long term DRBG context, status=%" PRIx32 "\n", status);
00119                     goto finish;
00120                 }
00121                 memcpy((void*)&sotpCounter, (void*)ptrSotpCounterRead, sizeof(sotpCounter)); // read the counter from the buffer (sotp data) to local var
00122 #if PAL_USE_HW_TRNG
00123                 memset((void*)buf, 0, sizeof(buf));                
00124                 status = pal_plat_osRandomBuffer(buf, PAL_NOISE_SIZE_BYTES, &trngBytesRead);
00125                 if ((PAL_SUCCESS == status) || (PAL_ERR_RTOS_TRNG_PARTIAL_DATA  == status))
00126                 {
00127                     if (0 < trngBytesRead)
00128                     {
00129                         tmpStatus = pal_plat_noiseWriteBuffer((int32_t*)buf, (trngBytesRead * CHAR_BIT), &noiseBitsWrittern); // write whatever was collected from trng to the noise buffer
00130                         PAL_LOG_DBG( "Write TRNG to noise buffer, status=%" PRIx32 ", bits writtern=%" PRIu16 "\n", tmpStatus, noiseBitsWrittern);
00131                     }
00132                 }
00133                 else
00134                 {
00135                     PAL_LOG_ERR("Read from TRNG failed, status=%" PRIx32 "\n", status);
00136                 }                
00137 #endif // PAL_USE_HW_TRNG
00138                 memset((void*)buf, 0, sizeof(buf));
00139                 status = pal_plat_generateDrbgWithNoiseAttempt(longCtrDRBGCtx, buf, true, (PAL_INITIAL_RANDOM_SIZE * 2)); // generate 96 bytes, the 1st 48 bytes will be used for short term drbg and the other 48 bytes will be used for long term drbg
00140                 if (PAL_SUCCESS != status)
00141                 {
00142                     PAL_LOG_ERR("Failed to gererate DRBG long term and short term seeds, status=%" PRIx32 "\n", status);
00143                     goto drbg_cleanup;
00144                 }
00145                 sotpCounter++; // increment counter before writting it back to sotp
00146                 memcpy((void*)ptrSotpCounterWrite, (void*)&sotpCounter, sizeof(sotpCounter)); // copy the incremented counter to the last 4 bytes of the buffer
00147                 sotpResult = sotp_set(SOTP_TYPE_RANDOM_SEED, sotpLenBytes, ptrSotpWrite); // write 48 long term drbg bytes + 4 counter bytes
00148                 if (SOTP_SUCCESS != sotpResult)
00149                 {
00150                     PAL_LOG_ERR("Failed to write to SOTP, sotp result=%d", sotpResult);
00151                     status = PAL_ERR_GENERIC_FAILURE ;
00152                 }                
00153 drbg_cleanup:
00154                 {
00155                     tmpStatus = pal_CtrDRBGFree(&longCtrDRBGCtx);
00156                     if (PAL_SUCCESS != tmpStatus)
00157                     {
00158                         PAL_LOG_ERR("Failed to free long term DRBG context, status=%" PRIx32 "\n", tmpStatus);
00159                     }
00160                     longCtrDRBGCtx = NULLPTR;                    
00161                     if (PAL_SUCCESS != status)
00162                     {
00163                         goto finish;
00164                     }
00165 #if PAL_USE_HW_TRNG
00166                     status = pal_plat_noiseCreateThread();
00167                     if (PAL_SUCCESS != status)
00168                     {
00169                         PAL_LOG_ERR("Failed to create noise TRNG thread, status=%" PRIx32 "\n", tmpStatus);
00170                     }
00171 #endif // PAL_USE_HW_TRNG
00172                 }
00173             }
00174             else if (SOTP_NOT_FOUND == sotpResult)
00175             {
00176 #if PAL_USE_HW_TRNG
00177                 memset((void*)buf, 0, sizeof(buf));
00178                 uint8_t* seedPtr = buf;
00179                 size_t randomCounterBytes = 0;
00180                 do
00181                 {
00182                     status = pal_plat_osRandomBuffer(seedPtr, PAL_INITIAL_RANDOM_SIZE - randomCounterBytes, &trngBytesRead);
00183                     if (PAL_ERR_RTOS_TRNG_PARTIAL_DATA  == status)
00184                     {
00185                         pal_osDelay(PAL_TRNG_COLLECT_DELAY_MILLI_SEC); // sleep to let the device to collect random data.
00186                         randomCounterBytes += trngBytesRead;
00187                         seedPtr += trngBytesRead;
00188                     }
00189                 } while (PAL_ERR_RTOS_TRNG_PARTIAL_DATA  == status);
00190 #else
00191                 status = PAL_ERR_CTR_DRBG_NOT_SEEDED; // No entropy in SOTP and no TRNG = DRBG not seeded
00192 #endif // PAL_USE_HW_TRNG
00193             }
00194             if (PAL_SUCCESS != status)
00195             {
00196                 goto finish;
00197             }
00198             status = pal_CtrDRBGInit(&s_ctrDRBGCtx, (void*)buf, PAL_INITIAL_RANDOM_SIZE);
00199             if (PAL_SUCCESS != status)
00200             {
00201                 PAL_LOG_ERR("Failed to initialize short term DRBG context, status=%" PRIx32 "\n", status);
00202                 goto finish;
00203             }
00204         }
00205         status = pal_plat_generateDrbgWithNoiseAttempt(s_ctrDRBGCtx, randomBuf, false, bufSizeBytes);
00206         if (PAL_SUCCESS != status)
00207         {
00208             PAL_LOG_ERR("Failed to generate random, status=%" PRIx32 "\n", status);
00209         }
00210     }
00211     else
00212     {
00213         return PAL_ERR_NOT_INITIALIZED ;
00214     }
00215 finish:
00216     return status;
00217 }
00218 
00219 
00220 
00221 #endif // !MBED_CONF_MBED_CLOUD_CLIENT_EXTERNAL_SST_SUPPORT