takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DeviceKey.cpp Source File

DeviceKey.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2018 ARM Limited
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 #include "DeviceKey.h"
00018 #include "mbedtls/config.h"
00019 #include "mbedtls/cmac.h"
00020 #include "nvstore.h"
00021 #include "trng_api.h"
00022 #include "mbed_wait_api.h"
00023 #include "stdlib.h"
00024 
00025 #include <string.h>
00026 
00027 #if !defined(MBEDTLS_CMAC_C)
00028 #error [NOT_SUPPORTED] MBEDTLS_CMAC_C needs to be enabled for this driver
00029 #else
00030 
00031 #if NVSTORE_ENABLED
00032 
00033 namespace mbed {
00034 
00035 #define DEVKEY_WRITE_UINT32_LE( dst, src )                              \
00036     do                                                                  \
00037     {                                                                   \
00038         (dst)[0] = ( (src) >> 0 ) & 0xFF;                               \
00039         (dst)[1] = ( (src) >> 8 ) & 0xFF;                               \
00040         (dst)[2] = ( (src) >> 16 ) & 0xFF;                              \
00041         (dst)[3] = ( (src) >> 24 ) & 0xFF;                              \
00042     } while( 0 )
00043 
00044 #define DEVKEY_WRITE_UINT8_LE( dst, src )                               \
00045     do                                                                  \
00046     {                                                                   \
00047         (dst)[0] = (src) & 0xFF;                                        \
00048     } while( 0 )
00049 
00050 
00051 DeviceKey::DeviceKey()
00052 {
00053     return;
00054 }
00055 
00056 DeviceKey::~DeviceKey()
00057 {
00058     return;
00059 }
00060 
00061 int DeviceKey::generate_derived_key(const unsigned char *salt, size_t isalt_size, unsigned char *output,
00062                                     uint16_t ikey_type)
00063 {
00064     uint32_t key_buff[DEVICE_KEY_32BYTE / sizeof(uint32_t)];
00065     size_t actual_size = DEVICE_KEY_32BYTE;
00066 
00067     if (DEVICE_KEY_16BYTE != ikey_type && DEVICE_KEY_32BYTE != ikey_type) {
00068         return DEVICEKEY_INVALID_KEY_TYPE;
00069     }
00070 
00071     //First try to read the key from NVStore
00072     int ret = read_key_from_nvstore(key_buff, actual_size);
00073     if (DEVICEKEY_SUCCESS != ret && DEVICEKEY_NOT_FOUND != ret) {
00074         return ret;
00075     }
00076 
00077     if (DEVICE_KEY_16BYTE != actual_size && DEVICE_KEY_32BYTE != actual_size) {
00078         return DEVICEKEY_READ_FAILED;
00079     }
00080 
00081     //If the key was not found in NVStore we will create it by using TRNG and then save it to NVStore
00082     if (DEVICEKEY_NOT_FOUND == ret) {
00083         ret = generate_key_by_trng(key_buff, actual_size);
00084         if (DEVICEKEY_SUCCESS != ret) {
00085             return ret;
00086         }
00087 
00088         ret = device_inject_root_of_trust(key_buff, actual_size);
00089         if (DEVICEKEY_SUCCESS != ret) {
00090             return ret;
00091         }
00092     }
00093 
00094     ret = get_derived_key(key_buff, actual_size, salt, isalt_size, output, ikey_type);
00095     return ret;
00096 }
00097 
00098 int DeviceKey::device_inject_root_of_trust(uint32_t *value, size_t isize)
00099 {
00100     return write_key_to_nvstore(value, isize);
00101 }
00102 
00103 int DeviceKey::write_key_to_nvstore(uint32_t *input, size_t isize)
00104 {
00105     if (DEVICE_KEY_16BYTE != isize && DEVICE_KEY_32BYTE != isize) {
00106         return DEVICEKEY_INVALID_KEY_SIZE;
00107     }
00108 
00109     //First we read if key exist. If it is exists, we return DEVICEKEY_ALREADY_EXIST error
00110     uint32_t read_key[DEVICE_KEY_32BYTE / sizeof(uint32_t)] = {0};
00111     size_t read_size = DEVICE_KEY_32BYTE;
00112     int ret = read_key_from_nvstore(read_key, read_size);
00113     if (DEVICEKEY_SUCCESS == ret) {
00114         return DEVICEKEY_ALREADY_EXIST;
00115     }
00116     if (DEVICEKEY_NOT_FOUND != ret) {
00117         return ret;
00118     }
00119 
00120     NVStore& nvstore = NVStore::get_instance();
00121     ret = nvstore.set(NVSTORE_DEVICEKEY_KEY, (uint16_t)isize, input);
00122     if (NVSTORE_WRITE_ERROR == ret || NVSTORE_BUFF_TOO_SMALL == ret) {
00123         return DEVICEKEY_SAVE_FAILED;
00124     }
00125 
00126     if (NVSTORE_SUCCESS != ret) {
00127         return DEVICEKEY_NVSTORE_UNPREDICTED_ERROR;
00128     }
00129 
00130     return DEVICEKEY_SUCCESS;
00131 }
00132 
00133 int DeviceKey::read_key_from_nvstore(uint32_t *output, size_t& size)
00134 {
00135     if (size > (uint16_t)-1) {
00136         return DEVICEKEY_INVALID_PARAM;
00137     }
00138 
00139     uint16_t in_size = size;
00140     uint16_t out_size = 0;
00141     NVStore& nvstore = NVStore::get_instance();
00142     int nvStatus = nvstore.get(NVSTORE_DEVICEKEY_KEY, in_size, output, out_size);
00143     if (NVSTORE_NOT_FOUND == nvStatus) {
00144         return DEVICEKEY_NOT_FOUND;
00145     }
00146 
00147     if (NVSTORE_READ_ERROR == nvStatus || NVSTORE_BUFF_TOO_SMALL == nvStatus) {
00148         return DEVICEKEY_READ_FAILED;
00149     }
00150 
00151     if (NVSTORE_SUCCESS != nvStatus) {
00152         return DEVICEKEY_NVSTORE_UNPREDICTED_ERROR;
00153     }
00154 
00155     size = out_size;
00156     return DEVICEKEY_SUCCESS;
00157 }
00158 
00159 int DeviceKey::get_derived_key(uint32_t *ikey_buff, size_t ikey_size, const unsigned char *isalt,
00160                                size_t isalt_size, unsigned char *output, uint32_t ikey_type)
00161 {
00162     //KDF in counter mode implementation as described in Section 5.1
00163     //of NIST SP 800-108, Recommendation for Key Derivation Using Pseudorandom Functions
00164     int ret;
00165     size_t counter = 0;
00166     char separator = 0x00;
00167     mbedtls_cipher_context_t ctx;
00168     unsigned char output_len_enc[ 4 ] = {0};
00169     unsigned char counter_enc[ 1 ] = {0};
00170 
00171     DEVKEY_WRITE_UINT32_LE(output_len_enc, ikey_type);
00172 
00173     mbedtls_cipher_type_t mbedtls_cipher_type = MBEDTLS_CIPHER_AES_128_ECB;
00174     if (DEVICE_KEY_32BYTE == ikey_size) {
00175         mbedtls_cipher_type = MBEDTLS_CIPHER_AES_256_ECB;
00176     }
00177 
00178     const mbedtls_cipher_info_t *cipher_info = mbedtls_cipher_info_from_type(mbedtls_cipher_type);
00179 
00180     do {
00181 
00182         mbedtls_cipher_init(&ctx);
00183         ret = mbedtls_cipher_setup(&ctx, cipher_info);
00184         if (ret != 0) {
00185             goto finish;
00186         }
00187 
00188         ret = mbedtls_cipher_cmac_starts(&ctx, (unsigned char *)ikey_buff, ikey_size * 8);
00189         if (ret != 0) {
00190             goto finish;
00191         }
00192 
00193         DEVKEY_WRITE_UINT8_LE(counter_enc, (counter+1));
00194 
00195         ret = mbedtls_cipher_cmac_update(&ctx, (unsigned char *)counter_enc, sizeof(counter_enc));
00196         if (ret != 0) {
00197             goto finish;
00198         }
00199 
00200         ret = mbedtls_cipher_cmac_update(&ctx, isalt, isalt_size);
00201         if (ret != 0) {
00202             goto finish;
00203         }
00204 
00205         ret = mbedtls_cipher_cmac_update(&ctx, (unsigned char *)&separator, sizeof(char));
00206         if (ret != 0) {
00207             goto finish;
00208         }
00209 
00210         ret = mbedtls_cipher_cmac_update(&ctx, (unsigned char *)&output_len_enc, sizeof(output_len_enc));
00211         if (ret != 0) {
00212             goto finish;
00213         }
00214 
00215         ret = mbedtls_cipher_cmac_finish(&ctx, output + (DEVICE_KEY_16BYTE * (counter)));
00216         if (ret != 0) {
00217             goto finish;
00218         }
00219 
00220         mbedtls_cipher_free( &ctx );
00221 
00222         counter++;
00223 
00224     } while (DEVICE_KEY_16BYTE * counter < ikey_type);
00225 
00226 finish:
00227     if (DEVICEKEY_SUCCESS != ret) {
00228         mbedtls_cipher_free( &ctx );
00229         return DEVICEKEY_ERR_CMAC_GENERIC_FAILURE;
00230     }
00231 
00232     return DEVICEKEY_SUCCESS;
00233 }
00234 
00235 int DeviceKey::generate_key_by_trng(uint32_t *output, size_t size)
00236 {
00237 #if defined(DEVICE_TRNG)
00238     size_t in_size;
00239     size_t ongoing_size;
00240     trng_t trng_obj;
00241     int ret = DEVICEKEY_SUCCESS;
00242     unsigned char *pBuffer = (unsigned char *)output;
00243 
00244     memset(output, 0, size);
00245 
00246     if (DEVICE_KEY_16BYTE > size) {
00247         return DEVICEKEY_BUFFER_TOO_SMALL;
00248     } else if (DEVICE_KEY_16BYTE != size && DEVICE_KEY_32BYTE != size) {
00249         return DEVICEKEY_INVALID_PARAM;
00250     }
00251 
00252     trng_init(&trng_obj);
00253 
00254     in_size = size;
00255     while (in_size > 0) {
00256 
00257         ongoing_size = 0;
00258         ret = trng_get_bytes(&trng_obj, (unsigned char *)pBuffer, in_size, &ongoing_size);
00259         if (0 != ret || ongoing_size > in_size) {
00260             ret = DEVICEKEY_TRNG_ERROR;
00261             goto finish;
00262         }
00263 
00264         pBuffer += ongoing_size;
00265         in_size -= ongoing_size;
00266     }
00267 
00268     ret = DEVICEKEY_SUCCESS;
00269 
00270 finish:
00271     trng_free(&trng_obj);
00272     return ret;
00273 
00274 #else
00275     return DEVICEKEY_NO_KEY_INJECTED;
00276 #endif
00277 }
00278 
00279 } // namespace mbed
00280 
00281 #endif //NVSTORE_ENABLED
00282 #endif
00283 
00284