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