mirror of https://github.com/ARMmbed/mbed-os.git
Device key implementation
parent
f895392374
commit
a8febd57a1
|
|
@ -0,0 +1,150 @@
|
|||
"""
|
||||
Copyright (c) 2018 ARM Limited
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import time
|
||||
from mbed_host_tests import BaseHostTest
|
||||
from mbed_host_tests.host_tests_runner.host_test_default import DefaultTestSelector
|
||||
|
||||
DEFAULT_CYCLE_PERIOD = 1.0
|
||||
MSG_VALUE_DUMMY = '0'
|
||||
MSG_KEY_DEVICE_READY = 'ready'
|
||||
MSG_KEY_DEVICE_FINISH = 'finish'
|
||||
MSG_KEY_DEVICE_TEST_STEP1 = 'check_consistency_step1'
|
||||
MSG_KEY_DEVICE_TEST_STEP2 = 'check_consistency_step2'
|
||||
MSG_KEY_DEVICE_TEST_STEP3 = 'check_consistency_step3'
|
||||
MSG_KEY_DEVICE_TEST_STEP4 = 'check_consistency_step4'
|
||||
MSG_KEY_SYNC = '__sync'
|
||||
MSG_KEY_TEST_SUITE_ENDED = 'Test suite ended'
|
||||
|
||||
class DeviceKeyResetTest(BaseHostTest):
|
||||
"""Test for the DeviceKey driver API.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(DeviceKeyResetTest, self).__init__()
|
||||
self.reset = False
|
||||
self.finish = False
|
||||
self.suite_ended = False
|
||||
cycle_s = self.get_config_item('program_cycle_s')
|
||||
self.program_cycle_s = cycle_s if cycle_s is not None else DEFAULT_CYCLE_PERIOD
|
||||
self.test_steps_sequence = self.test_steps()
|
||||
# Advance the coroutine to it's first yield statement.
|
||||
self.test_steps_sequence.send(None)
|
||||
|
||||
def setup(self):
|
||||
self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready)
|
||||
self.register_callback(MSG_KEY_DEVICE_FINISH, self.cb_device_finish)
|
||||
self.register_callback(MSG_KEY_TEST_SUITE_ENDED, self.cb_device_test_suit_ended)
|
||||
|
||||
def cb_device_ready(self, key, value, timestamp):
|
||||
"""Acknowledge device rebooted correctly and feed the test execution
|
||||
"""
|
||||
self.reset = True
|
||||
|
||||
try:
|
||||
if self.test_steps_sequence.send(value):
|
||||
self.notify_complete(True)
|
||||
except (StopIteration, RuntimeError) as exc:
|
||||
self.notify_complete(False)
|
||||
|
||||
def cb_device_finish(self, key, value, timestamp):
|
||||
"""Acknowledge device finished a test step correctly and feed the test execution
|
||||
"""
|
||||
self.finish = True
|
||||
|
||||
try:
|
||||
if self.test_steps_sequence.send(value):
|
||||
self.notify_complete(True)
|
||||
except (StopIteration, RuntimeError) as exc:
|
||||
self.notify_complete(False)
|
||||
|
||||
def cb_device_test_suit_ended(self, key, value, timestamp):
|
||||
"""Acknowledge device finished a test step correctly and feed the test execution
|
||||
"""
|
||||
self.suite_ended = True
|
||||
|
||||
try:
|
||||
if self.test_steps_sequence.send(value):
|
||||
self.notify_complete(True)
|
||||
except (StopIteration, RuntimeError) as exc:
|
||||
self.notify_complete(False)
|
||||
|
||||
def test_steps(self):
|
||||
"""Test step 1 (16 byte key test)
|
||||
"""
|
||||
wait_for_communication = yield
|
||||
|
||||
self.reset = False
|
||||
self.send_kv(MSG_KEY_DEVICE_TEST_STEP1, MSG_VALUE_DUMMY)
|
||||
time.sleep(self.program_cycle_s)
|
||||
self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY)
|
||||
|
||||
wait_for_communication = yield
|
||||
|
||||
if self.reset == False:
|
||||
raise RuntimeError('Phase 1: Platform did not reset as expected.')
|
||||
|
||||
"""Test step 2 (After reset)
|
||||
"""
|
||||
self.finish = False
|
||||
self.send_kv(MSG_KEY_DEVICE_TEST_STEP2, MSG_VALUE_DUMMY)
|
||||
time.sleep(self.program_cycle_s)
|
||||
wait_for_communication = yield
|
||||
|
||||
if self.finish == False:
|
||||
raise RuntimeError('Test failed.')
|
||||
|
||||
"""Test Step 3 (32 byte key test)
|
||||
"""
|
||||
wait_for_communication = yield
|
||||
|
||||
self.reset = False
|
||||
self.send_kv(MSG_KEY_DEVICE_TEST_STEP3, MSG_VALUE_DUMMY)
|
||||
time.sleep(self.program_cycle_s)
|
||||
self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY)
|
||||
|
||||
wait_for_communication = yield
|
||||
|
||||
if self.reset == False:
|
||||
raise RuntimeError('Phase 3: Platform did not reset as expected.')
|
||||
|
||||
"""Test step 4 (After reset)
|
||||
"""
|
||||
self.finish = False
|
||||
self.send_kv(MSG_KEY_DEVICE_TEST_STEP4, MSG_VALUE_DUMMY)
|
||||
time.sleep(self.program_cycle_s)
|
||||
|
||||
wait_for_communication = yield
|
||||
|
||||
if self.finish == False:
|
||||
raise RuntimeError('Test failed.')
|
||||
|
||||
"""Test step 4 (After reset)
|
||||
"""
|
||||
self.suite_ended = False
|
||||
time.sleep(self.program_cycle_s)
|
||||
|
||||
wait_for_communication = yield
|
||||
|
||||
if self.suite_ended == False:
|
||||
raise RuntimeError('Test failed.')
|
||||
|
||||
# The sequence is correct -- test passed.
|
||||
yield True
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,488 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "DeviceKey.h"
|
||||
#include "utest/utest.h"
|
||||
#include "unity/unity.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "nvstore.h"
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
#define MSG_VALUE_DUMMY "0"
|
||||
#define MSG_VALUE_LEN 32
|
||||
#define MSG_KEY_LEN 32
|
||||
|
||||
#define MSG_KEY_DEVICE_READY "ready"
|
||||
#define MSG_KEY_DEVICE_FINISH "finish"
|
||||
#define MSG_KEY_DEVICE_TEST_STEP1 "check_consistency_step1"
|
||||
#define MSG_KEY_DEVICE_TEST_STEP2 "check_consistency_step2"
|
||||
#define MSG_KEY_DEVICE_TEST_STEP3 "check_consistency_step3"
|
||||
#define MSG_KEY_DEVICE_TEST_STEP4 "check_consistency_step4"
|
||||
#define MSG_KEY_DEVICE_TEST_SUITE_ENDED "Test suite ended"
|
||||
|
||||
void device_key_derived_key_consistency_16_byte_key_reset_test(char *key);
|
||||
void device_key_derived_key_consistency_32_byte_key_reset_test(char *key);
|
||||
|
||||
/*
|
||||
* Injection of a dummy key when there is no TRNG
|
||||
*/
|
||||
int inject_dummy_rot_key()
|
||||
{
|
||||
#if !defined(DEVICE_TRNG)
|
||||
uint32_t key[DEVICE_KEY_16BYTE / sizeof(uint32_t)];
|
||||
|
||||
memset(key, 0, DEVICE_KEY_16BYTE);
|
||||
memcpy(key, "1234567812345678", DEVICE_KEY_16BYTE);
|
||||
int size = DEVICE_KEY_16BYTE;
|
||||
DeviceKey& devkey = DeviceKey::get_instance();
|
||||
return devkey.device_inject_root_of_trust(key, size);
|
||||
#else
|
||||
return DEVICEKEY_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
void device_key_derived_key_reset_test()
|
||||
{
|
||||
greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY);
|
||||
|
||||
static char key[MSG_KEY_LEN + 1] = { };
|
||||
static char value[MSG_VALUE_LEN + 1] = { };
|
||||
memset(key, 0, MSG_KEY_LEN + 1);
|
||||
memset(value, 0, MSG_VALUE_LEN + 1);
|
||||
|
||||
greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);
|
||||
|
||||
if (strcmp(key, MSG_KEY_DEVICE_TEST_STEP1) == 0 || strcmp(key, MSG_KEY_DEVICE_TEST_STEP2) == 0) {
|
||||
device_key_derived_key_consistency_16_byte_key_reset_test(key);
|
||||
return device_key_derived_key_reset_test();
|
||||
}
|
||||
|
||||
if (strcmp(key, MSG_KEY_DEVICE_TEST_STEP3) == 0 || strcmp(key, MSG_KEY_DEVICE_TEST_STEP4) == 0) {
|
||||
return device_key_derived_key_consistency_32_byte_key_reset_test(key);
|
||||
}
|
||||
|
||||
TEST_ASSERT_MESSAGE(false, key); //Indicates error!!!
|
||||
}
|
||||
|
||||
/*
|
||||
* Test the consistency of derived 16 byte key result after device reset.
|
||||
*/
|
||||
void device_key_derived_key_consistency_16_byte_key_reset_test(char *key)
|
||||
{
|
||||
unsigned char output1[DEVICE_KEY_16BYTE];
|
||||
unsigned char output2[DEVICE_KEY_16BYTE];
|
||||
unsigned char empty_buffer[DEVICE_KEY_16BYTE];
|
||||
unsigned char salt[] = "Once upon a time, I worked for the circus and I lived in Omaha.";
|
||||
int key_type = DEVICE_KEY_16BYTE;
|
||||
uint16_t actual_size = 0;
|
||||
DeviceKey& devkey = DeviceKey::get_instance();
|
||||
NVStore& nvstore = NVStore::get_instance();
|
||||
size_t salt_size = sizeof(salt);
|
||||
|
||||
if (strcmp(key, MSG_KEY_DEVICE_TEST_STEP1) == 0) {
|
||||
|
||||
//Third step: Clear NVStore, create an ROT key, derive a 16 byte
|
||||
//key and store it in NVStore at index 15, At the end reset the device
|
||||
int ret = nvstore.reset();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
ret = inject_dummy_rot_key();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
memset(output1, 0, sizeof(output1));
|
||||
ret = devkey.device_key_derived_key(salt, salt_size, output1, key_type);
|
||||
TEST_ASSERT_EQUAL_INT32(0, ret);
|
||||
bool is_empty = !memcmp(empty_buffer, output1, sizeof(output1));
|
||||
TEST_ASSERT_FALSE(is_empty);
|
||||
|
||||
ret = nvstore.set(15, DEVICE_KEY_16BYTE, output1);
|
||||
TEST_ASSERT_EQUAL_INT32(0, ret);
|
||||
|
||||
system_reset();
|
||||
TEST_ASSERT_MESSAGE(false, "system_reset() did not reset the device as expected.");
|
||||
} else if (strcmp(key, MSG_KEY_DEVICE_TEST_STEP2) == 0) {
|
||||
|
||||
//Second step: Read from NVStore at index 15 there should be a derived key there.
|
||||
//Now try to derive a key for 100 times and check it is the same key like before the reset.
|
||||
//At the end clear NVStore.
|
||||
int ret = nvstore.get(15, DEVICE_KEY_16BYTE, output1, actual_size);
|
||||
TEST_ASSERT_FALSE(NVSTORE_SUCCESS != ret)
|
||||
TEST_ASSERT_EQUAL_INT(DEVICE_KEY_16BYTE, actual_size);
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
memset(output2, 0, sizeof(output2));
|
||||
ret = devkey.device_key_derived_key(salt, salt_size, output2, key_type);
|
||||
TEST_ASSERT_EQUAL_INT32(0, ret);
|
||||
TEST_ASSERT_EQUAL_UINT8_ARRAY(output1, output2, DEVICE_KEY_16BYTE);
|
||||
}
|
||||
|
||||
ret = nvstore.reset();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
greentea_send_kv(MSG_KEY_DEVICE_FINISH, MSG_VALUE_DUMMY);
|
||||
} else {
|
||||
TEST_ASSERT_MESSAGE(false, "Unknown test step received");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test the consistency of derived 32 byte key result after device reset.
|
||||
*/
|
||||
void device_key_derived_key_consistency_32_byte_key_reset_test(char *key)
|
||||
{
|
||||
unsigned char output1[DEVICE_KEY_32BYTE];
|
||||
unsigned char output2[DEVICE_KEY_32BYTE];
|
||||
unsigned char empty_buffer[DEVICE_KEY_32BYTE];
|
||||
unsigned char salt[] = "The quick brown fox jumps over the lazy dog";
|
||||
int key_type = DEVICE_KEY_32BYTE;
|
||||
uint16_t actual_size = 0;
|
||||
DeviceKey& devkey = DeviceKey::get_instance();
|
||||
NVStore& nvstore = NVStore::get_instance();
|
||||
size_t salt_size = sizeof(salt);
|
||||
|
||||
if (strcmp(key, MSG_KEY_DEVICE_TEST_STEP3) == 0) {
|
||||
|
||||
//Third step: Clear NVStore, create an ROT key, derive a 32 byte
|
||||
//key and store it in NVStore at index 15, At the end reset the device
|
||||
int ret = nvstore.reset();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
ret = inject_dummy_rot_key();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
memset(output1, 0, sizeof(output1));
|
||||
ret = devkey.device_key_derived_key(salt, salt_size, output1, key_type);
|
||||
TEST_ASSERT_EQUAL_INT32(0, ret);
|
||||
bool is_empty = !memcmp(empty_buffer, output1, sizeof(output1));
|
||||
TEST_ASSERT_FALSE(is_empty);
|
||||
|
||||
ret = nvstore.set(15, DEVICE_KEY_32BYTE, output1);
|
||||
TEST_ASSERT_EQUAL_INT32(0, ret);
|
||||
|
||||
system_reset();
|
||||
TEST_ASSERT_MESSAGE(false, "system_reset() did not reset the device as expected.");
|
||||
} else if (strcmp(key, MSG_KEY_DEVICE_TEST_STEP4) == 0) {
|
||||
|
||||
//Fourth step: Read from NVStore at index 15 there should be a derived key there.
|
||||
//Now try to derive a key for 100 times and check it is the same key like before the reset.
|
||||
//At the end clear NVStore.
|
||||
int ret = nvstore.get(15, DEVICE_KEY_32BYTE, output1, actual_size);
|
||||
TEST_ASSERT_FALSE(NVSTORE_SUCCESS != ret)
|
||||
TEST_ASSERT_EQUAL_INT(DEVICE_KEY_32BYTE, actual_size);
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
memset(output2, 0, sizeof(output2));
|
||||
ret = devkey.device_key_derived_key(salt, salt_size, output2, key_type);
|
||||
TEST_ASSERT_EQUAL_INT32(0, ret);
|
||||
TEST_ASSERT_EQUAL_UINT8_ARRAY(output1, output2, DEVICE_KEY_32BYTE);
|
||||
}
|
||||
|
||||
ret = nvstore.reset();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
greentea_send_kv(MSG_KEY_DEVICE_FINISH, MSG_VALUE_DUMMY);
|
||||
} else {
|
||||
TEST_ASSERT_MESSAGE(false, "Unknown test step received");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that wrong size of key is rejected when trying to persist a key
|
||||
*/
|
||||
void device_inject_root_of_trust_wrong_size_test()
|
||||
{
|
||||
DeviceKey& devkey = DeviceKey::get_instance();
|
||||
uint32_t key[DEVICE_KEY_32BYTE / sizeof(uint32_t)];
|
||||
|
||||
memcpy(key, "12345678123456788765432187654321", DEVICE_KEY_32BYTE);
|
||||
|
||||
for (int i = 0; i < 50; i++) {
|
||||
if (DEVICE_KEY_16BYTE == i || DEVICE_KEY_32BYTE == i) {
|
||||
continue;
|
||||
}
|
||||
int ret = devkey.device_inject_root_of_trust(key, i);
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_INVALID_KEY_SIZE, ret);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that a 16 byte size key is written to persistent storage
|
||||
*/
|
||||
void device_inject_root_of_trust_16_byte_size_test()
|
||||
{
|
||||
DeviceKey& devkey = DeviceKey::get_instance();
|
||||
uint32_t rkey[DEVICE_KEY_16BYTE / sizeof(uint32_t)];
|
||||
uint16_t actual_size;
|
||||
uint32_t key[DEVICE_KEY_16BYTE / sizeof(uint32_t)];
|
||||
NVStore& nvstore = NVStore::get_instance();
|
||||
|
||||
int ret = nvstore.reset();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
memcpy(key, "1234567812345678", sizeof(key));
|
||||
ret = devkey.device_inject_root_of_trust(key, DEVICE_KEY_16BYTE);
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
//Read the key from NVStore.
|
||||
memset(rkey, 0, sizeof(rkey));
|
||||
ret = nvstore.get(NVSTORE_DEVICEKEY_KEY, DEVICE_KEY_16BYTE, rkey, actual_size);
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
TEST_ASSERT_EQUAL_INT(DEVICE_KEY_16BYTE, actual_size);
|
||||
TEST_ASSERT_EQUAL_INT32_ARRAY(key, rkey, actual_size / sizeof(uint32_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that a 32 byte size key is written to persistent storage
|
||||
*/
|
||||
void device_inject_root_of_trust_32_byte_size_test()
|
||||
{
|
||||
DeviceKey& devkey = DeviceKey::get_instance();
|
||||
uint32_t rkey[DEVICE_KEY_32BYTE / sizeof(uint32_t)];
|
||||
uint16_t actual_size;
|
||||
uint32_t key[DEVICE_KEY_32BYTE / sizeof(uint32_t)];
|
||||
NVStore& nvstore = NVStore::get_instance();
|
||||
|
||||
int ret = nvstore.reset();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
memcpy(key, "12345678123456788765432187654321", sizeof(key));
|
||||
ret = devkey.device_inject_root_of_trust(key, DEVICE_KEY_32BYTE);
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
//Read the key from NVStore.
|
||||
memset(rkey, 0, sizeof(rkey));
|
||||
ret = nvstore.get(NVSTORE_DEVICEKEY_KEY, DEVICE_KEY_32BYTE, rkey, actual_size);
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
TEST_ASSERT_EQUAL_INT(DEVICE_KEY_32BYTE, actual_size);
|
||||
TEST_ASSERT_EQUAL_INT32_ARRAY(key, rkey, actual_size / sizeof(uint32_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that a key can be written to persistent storage only once.
|
||||
*/
|
||||
void device_inject_root_of_trust_several_times_test()
|
||||
{
|
||||
DeviceKey& devkey = DeviceKey::get_instance();
|
||||
uint32_t key[DEVICE_KEY_32BYTE / sizeof(uint32_t)];
|
||||
NVStore& nvstore = NVStore::get_instance();
|
||||
|
||||
int ret = nvstore.reset();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
memcpy(key, "12345678123456788765432187654321", DEVICE_KEY_32BYTE);
|
||||
ret = devkey.device_inject_root_of_trust(key, DEVICE_KEY_32BYTE);
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
//Trying to use the same key should fail.
|
||||
ret = devkey.device_inject_root_of_trust(key, DEVICE_KEY_32BYTE);
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_ALREADY_EXIST, ret);
|
||||
|
||||
//Trying to use different key should also fail.
|
||||
ret = devkey.device_inject_root_of_trust(key, DEVICE_KEY_16BYTE);
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_ALREADY_EXIST, ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test the consistency of derived 16 byte key result.
|
||||
*/
|
||||
void device_key_derived_key_consistency_16_byte_key_test()
|
||||
{
|
||||
unsigned char output1[DEVICE_KEY_16BYTE];
|
||||
unsigned char output2[DEVICE_KEY_16BYTE];
|
||||
unsigned char empty_buffer[DEVICE_KEY_16BYTE];
|
||||
unsigned char salt[] = "Once upon a time, I worked for the circus and I lived in Omaha.";
|
||||
int key_type = DEVICE_KEY_16BYTE;
|
||||
DeviceKey& devkey = DeviceKey::get_instance();
|
||||
NVStore& nvstore = NVStore::get_instance();
|
||||
|
||||
int ret = nvstore.reset();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
ret = inject_dummy_rot_key();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
size_t salt_size = sizeof(salt);
|
||||
memset(output1, 0, sizeof(output1));
|
||||
ret = devkey.device_key_derived_key(salt, salt_size, output1, key_type);
|
||||
TEST_ASSERT_EQUAL_INT32(0, ret);
|
||||
bool is_empty = !memcmp(empty_buffer, output1, sizeof(output1));
|
||||
TEST_ASSERT_FALSE(is_empty);
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
memset(output2, 0, sizeof(output2));
|
||||
ret = devkey.device_key_derived_key(salt, salt_size, output2, key_type);
|
||||
TEST_ASSERT_EQUAL_INT32(0, ret);
|
||||
TEST_ASSERT_EQUAL_UINT8_ARRAY(output1, output2, DEVICE_KEY_16BYTE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test the consistency of derived 32 byte key result.
|
||||
*/
|
||||
void device_key_derived_key_consistency_32_byte_key_test()
|
||||
{
|
||||
unsigned char output1[DEVICE_KEY_32BYTE];
|
||||
unsigned char output2[DEVICE_KEY_32BYTE];
|
||||
unsigned char empty_buffer[DEVICE_KEY_32BYTE];
|
||||
unsigned char salt[] = "The quick brown fox jumps over the lazy dog";
|
||||
int key_type = DEVICE_KEY_32BYTE;
|
||||
DeviceKey& devkey = DeviceKey::get_instance();
|
||||
NVStore& nvstore = NVStore::get_instance();
|
||||
|
||||
int ret = nvstore.reset();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
ret = inject_dummy_rot_key();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
size_t salt_size = sizeof(salt);
|
||||
memset(output1, 0, sizeof(output1));
|
||||
ret = devkey.device_key_derived_key(salt, salt_size, output1, key_type);
|
||||
TEST_ASSERT_EQUAL_INT32(0, ret);
|
||||
bool is_empty = !memcmp(empty_buffer, output1, sizeof(output1));
|
||||
TEST_ASSERT_FALSE(is_empty);
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
memset(output2, 0, sizeof(output2));
|
||||
ret = devkey.device_key_derived_key(salt, salt_size, output2, key_type);
|
||||
TEST_ASSERT_EQUAL_INT32(0, ret);
|
||||
TEST_ASSERT_EQUAL_UINT8_ARRAY(output1, output2, DEVICE_KEY_32BYTE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test request for 16 byte key is returning a correct key size.
|
||||
*/
|
||||
void device_key_derived_key_key_type_16_test()
|
||||
{
|
||||
unsigned char output[DEVICE_KEY_16BYTE * 2];
|
||||
unsigned char salt[] = "The quick brown fox jumps over the lazy dog";
|
||||
unsigned char expectedString[] = "Some String";
|
||||
int key_type = DEVICE_KEY_16BYTE;
|
||||
size_t salt_size = sizeof(salt);
|
||||
DeviceKey& devkey = DeviceKey::get_instance();
|
||||
NVStore& nvstore = NVStore::get_instance();
|
||||
|
||||
int ret = nvstore.reset();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
ret = inject_dummy_rot_key();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
memset(output, 0, DEVICE_KEY_16BYTE * 2);
|
||||
memcpy(output + DEVICE_KEY_16BYTE - sizeof(expectedString), expectedString, sizeof(expectedString));
|
||||
memcpy(output + DEVICE_KEY_16BYTE + 1, expectedString, sizeof(expectedString));
|
||||
|
||||
ret = devkey.device_key_derived_key(salt, salt_size, output, key_type);
|
||||
TEST_ASSERT_EQUAL_INT32(0, ret);
|
||||
//Test that we didn't override the buffer after the 16 byte size
|
||||
TEST_ASSERT_EQUAL_UINT8_ARRAY(output + DEVICE_KEY_16BYTE + 1, expectedString, sizeof(expectedString));
|
||||
//Test that we did override the buffer all 16 byte
|
||||
TEST_ASSERT(memcmp(output + DEVICE_KEY_16BYTE - sizeof(expectedString), expectedString, sizeof(expectedString)) != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test request for 32 byte key is returning a correct key size.
|
||||
*/
|
||||
void device_key_derived_key_key_type_32_test()
|
||||
{
|
||||
unsigned char output[DEVICE_KEY_32BYTE * 2];
|
||||
unsigned char salt[] = "The quick brown fox jumps over the lazy dog";
|
||||
int key_type = DEVICE_KEY_32BYTE;
|
||||
size_t salt_size = sizeof(salt);
|
||||
unsigned char expectedString[] = "Some String";
|
||||
DeviceKey& devkey = DeviceKey::get_instance();
|
||||
NVStore& nvstore = NVStore::get_instance();
|
||||
|
||||
int ret = nvstore.reset();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
ret = inject_dummy_rot_key();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
memset(output, 0, DEVICE_KEY_32BYTE * 2);
|
||||
memcpy(output + DEVICE_KEY_32BYTE - sizeof(expectedString), expectedString, sizeof(expectedString));
|
||||
memcpy(output + DEVICE_KEY_32BYTE + 1, expectedString, sizeof(expectedString));
|
||||
|
||||
ret = devkey.device_key_derived_key(salt, salt_size, output, key_type);
|
||||
TEST_ASSERT_EQUAL_INT32(0, ret);
|
||||
//Test that we didn't override the buffer after the 32 byte size
|
||||
TEST_ASSERT_EQUAL_UINT8_ARRAY(output + DEVICE_KEY_32BYTE + 1, expectedString, sizeof(expectedString));
|
||||
//Test that we did override the buffer all 32 byte
|
||||
TEST_ASSERT(memcmp(output + DEVICE_KEY_32BYTE - sizeof(expectedString), expectedString, sizeof(expectedString)) != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test request for unknown key size returns an error
|
||||
*/
|
||||
void device_key_derived_key_wrong_key_type_test()
|
||||
{
|
||||
unsigned char output[DEVICE_KEY_16BYTE];
|
||||
unsigned char salt[] = "The quick brown fox jumps over the lazy dog";
|
||||
size_t salt_size = sizeof(salt);
|
||||
DeviceKey& devkey = DeviceKey::get_instance();
|
||||
NVStore& nvstore = NVStore::get_instance();
|
||||
|
||||
nvstore.init();
|
||||
int ret = nvstore.reset();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
ret = inject_dummy_rot_key();
|
||||
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
|
||||
|
||||
memset(output, 0, DEVICE_KEY_32BYTE);
|
||||
ret = devkey.device_key_derived_key(salt, salt_size, output, 12);//96 bit key type is not supported
|
||||
TEST_ASSERT_EQUAL_INT32(DEVICEKEY_INVALID_KEY_TYPE, ret);
|
||||
|
||||
}
|
||||
|
||||
utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason)
|
||||
{
|
||||
greentea_case_failure_abort_handler(source, reason);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
//Currently there can be only one test that contains reset and it has to be the first test!
|
||||
Case cases[] = {
|
||||
Case("Device Key - derived key reset", device_key_derived_key_reset_test, greentea_failure_handler),
|
||||
Case("Device Key - inject value wrong size", device_inject_root_of_trust_wrong_size_test, greentea_failure_handler),
|
||||
Case("Device Key - inject value 16 byte size", device_inject_root_of_trust_16_byte_size_test, greentea_failure_handler),
|
||||
Case("Device Key - inject value 32 byte size", device_inject_root_of_trust_32_byte_size_test, greentea_failure_handler),
|
||||
Case("Device Key - inject value several times", device_inject_root_of_trust_several_times_test, greentea_failure_handler),
|
||||
Case("Device Key - derived key consistency 16 byte key", device_key_derived_key_consistency_16_byte_key_test, greentea_failure_handler),
|
||||
Case("Device Key - derived key consistency 32 byte key", device_key_derived_key_consistency_32_byte_key_test, greentea_failure_handler),
|
||||
Case("Device Key - derived key key type 16", device_key_derived_key_key_type_16_test, greentea_failure_handler),
|
||||
Case("Device Key - derived key key type 32", device_key_derived_key_key_type_32_test, greentea_failure_handler),
|
||||
Case("Device Key - derived key wrong key type", device_key_derived_key_wrong_key_type_test, greentea_failure_handler)
|
||||
};
|
||||
|
||||
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
||||
{
|
||||
GREENTEA_SETUP(14, "devicekey_reset");
|
||||
return greentea_test_setup_handler(number_of_cases);
|
||||
}
|
||||
|
||||
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
|
||||
|
||||
int main()
|
||||
{
|
||||
bool ret = Harness::run(specification);
|
||||
greentea_send_kv(MSG_KEY_DEVICE_TEST_SUITE_ENDED, MSG_VALUE_DUMMY);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,252 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "drivers/DeviceKey.h"
|
||||
#include "mbedtls/config.h"
|
||||
#include "mbedtls/cmac.h"
|
||||
#include "nvstore.h"
|
||||
#include "trng_api.h"
|
||||
|
||||
#if !defined(MBEDTLS_CMAC_C)
|
||||
#error [NOT_SUPPORTED] MBEDTLS_CMAC_C needs to be enabled for this driver
|
||||
#else
|
||||
|
||||
namespace mbed {
|
||||
|
||||
DeviceKey::DeviceKey()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DeviceKey::~DeviceKey()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int DeviceKey::device_key_derived_key(const unsigned char *salt, size_t isalt_size, unsigned char *output,
|
||||
uint16_t ikey_type)
|
||||
{
|
||||
uint32_t key_buff[DEVICE_KEY_32BYTE / sizeof(uint32_t)];
|
||||
size_t actual_size = DEVICE_KEY_32BYTE;
|
||||
|
||||
if (DEVICE_KEY_16BYTE != ikey_type && DEVICE_KEY_32BYTE != ikey_type) {
|
||||
return DEVICEKEY_INVALID_KEY_TYPE;
|
||||
}
|
||||
|
||||
//First try to read the key from NVStore
|
||||
int ret = read_key_from_nvstore(key_buff, actual_size);
|
||||
if (DEVICEKEY_SUCCESS != ret && DEVICEKEY_NOT_FOUND != ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (DEVICE_KEY_16BYTE != actual_size && DEVICE_KEY_32BYTE != actual_size) {
|
||||
return DEVICEKEY_READ_FAILED;
|
||||
}
|
||||
|
||||
//If the key was not found in NVStore we will create it by using TRNG and then save it to NVStore
|
||||
if (DEVICEKEY_NOT_FOUND == ret) {
|
||||
ret = generate_key_by_trng(key_buff, actual_size);
|
||||
if (DEVICEKEY_SUCCESS != ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = device_inject_root_of_trust(key_buff, actual_size);
|
||||
if (DEVICEKEY_SUCCESS != ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = get_derived_key(key_buff, actual_size, salt, isalt_size, output, ikey_type);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int DeviceKey::device_inject_root_of_trust(uint32_t *value, size_t isize)
|
||||
{
|
||||
return write_key_to_nvstore(value, isize);
|
||||
}
|
||||
|
||||
int DeviceKey::write_key_to_nvstore(uint32_t *input, size_t isize)
|
||||
{
|
||||
if (DEVICE_KEY_16BYTE != isize && DEVICE_KEY_32BYTE != isize) {
|
||||
return DEVICEKEY_INVALID_KEY_SIZE;
|
||||
}
|
||||
|
||||
//First we read if key exist. If it is exists, we return DEVICEKEY_ALREADY_EXIST error
|
||||
uint32_t read_key[DEVICE_KEY_32BYTE / sizeof(uint32_t)] = {0};
|
||||
size_t read_size = DEVICE_KEY_32BYTE;
|
||||
int ret = read_key_from_nvstore(read_key, read_size);
|
||||
if (DEVICEKEY_SUCCESS == ret) {
|
||||
return DEVICEKEY_ALREADY_EXIST;
|
||||
}
|
||||
if (DEVICEKEY_NOT_FOUND != ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
NVStore& nvstore = NVStore::get_instance();
|
||||
ret = nvstore.set(NVSTORE_DEVICEKEY_KEY, (uint16_t)isize, input);
|
||||
if (NVSTORE_WRITE_ERROR == ret || NVSTORE_BUFF_TOO_SMALL == ret) {
|
||||
return DEVICEKEY_SAVE_FAILED;
|
||||
}
|
||||
|
||||
if (NVSTORE_SUCCESS != ret) {
|
||||
return DEVICEKEY_NVSTORE_UNPREDICTABLE_ERROR;
|
||||
}
|
||||
|
||||
return DEVICEKEY_SUCCESS;
|
||||
}
|
||||
|
||||
int DeviceKey::read_key_from_nvstore(uint32_t *output, size_t& size)
|
||||
{
|
||||
if (size > UINT16_MAX) {
|
||||
return DEVICEKEY_INVALID_PARAM;
|
||||
}
|
||||
|
||||
uint16_t in_size = size;
|
||||
uint16_t out_size = 0;
|
||||
NVStore& nvstore = NVStore::get_instance();
|
||||
int nvStatus = nvstore.get(NVSTORE_DEVICEKEY_KEY, in_size, output, out_size);
|
||||
if (NVSTORE_NOT_FOUND == nvStatus) {
|
||||
return DEVICEKEY_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (NVSTORE_READ_ERROR == nvStatus || NVSTORE_BUFF_TOO_SMALL == nvStatus) {
|
||||
return DEVICEKEY_READ_FAILED;
|
||||
}
|
||||
|
||||
if (NVSTORE_SUCCESS != nvStatus) {
|
||||
return DEVICEKEY_NVSTORE_UNPREDICTABLE_ERROR;
|
||||
}
|
||||
|
||||
size = out_size;
|
||||
return DEVICEKEY_SUCCESS;
|
||||
}
|
||||
|
||||
// Calculate CMAC functions - wrapper for mbedtls start/update and finish
|
||||
int DeviceKey::calc_cmac(const unsigned char *input, size_t isize, uint32_t *ikey_buff, int ikey_size,
|
||||
unsigned char *output)
|
||||
{
|
||||
int ret;
|
||||
mbedtls_cipher_context_t ctx;
|
||||
|
||||
mbedtls_cipher_type_t mbedtls_cipher_type = MBEDTLS_CIPHER_AES_128_ECB;
|
||||
if (DEVICE_KEY_32BYTE == ikey_size) {
|
||||
mbedtls_cipher_type = MBEDTLS_CIPHER_AES_256_ECB;
|
||||
}
|
||||
|
||||
const mbedtls_cipher_info_t *cipher_info = mbedtls_cipher_info_from_type(mbedtls_cipher_type);
|
||||
|
||||
mbedtls_cipher_init(&ctx);
|
||||
ret = mbedtls_cipher_setup(&ctx, cipher_info);
|
||||
if (ret != 0) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
ret = mbedtls_cipher_cmac_starts(&ctx, (unsigned char *)ikey_buff, ikey_size * 8);
|
||||
if (ret != 0) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
ret = mbedtls_cipher_cmac_update(&ctx, input, isize);
|
||||
if (ret != 0) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
ret = mbedtls_cipher_cmac_finish(&ctx, output);
|
||||
if (ret != 0) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
return DEVICEKEY_SUCCESS;
|
||||
|
||||
finish:
|
||||
mbedtls_cipher_free( &ctx );
|
||||
return ret;
|
||||
}
|
||||
|
||||
int DeviceKey::get_derived_key(uint32_t *ikey_buff, size_t ikey_size, const unsigned char *isalt,
|
||||
size_t isalt_size, unsigned char *output, uint32_t ikey_type)
|
||||
{
|
||||
int ret;
|
||||
unsigned char *double_size_salt = NULL;
|
||||
|
||||
if (DEVICE_KEY_16BYTE == ikey_type) {
|
||||
ret = calc_cmac(isalt, isalt_size, ikey_buff, ikey_size, output);
|
||||
if (DEVICEKEY_SUCCESS != ret) {
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
if (DEVICE_KEY_32BYTE == ikey_type) {
|
||||
ret = this->calc_cmac(isalt, isalt_size, ikey_buff, ikey_size, output);
|
||||
if (DEVICEKEY_SUCCESS != ret) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
//Double the salt size cause cmac always return just 16 bytes
|
||||
double_size_salt = new unsigned char[isalt_size * 2];
|
||||
memcpy(double_size_salt, isalt, isalt_size);
|
||||
memcpy(double_size_salt + isalt_size, isalt, isalt_size);
|
||||
|
||||
ret = this->calc_cmac(double_size_salt, isalt_size * 2, ikey_buff, ikey_size, output + 16);
|
||||
}
|
||||
|
||||
finish:
|
||||
if (double_size_salt != NULL) {
|
||||
delete[] double_size_salt;
|
||||
}
|
||||
|
||||
if (DEVICEKEY_SUCCESS != ret) {
|
||||
return DEVICEKEY_ERR_CMAC_GENERIC_FAILURE;
|
||||
}
|
||||
|
||||
return DEVICEKEY_SUCCESS;
|
||||
}
|
||||
|
||||
int DeviceKey::generate_key_by_trng(uint32_t *output, size_t& size)
|
||||
{
|
||||
#if defined(DEVICE_TRNG)
|
||||
size_t in_size;
|
||||
trng_t trng_obj;
|
||||
|
||||
memset(output, 0, size);
|
||||
|
||||
if (DEVICE_KEY_16BYTE > size) {
|
||||
return DEVICEKEY_BUFFER_TO_SMALL;
|
||||
} else if (DEVICE_KEY_16BYTE <= size && DEVICE_KEY_32BYTE > size) {
|
||||
in_size = DEVICE_KEY_16BYTE;
|
||||
} else {
|
||||
in_size = DEVICE_KEY_32BYTE;
|
||||
}
|
||||
|
||||
trng_init(&trng_obj);
|
||||
|
||||
int ret = trng_get_bytes(&trng_obj, (unsigned char *)output, in_size, &size);
|
||||
if (DEVICEKEY_SUCCESS != ret || in_size != size) {
|
||||
return DEVICEKEY_TRNG_ERROR;
|
||||
}
|
||||
|
||||
trng_free(&trng_obj);
|
||||
return DEVICEKEY_SUCCESS;
|
||||
#else
|
||||
return DEVICEKEY_NO_KEY_INJECTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace mbed
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef MBED_DEVICEKEY_H
|
||||
#define MBED_DEVICEKEY_H
|
||||
|
||||
#include "stddef.h"
|
||||
#include "stdint.h"
|
||||
#include "platform/NonCopyable.h"
|
||||
|
||||
namespace mbed {
|
||||
/** \addtogroup drivers */
|
||||
|
||||
#define DEVICE_KEY_16BYTE 16
|
||||
#define DEVICE_KEY_32BYTE 32
|
||||
|
||||
enum DeviceKeyStatus {
|
||||
DEVICEKEY_SUCCESS = 0,
|
||||
DEVICEKEY_INVALID_KEY_SIZE = -1,
|
||||
DEVICEKEY_INVALID_KEY_TYPE = -2,
|
||||
DEVICEKEY_SAVE_FAILED = -3,
|
||||
DEVICEKEY_ALREADY_EXIST = -4,
|
||||
DEVICEKEY_NOT_FOUND = -5,
|
||||
DEVICEKEY_READ_FAILED = -6,
|
||||
DEVICEKEY_NVSTORE_UNPREDICTABLE_ERROR = -7,
|
||||
DEVICEKEY_ERR_CMAC_GENERIC_FAILURE = -8,
|
||||
DEVICEKEY_BUFFER_TO_SMALL = -9,
|
||||
DEVICEKEY_NO_KEY_INJECTED = -10,
|
||||
DEVICEKEY_INVALID_PARAM = -11,
|
||||
DEVICEKEY_TRNG_ERROR = -12,
|
||||
};
|
||||
|
||||
/** Use this singleton if you need to derive a new key from the device root of trust.
|
||||
*
|
||||
*
|
||||
* @endcode
|
||||
* @ingroup drivers
|
||||
*/
|
||||
|
||||
class DeviceKey : private mbed::NonCopyable<DeviceKey> {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief As a singleton, return the single instance of the class.
|
||||
* Reason for this class being a singleton is the following:
|
||||
* - Ease the use for users of this class not having to coordinate instantiations.
|
||||
* - Lazy instantiation of internal data (which we can't achieve with simple static classes).
|
||||
*
|
||||
* @returns Singleton instance reference.
|
||||
*/
|
||||
static DeviceKey& get_instance()
|
||||
{
|
||||
// Use this implementation of singleton (Meyer's) rather than the one that allocates
|
||||
// the instance on the heap, as it ensures destruction at program end (preventing warnings
|
||||
// from memory checking tools such as valgrind).
|
||||
static DeviceKey instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
virtual ~DeviceKey();
|
||||
|
||||
/** Derive a new key based on the salt string. key type can be with values 16 bytes and 32 bytes
|
||||
* @param isalt input buffer used to create the new key. Same input will generate always the same key
|
||||
* @param isalt_size size of the data in salt buffer
|
||||
* @param output buffer to receive the derived key. Size must be 16 bytes or 32 bytes
|
||||
* according to the ikey_type parameter
|
||||
* @param ikey_type type of the required key. Type must be 16 bytes or 32 bytes.
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int device_key_derived_key(const unsigned char *isalt, size_t isalt_size, unsigned char *output, uint16_t ikey_type);
|
||||
|
||||
/** Set a device key into the NVStore. In case TRNG support is missing, Call this method
|
||||
* before calling device_key_derived_key. This method should be called only once!
|
||||
* @param value input buffer contain the key.
|
||||
* @param isize size of the supplied key. Must be 16 bytes or 32 bytes.
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int device_inject_root_of_trust(uint32_t *value, size_t isize);
|
||||
|
||||
private:
|
||||
// Private constructor, as class is a singleton
|
||||
DeviceKey();
|
||||
|
||||
/** Calculate CMAC
|
||||
* @param input buffer contain some string.
|
||||
* @param isize size of the supplied input string.
|
||||
* @param ikey_buff input buffer holding the ROT key
|
||||
* @param ikey_size size of the input key. must be 16 bytes or 32 bytes.
|
||||
* @param output buffer for the CMAC result.
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int calc_cmac(const unsigned char *input, size_t isize, uint32_t *ikey_buff, int ikey_size, unsigned char *output);
|
||||
|
||||
/** Read a device key from the NVStore
|
||||
* @param output buffer for the returned key.
|
||||
* @param size input: the size of the output buffer.
|
||||
* output: the actual size of the written data
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int read_key_from_nvstore(uint32_t *output, size_t& size);
|
||||
|
||||
/** Set a device key into the NVStore
|
||||
* @param input input buffer contain the key.
|
||||
* @param isize the size of the input buffer.
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int write_key_to_nvstore(uint32_t *input, size_t isize);
|
||||
|
||||
/** Get a derived key base on a salt string
|
||||
* @param ikey_buff input buffer holding the ROT key
|
||||
* @param ikey_size size of the input key. Must be 16 bytes or 32 bytes.
|
||||
* @param isalt input buffer contain some string.
|
||||
* @param isalt_size size of the supplied input string.
|
||||
* @param output buffer for the derived key result.
|
||||
* @param ikey_type the requested key size. Must be 16 bytes or 32 bytes.
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int get_derived_key(uint32_t *ikey_buff, size_t ikey_size, const unsigned char *isalt, size_t isalt_size,
|
||||
unsigned char *output, uint32_t ikey_type);
|
||||
|
||||
/** Generate a random ROT key by using TRNG
|
||||
* @param output output buffer for the generated key.
|
||||
* @param size input: the size of the buffer. if size is less
|
||||
* then 16 bytes the method will generate an
|
||||
* error. 16-31 bytes will create a 16 byte key.
|
||||
* 32 or higher will generate a 32 bytes key
|
||||
* output: the actual written size to the buffer
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int generate_key_by_trng(uint32_t *output, size_t& size);
|
||||
};
|
||||
/** @}*/
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -82,6 +82,7 @@
|
|||
#define MBEDTLS_X509_USE_C
|
||||
#define MBEDTLS_X509_CRT_PARSE_C
|
||||
#define MBEDTLS_X509_CRL_PARSE_C
|
||||
#define MBEDTLS_CMAC_C
|
||||
|
||||
/* Miscellaneous options */
|
||||
#define MBEDTLS_AES_ROM_TABLES
|
||||
|
|
|
|||
|
|
@ -1861,7 +1861,7 @@
|
|||
* Requires: MBEDTLS_AES_C or MBEDTLS_DES_C
|
||||
*
|
||||
*/
|
||||
//#define MBEDTLS_CMAC_C
|
||||
#define MBEDTLS_CMAC_C
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_CTR_DRBG_C
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ typedef enum {
|
|||
|
||||
// All predefined keys used for internal features should be defined here
|
||||
|
||||
NVSTORE_DEVICEKEY_KEY = 4,
|
||||
|
||||
NVSTORE_LAST_PREDEFINED_KEY = 15,
|
||||
NVSTORE_NUM_PREDEFINED_KEYS
|
||||
} nvstore_predefined_keys_e;
|
||||
|
|
|
|||
Loading…
Reference in New Issue