mirror of https://github.com/ARMmbed/mbed-os.git
Add secure_time library implementation
parent
a1625895c3
commit
44f6b8a07c
|
@ -0,0 +1,572 @@
|
||||||
|
/* 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 <secure_time_utils.h>
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "unity.h"
|
||||||
|
#include "utest.h"
|
||||||
|
#include "secure_time_client_spe.h"
|
||||||
|
#include "secure_time_impl.h"
|
||||||
|
#include "secure_time_storage.h"
|
||||||
|
#include "secure_time_test_utils.h"
|
||||||
|
#include "nvstore.h"
|
||||||
|
|
||||||
|
#ifdef ENABLE_LIBGCOV_PORT
|
||||||
|
#include "libgcov-embedded.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !NVSTORE_ENABLED
|
||||||
|
#error [NOT_SUPPORTED] NVSTORE needs to be enabled for this test
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace utest::v1;
|
||||||
|
|
||||||
|
#define SECURE_TIME_TEST_SECS_PER_MINUTE (60)
|
||||||
|
#define SECURE_TIME_TEST_SECS_PER_HOUR (60 * SECURE_TIME_TEST_SECS_PER_MINUTE)
|
||||||
|
#define SECURE_TIME_TEST_SECS_PER_DAY (24 * SECURE_TIME_TEST_SECS_PER_HOUR)
|
||||||
|
|
||||||
|
#define SECURE_TIME_TEST_DEFAULT_TIME (2555562978ULL)
|
||||||
|
|
||||||
|
#define EXTRACT_UINT16(buf) ((((uint16_t)(((uint8_t *)(buf))[1])) << 8) + (uint16_t)(((uint8_t *)(buf))[0]))
|
||||||
|
#define WRITE_UINT16(buf, val) \
|
||||||
|
{ \
|
||||||
|
((uint8_t *)(buf))[0] = (uint8_t)(((uint16_t)(val)) & 0xff); \
|
||||||
|
((uint8_t *)(buf))[1] = (uint8_t)(((uint16_t)(val)) >> 8); \
|
||||||
|
}
|
||||||
|
|
||||||
|
MBED_ALIGN(4) // a WA for a failure with ARMCC
|
||||||
|
static const uint8_t ca_prvkey[] = {
|
||||||
|
0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x47, 0x2d, 0x6d, 0x08, 0x7c,
|
||||||
|
0xeb, 0x6d, 0x4c, 0xb1, 0xa1, 0x20, 0xb4, 0x80, 0x5f, 0x47, 0x78, 0xd6,
|
||||||
|
0xa5, 0x69, 0xf7, 0x34, 0xf2, 0xa2, 0x85, 0xb1, 0x5d, 0xae, 0xfa, 0x53,
|
||||||
|
0x57, 0x33, 0x7b, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
|
||||||
|
0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x7f, 0x4a, 0x31,
|
||||||
|
0xc8, 0x30, 0xbf, 0x71, 0x0a, 0x62, 0x91, 0xd9, 0xef, 0x54, 0xfa, 0x66,
|
||||||
|
0xe4, 0xab, 0xe9, 0xfa, 0x80, 0x12, 0x42, 0xdc, 0x16, 0x9f, 0x09, 0x37,
|
||||||
|
0x4d, 0xc6, 0x8c, 0x06, 0x03, 0x51, 0x9b, 0x1d, 0xd2, 0x36, 0x69, 0xe6,
|
||||||
|
0xc8, 0x30, 0x62, 0x44, 0x5d, 0xe5, 0x15, 0xb4, 0x9c, 0x9f, 0x9b, 0x23,
|
||||||
|
0x0a, 0x00, 0x1f, 0x8b, 0x4e, 0x8c, 0x8f, 0x5e, 0x80, 0x46, 0x71, 0xdc,
|
||||||
|
0xb4
|
||||||
|
};
|
||||||
|
|
||||||
|
MBED_ALIGN(4) // a WA for a failure with ARMCC
|
||||||
|
static const uint8_t ca_pubkey[] = {
|
||||||
|
0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
|
||||||
|
0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
|
||||||
|
0x42, 0x00, 0x04, 0x7f, 0x4a, 0x31, 0xc8, 0x30, 0xbf, 0x71, 0x0a, 0x62,
|
||||||
|
0x91, 0xd9, 0xef, 0x54, 0xfa, 0x66, 0xe4, 0xab, 0xe9, 0xfa, 0x80, 0x12,
|
||||||
|
0x42, 0xdc, 0x16, 0x9f, 0x09, 0x37, 0x4d, 0xc6, 0x8c, 0x06, 0x03, 0x51,
|
||||||
|
0x9b, 0x1d, 0xd2, 0x36, 0x69, 0xe6, 0xc8, 0x30, 0x62, 0x44, 0x5d, 0xe5,
|
||||||
|
0x15, 0xb4, 0x9c, 0x9f, 0x9b, 0x23, 0x0a, 0x00, 0x1f, 0x8b, 0x4e, 0x8c,
|
||||||
|
0x8f, 0x5e, 0x80, 0x46, 0x71, 0xdc, 0xb4
|
||||||
|
};
|
||||||
|
|
||||||
|
MBED_ALIGN(4) // a WA for a failure with ARMCC
|
||||||
|
static const uint8_t prvkey1[] = {
|
||||||
|
0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x61, 0x93, 0xa8, 0x0f, 0xaf,
|
||||||
|
0xd0, 0xc0, 0x60, 0x78, 0x65, 0x40, 0xc8, 0xd7, 0x77, 0x83, 0xda, 0x5a,
|
||||||
|
0x12, 0x92, 0x26, 0x94, 0x77, 0xac, 0x1e, 0xb5, 0x69, 0xa2, 0x24, 0x3c,
|
||||||
|
0x97, 0x86, 0x93, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
|
||||||
|
0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x10, 0x47, 0x96,
|
||||||
|
0xc0, 0x7e, 0x64, 0x84, 0x9a, 0x56, 0xd5, 0xf0, 0xf6, 0x8f, 0x08, 0x74,
|
||||||
|
0xed, 0x90, 0x87, 0x89, 0x45, 0x41, 0x7a, 0xf4, 0xd0, 0x1f, 0x98, 0xce,
|
||||||
|
0xc2, 0xad, 0x0c, 0x62, 0x3e, 0x9d, 0x59, 0xde, 0x0f, 0x45, 0x4d, 0x8f,
|
||||||
|
0xa6, 0x54, 0x25, 0x91, 0xf5, 0x93, 0xd5, 0xb1, 0xd7, 0xe7, 0x62, 0x49,
|
||||||
|
0x61, 0x21, 0x6b, 0x62, 0xa7, 0x18, 0x4b, 0xc9, 0x73, 0x28, 0xc8, 0x5d,
|
||||||
|
0xa9
|
||||||
|
};
|
||||||
|
|
||||||
|
MBED_ALIGN(4) // a WA for a failure with ARMCC
|
||||||
|
static const uint8_t pubkey1[] = {
|
||||||
|
0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
|
||||||
|
0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
|
||||||
|
0x42, 0x00, 0x04, 0x10, 0x47, 0x96, 0xc0, 0x7e, 0x64, 0x84, 0x9a, 0x56,
|
||||||
|
0xd5, 0xf0, 0xf6, 0x8f, 0x08, 0x74, 0xed, 0x90, 0x87, 0x89, 0x45, 0x41,
|
||||||
|
0x7a, 0xf4, 0xd0, 0x1f, 0x98, 0xce, 0xc2, 0xad, 0x0c, 0x62, 0x3e, 0x9d,
|
||||||
|
0x59, 0xde, 0x0f, 0x45, 0x4d, 0x8f, 0xa6, 0x54, 0x25, 0x91, 0xf5, 0x93,
|
||||||
|
0xd5, 0xb1, 0xd7, 0xe7, 0x62, 0x49, 0x61, 0x21, 0x6b, 0x62, 0xa7, 0x18,
|
||||||
|
0x4b, 0xc9, 0x73, 0x28, 0xc8, 0x5d, 0xa9
|
||||||
|
};
|
||||||
|
|
||||||
|
MBED_ALIGN(4) // a WA for a failure with ARMCC
|
||||||
|
static const uint8_t prvkey2[] = {
|
||||||
|
0x30, 0x76, 0x02, 0x01, 0x01, 0x04, 0x1f, 0x47, 0x17, 0x35, 0x1f, 0xb1,
|
||||||
|
0xbd, 0xb9, 0x94, 0x83, 0x10, 0x11, 0xee, 0x4a, 0x6f, 0xc1, 0xc7, 0xa9,
|
||||||
|
0xab, 0xec, 0xf7, 0xd8, 0x33, 0xb1, 0xf8, 0x63, 0xe5, 0xf2, 0xa7, 0xaa,
|
||||||
|
0x68, 0xc9, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03,
|
||||||
|
0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xd9, 0xbf, 0xff, 0xcb,
|
||||||
|
0xb1, 0x40, 0x0c, 0x9b, 0x8b, 0x7e, 0x0e, 0xbd, 0x69, 0x89, 0x82, 0xa1,
|
||||||
|
0xed, 0x33, 0xee, 0x95, 0xa5, 0x34, 0xc8, 0x41, 0xb0, 0x88, 0xf9, 0xcb,
|
||||||
|
0xac, 0x15, 0xdf, 0xab, 0x4e, 0x0a, 0x16, 0x45, 0xd5, 0xdf, 0x89, 0x3e,
|
||||||
|
0xb3, 0x7f, 0x05, 0xc2, 0x78, 0x28, 0xb3, 0xf5, 0x2f, 0x29, 0xed, 0xa1,
|
||||||
|
0x6c, 0x43, 0xf6, 0x7a, 0x59, 0x81, 0x73, 0x1e, 0x1d, 0xa5, 0x22, 0x19
|
||||||
|
};
|
||||||
|
|
||||||
|
MBED_ALIGN(4) // a WA for a failure with ARMCC
|
||||||
|
static const uint8_t pubkey2[] = {
|
||||||
|
0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
|
||||||
|
0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
|
||||||
|
0x42, 0x00, 0x04, 0xd9, 0xbf, 0xff, 0xcb, 0xb1, 0x40, 0x0c, 0x9b, 0x8b,
|
||||||
|
0x7e, 0x0e, 0xbd, 0x69, 0x89, 0x82, 0xa1, 0xed, 0x33, 0xee, 0x95, 0xa5,
|
||||||
|
0x34, 0xc8, 0x41, 0xb0, 0x88, 0xf9, 0xcb, 0xac, 0x15, 0xdf, 0xab, 0x4e,
|
||||||
|
0x0a, 0x16, 0x45, 0xd5, 0xdf, 0x89, 0x3e, 0xb3, 0x7f, 0x05, 0xc2, 0x78,
|
||||||
|
0x28, 0xb3, 0xf5, 0x2f, 0x29, 0xed, 0xa1, 0x6c, 0x43, 0xf6, 0x7a, 0x59,
|
||||||
|
0x81, 0x73, 0x1e, 0x1d, 0xa5, 0x22, 0x19
|
||||||
|
};
|
||||||
|
|
||||||
|
MBED_ALIGN(4) // a WA for a failure with ARMCC
|
||||||
|
static const uint8_t prvkey3[] = {
|
||||||
|
0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0xd2, 0x4a, 0x9c, 0xf3, 0xe2,
|
||||||
|
0x26, 0x1e, 0x25, 0xc0, 0x04, 0xdf, 0x90, 0x19, 0xf0, 0xdc, 0xb1, 0xd6,
|
||||||
|
0x2d, 0xdb, 0x5a, 0x10, 0x25, 0x2a, 0x48, 0xd2, 0xdd, 0x85, 0x4d, 0x90,
|
||||||
|
0xda, 0x3a, 0xbc, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
|
||||||
|
0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xd8, 0x4a, 0x68,
|
||||||
|
0x3a, 0xf1, 0x20, 0xec, 0x8f, 0x55, 0x68, 0x15, 0xbc, 0x9c, 0xc3, 0xb2,
|
||||||
|
0x29, 0xcb, 0x91, 0x99, 0xea, 0xd9, 0xe7, 0xa3, 0x6c, 0x58, 0xec, 0xd7,
|
||||||
|
0x22, 0x80, 0xc0, 0xfe, 0xf2, 0x63, 0x2a, 0x13, 0x71, 0x93, 0x11, 0xc0,
|
||||||
|
0x8b, 0x70, 0x04, 0xd5, 0x2f, 0x95, 0xfa, 0xd7, 0x06, 0x79, 0xc6, 0x32,
|
||||||
|
0xdf, 0xca, 0xbb, 0xa8, 0xf5, 0x68, 0xdc, 0x9d, 0x5a, 0x5a, 0x18, 0x6f,
|
||||||
|
0xad
|
||||||
|
};
|
||||||
|
|
||||||
|
MBED_ALIGN(4) // a WA for a failure with ARMCC
|
||||||
|
static const uint8_t pubkey3[] = {
|
||||||
|
0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
|
||||||
|
0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
|
||||||
|
0x42, 0x00, 0x04, 0xd8, 0x4a, 0x68, 0x3a, 0xf1, 0x20, 0xec, 0x8f, 0x55,
|
||||||
|
0x68, 0x15, 0xbc, 0x9c, 0xc3, 0xb2, 0x29, 0xcb, 0x91, 0x99, 0xea, 0xd9,
|
||||||
|
0xe7, 0xa3, 0x6c, 0x58, 0xec, 0xd7, 0x22, 0x80, 0xc0, 0xfe, 0xf2, 0x63,
|
||||||
|
0x2a, 0x13, 0x71, 0x93, 0x11, 0xc0, 0x8b, 0x70, 0x04, 0xd5, 0x2f, 0x95,
|
||||||
|
0xfa, 0xd7, 0x06, 0x79, 0xc6, 0x32, 0xdf, 0xca, 0xbb, 0xa8, 0xf5, 0x68,
|
||||||
|
0xdc, 0x9d, 0x5a, 0x5a, 0x18, 0x6f, 0xad
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t blob[SECURE_TIME_TESTS_MAX_BLOB_SIZE_BYTES] = {0};
|
||||||
|
static uint8_t blob2[SECURE_TIME_TESTS_MAX_BLOB_SIZE_BYTES] = {0};
|
||||||
|
|
||||||
|
static data_buffer_t delegation_pubkeys[] = {
|
||||||
|
{pubkey1, sizeof(pubkey1)},
|
||||||
|
{pubkey2, sizeof(pubkey2)},
|
||||||
|
{pubkey3, sizeof(pubkey3)}
|
||||||
|
};
|
||||||
|
|
||||||
|
static data_buffer_t privkeys[] = {
|
||||||
|
{ca_prvkey, sizeof(ca_prvkey)},
|
||||||
|
{prvkey1, sizeof(prvkey1)},
|
||||||
|
{prvkey2, sizeof(prvkey2)},
|
||||||
|
{prvkey3, sizeof(prvkey3)}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void blob_without_delegations(void)
|
||||||
|
{
|
||||||
|
uint64_t set_time = SECURE_TIME_TEST_DEFAULT_TIME;
|
||||||
|
uint64_t nonce = 0;
|
||||||
|
|
||||||
|
provision_data(ca_pubkey, sizeof(ca_pubkey));
|
||||||
|
|
||||||
|
secure_time_set_trusted_init(&nonce);
|
||||||
|
size_t blob_size = create_blob(set_time, nonce, delegation_pubkeys, privkeys, 0, blob, SECURE_TIME_TESTS_MAX_BLOB_SIZE_BYTES);
|
||||||
|
TEST_ASSERT_EQUAL_HEX(
|
||||||
|
SECURE_TIME_SUCCESS,
|
||||||
|
secure_time_set_trusted_commit(blob, blob_size)
|
||||||
|
);
|
||||||
|
TEST_ASSERT_UINT64_WITHIN(3, set_time, secure_time_get());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void blob_with_delegations(void)
|
||||||
|
{
|
||||||
|
uint64_t set_time = SECURE_TIME_TEST_DEFAULT_TIME;
|
||||||
|
uint64_t nonce = 0;
|
||||||
|
|
||||||
|
provision_data(ca_pubkey, sizeof(ca_pubkey));
|
||||||
|
|
||||||
|
secure_time_set_trusted_init(&nonce);
|
||||||
|
size_t blob_size = create_blob(set_time, nonce, delegation_pubkeys, privkeys, 3, blob, SECURE_TIME_TESTS_MAX_BLOB_SIZE_BYTES);
|
||||||
|
TEST_ASSERT_EQUAL_HEX(
|
||||||
|
SECURE_TIME_SUCCESS,
|
||||||
|
secure_time_set_trusted_commit(blob, blob_size)
|
||||||
|
);
|
||||||
|
TEST_ASSERT_UINT64_WITHIN(3, set_time, secure_time_get());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void malformed_blob_signature(void)
|
||||||
|
{
|
||||||
|
uint64_t set_time = SECURE_TIME_TEST_DEFAULT_TIME;
|
||||||
|
uint64_t nonce = 0;
|
||||||
|
|
||||||
|
provision_data(ca_pubkey, sizeof(ca_pubkey));
|
||||||
|
|
||||||
|
secure_time_set_trusted_init(&nonce);
|
||||||
|
size_t blob_size = create_blob(set_time, nonce, delegation_pubkeys, privkeys, 1, blob, SECURE_TIME_TESTS_MAX_BLOB_SIZE_BYTES);
|
||||||
|
|
||||||
|
// Break the last byte of the blob which is also the last byte of the blob's signature.
|
||||||
|
blob[blob_size - 1] ^= 1;
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_HEX(
|
||||||
|
SECURE_TIME_SIGNATURE_VERIFICATION_FAILED,
|
||||||
|
secure_time_set_trusted_commit(blob, blob_size)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void malformed_delegation_signature(void)
|
||||||
|
{
|
||||||
|
uint64_t set_time = SECURE_TIME_TEST_DEFAULT_TIME;
|
||||||
|
uint64_t nonce = 0;
|
||||||
|
|
||||||
|
provision_data(ca_pubkey, sizeof(ca_pubkey));
|
||||||
|
|
||||||
|
secure_time_set_trusted_init(&nonce);
|
||||||
|
size_t blob_size = create_blob(set_time, nonce, delegation_pubkeys, privkeys, 1, blob, SECURE_TIME_TESTS_MAX_BLOB_SIZE_BYTES);
|
||||||
|
|
||||||
|
// Break the first byte of the delegation signature.
|
||||||
|
blob[
|
||||||
|
SECURE_TIME_BLOB_HEADER_SIZE_BYTES +
|
||||||
|
SECURE_TIME_PUBKEY_LENGTH_SIZE_BYTES +
|
||||||
|
delegation_pubkeys[0].size +
|
||||||
|
SECURE_TIME_SIGNATURE_LENGTH_SIZE_BYTES
|
||||||
|
] ^= 1;
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_HEX(
|
||||||
|
SECURE_TIME_SIGNATURE_VERIFICATION_FAILED,
|
||||||
|
secure_time_set_trusted_commit(blob, blob_size)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void malformed_blob_signature_size(void)
|
||||||
|
{
|
||||||
|
uint64_t set_time = SECURE_TIME_TEST_DEFAULT_TIME;
|
||||||
|
uint64_t nonce = 0;
|
||||||
|
|
||||||
|
provision_data(ca_pubkey, sizeof(ca_pubkey));
|
||||||
|
|
||||||
|
secure_time_set_trusted_init(&nonce);
|
||||||
|
size_t blob_size = create_blob(set_time, nonce, delegation_pubkeys, privkeys, 0, blob, SECURE_TIME_TESTS_MAX_BLOB_SIZE_BYTES);
|
||||||
|
|
||||||
|
// Break blob's signature size field.
|
||||||
|
uint16_t delegation_size = EXTRACT_UINT16(blob + SECURE_TIME_DELEGATION_LENGTH_OFFSET);
|
||||||
|
uint16_t blob_signature_size = EXTRACT_UINT16(blob + SECURE_TIME_BLOB_HEADER_SIZE_BYTES + delegation_size);
|
||||||
|
WRITE_UINT16(blob + SECURE_TIME_BLOB_HEADER_SIZE_BYTES + delegation_size, blob_signature_size - 1);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_HEX(
|
||||||
|
SECURE_TIME_INVALID_BLOB_SIZE,
|
||||||
|
secure_time_set_trusted_commit(blob, blob_size)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void malformed_delegation_signature_size(void)
|
||||||
|
{
|
||||||
|
uint64_t set_time = SECURE_TIME_TEST_DEFAULT_TIME;
|
||||||
|
uint64_t nonce = 0;
|
||||||
|
|
||||||
|
provision_data(ca_pubkey, sizeof(ca_pubkey));
|
||||||
|
|
||||||
|
secure_time_set_trusted_init(&nonce);
|
||||||
|
size_t blob_size = create_blob(set_time, nonce, delegation_pubkeys, privkeys, 2, blob, SECURE_TIME_TESTS_MAX_BLOB_SIZE_BYTES);
|
||||||
|
|
||||||
|
// Break first delegation signature size field.
|
||||||
|
size_t signature_offset = SECURE_TIME_BLOB_HEADER_SIZE_BYTES + SECURE_TIME_PUBKEY_LENGTH_SIZE_BYTES + delegation_pubkeys[0].size;
|
||||||
|
uint16_t signature_size = EXTRACT_UINT16(blob + signature_offset);
|
||||||
|
WRITE_UINT16(blob + signature_offset, signature_size + 1);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_HEX(
|
||||||
|
SECURE_TIME_SIGNATURE_VERIFICATION_FAILED,
|
||||||
|
secure_time_set_trusted_commit(blob, blob_size)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void delegation_size_too_short(void)
|
||||||
|
{
|
||||||
|
uint64_t set_time = SECURE_TIME_TEST_DEFAULT_TIME;
|
||||||
|
uint64_t nonce = 0;
|
||||||
|
|
||||||
|
provision_data(ca_pubkey, sizeof(ca_pubkey));
|
||||||
|
|
||||||
|
secure_time_set_trusted_init(&nonce);
|
||||||
|
size_t blob_size = create_blob(set_time, nonce, delegation_pubkeys, privkeys, 1, blob, SECURE_TIME_TESTS_MAX_BLOB_SIZE_BYTES);
|
||||||
|
|
||||||
|
// Decrement delegation section size by 1 byte.
|
||||||
|
uint16_t delegation_size = EXTRACT_UINT16(blob + SECURE_TIME_DELEGATION_LENGTH_OFFSET);
|
||||||
|
WRITE_UINT16(blob + SECURE_TIME_DELEGATION_LENGTH_OFFSET, delegation_size - 1);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_HEX(
|
||||||
|
SECURE_TIME_INVALID_BLOB_SIZE,
|
||||||
|
secure_time_set_trusted_commit(blob, blob_size)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void delegation_size_too_long(void)
|
||||||
|
{
|
||||||
|
uint64_t set_time = SECURE_TIME_TEST_DEFAULT_TIME;
|
||||||
|
uint64_t nonce = 0;
|
||||||
|
|
||||||
|
provision_data(ca_pubkey, sizeof(ca_pubkey));
|
||||||
|
|
||||||
|
secure_time_set_trusted_init(&nonce);
|
||||||
|
size_t blob_size = create_blob(set_time, nonce, delegation_pubkeys, privkeys, 1, blob, SECURE_TIME_TESTS_MAX_BLOB_SIZE_BYTES);
|
||||||
|
|
||||||
|
// Increment delegation section size by 1 byte.
|
||||||
|
uint16_t delegation_size = EXTRACT_UINT16(blob + SECURE_TIME_DELEGATION_LENGTH_OFFSET);
|
||||||
|
WRITE_UINT16(blob + SECURE_TIME_DELEGATION_LENGTH_OFFSET, delegation_size + 1);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_HEX(
|
||||||
|
SECURE_TIME_INVALID_BLOB_SIZE,
|
||||||
|
secure_time_set_trusted_commit(blob, blob_size)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wrong_nonce(void)
|
||||||
|
{
|
||||||
|
uint64_t set_time = SECURE_TIME_TEST_DEFAULT_TIME;
|
||||||
|
uint64_t nonce1 = 0, nonce2 = 0;
|
||||||
|
|
||||||
|
provision_data(ca_pubkey, sizeof(ca_pubkey));
|
||||||
|
|
||||||
|
secure_time_set_trusted_init(&nonce1);
|
||||||
|
size_t blob_size1 = create_blob(set_time, nonce1, delegation_pubkeys, privkeys, 0, blob, SECURE_TIME_TESTS_MAX_BLOB_SIZE_BYTES);
|
||||||
|
|
||||||
|
secure_time_set_trusted_init(&nonce2);
|
||||||
|
size_t blob_size2 = create_blob(set_time, nonce2, delegation_pubkeys, privkeys, 0, blob2, SECURE_TIME_TESTS_MAX_BLOB_SIZE_BYTES);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_HEX(
|
||||||
|
SECURE_TIME_NONCE_NOT_MATCH,
|
||||||
|
secure_time_set_trusted_commit(blob, blob_size1)
|
||||||
|
);
|
||||||
|
TEST_ASSERT_EQUAL_HEX(
|
||||||
|
SECURE_TIME_SUCCESS,
|
||||||
|
secure_time_set_trusted_commit(blob2, blob_size2)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wrong_nonce2(void)
|
||||||
|
{
|
||||||
|
uint64_t set_time = SECURE_TIME_TEST_DEFAULT_TIME;
|
||||||
|
uint64_t nonce1 = 0, nonce2 = 0;
|
||||||
|
|
||||||
|
provision_data(ca_pubkey, sizeof(ca_pubkey));
|
||||||
|
|
||||||
|
secure_time_set_trusted_init(&nonce1);
|
||||||
|
size_t blob_size1 = create_blob(set_time, nonce1, delegation_pubkeys, privkeys, 0, blob, SECURE_TIME_TESTS_MAX_BLOB_SIZE_BYTES);
|
||||||
|
|
||||||
|
secure_time_set_trusted_init(&nonce2);
|
||||||
|
size_t blob_size2 = create_blob(set_time, nonce2, delegation_pubkeys, privkeys, 0, blob2, SECURE_TIME_TESTS_MAX_BLOB_SIZE_BYTES);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_HEX(
|
||||||
|
SECURE_TIME_SUCCESS,
|
||||||
|
secure_time_set_trusted_commit(blob2, blob_size2)
|
||||||
|
);
|
||||||
|
TEST_ASSERT_EQUAL_HEX(
|
||||||
|
SECURE_TIME_NONCE_MISSING,
|
||||||
|
secure_time_set_trusted_commit(blob, blob_size1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void replay_blob(void)
|
||||||
|
{
|
||||||
|
uint64_t set_time = SECURE_TIME_TEST_DEFAULT_TIME;
|
||||||
|
uint64_t nonce = 0;
|
||||||
|
|
||||||
|
provision_data(ca_pubkey, sizeof(ca_pubkey));
|
||||||
|
|
||||||
|
secure_time_set_trusted_init(&nonce);
|
||||||
|
size_t blob_size = create_blob(set_time, nonce, delegation_pubkeys, privkeys, 0, blob, SECURE_TIME_TESTS_MAX_BLOB_SIZE_BYTES);
|
||||||
|
TEST_ASSERT_EQUAL_HEX(
|
||||||
|
SECURE_TIME_SUCCESS,
|
||||||
|
secure_time_set_trusted_commit(blob, blob_size)
|
||||||
|
);
|
||||||
|
TEST_ASSERT_UINT64_WITHIN(3, set_time, secure_time_get());
|
||||||
|
|
||||||
|
wait(4);
|
||||||
|
|
||||||
|
// Send the blob again
|
||||||
|
TEST_ASSERT_EQUAL_HEX(
|
||||||
|
SECURE_TIME_NONCE_MISSING,
|
||||||
|
secure_time_set_trusted_commit(blob, blob_size)
|
||||||
|
);
|
||||||
|
TEST_ASSERT_UINT64_WITHIN(7, set_time, secure_time_get());
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
void nonce_timeout(void)
|
||||||
|
{
|
||||||
|
uint64_t set_time = SECURE_TIME_TEST_DEFAULT_TIME;
|
||||||
|
uint64_t nonce = 0;
|
||||||
|
|
||||||
|
provision_data(ca_pubkey, sizeof(ca_pubkey));
|
||||||
|
|
||||||
|
secure_time_set_trusted_init(&nonce);
|
||||||
|
|
||||||
|
// Create a significant timeout for the nonce to become obsolete.
|
||||||
|
wait(SECURE_TIME_NONCE_TIMEOUT_SECONDS + 1);
|
||||||
|
|
||||||
|
size_t blob_size = create_blob(set_time, nonce, delegation_pubkeys, privkeys, 0, blob, SECURE_TIME_TESTS_MAX_BLOB_SIZE_BYTES);
|
||||||
|
TEST_ASSERT_EQUAL_HEX(
|
||||||
|
SECURE_TIME_NONCE_TIMEOUT,
|
||||||
|
secure_time_set_trusted_commit(blob, blob_size)
|
||||||
|
);
|
||||||
|
TEST_ASSERT_UINT64_WITHIN(3, set_time, secure_time_get());
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
void normal_set_forward_no_storage_update(void)
|
||||||
|
{
|
||||||
|
uint64_t curr_time = SECURE_TIME_TEST_DEFAULT_TIME;
|
||||||
|
uint64_t set_time = curr_time + (SECURE_TIME_MIN_STORAGE_FORWARD_LATENCY_SEC - 100);
|
||||||
|
uint64_t stored_time = 0;
|
||||||
|
|
||||||
|
secure_time_update_boot_time(curr_time);
|
||||||
|
secure_time_set_stored_time(curr_time);
|
||||||
|
|
||||||
|
secure_time_set(set_time);
|
||||||
|
TEST_ASSERT_UINT64_WITHIN(3, set_time, secure_time_get());
|
||||||
|
secure_time_get_stored_time(&stored_time);
|
||||||
|
TEST_ASSERT(stored_time > 0);
|
||||||
|
TEST_ASSERT_EQUAL_UINT64(curr_time, stored_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
void normal_set_forward_with_storage_update(void)
|
||||||
|
{
|
||||||
|
uint64_t curr_time = SECURE_TIME_TEST_DEFAULT_TIME;
|
||||||
|
uint64_t set_time = curr_time + (SECURE_TIME_MIN_STORAGE_FORWARD_LATENCY_SEC + 100);
|
||||||
|
uint64_t stored_time = 0;
|
||||||
|
|
||||||
|
secure_time_update_boot_time(curr_time);
|
||||||
|
secure_time_set_stored_time(curr_time);
|
||||||
|
|
||||||
|
secure_time_set(set_time);
|
||||||
|
TEST_ASSERT_UINT64_WITHIN(3, set_time, secure_time_get());
|
||||||
|
secure_time_get_stored_time(&stored_time);
|
||||||
|
TEST_ASSERT(stored_time > 0);
|
||||||
|
TEST_ASSERT_EQUAL_UINT64(set_time, stored_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
void normal_set_forward_with_storage_update2(void)
|
||||||
|
{
|
||||||
|
uint64_t curr_time = SECURE_TIME_TEST_DEFAULT_TIME;
|
||||||
|
uint64_t set_time = curr_time + (SECURE_TIME_MIN_STORAGE_FORWARD_LATENCY_SEC - 100);
|
||||||
|
uint64_t stored_time = 0;
|
||||||
|
|
||||||
|
secure_time_update_boot_time(curr_time);
|
||||||
|
secure_time_set_stored_time(curr_time - (SECURE_TIME_MIN_STORAGE_IDLE_LATENCY_SEC + 100));
|
||||||
|
|
||||||
|
secure_time_set(set_time);
|
||||||
|
TEST_ASSERT_UINT64_WITHIN(3, set_time, secure_time_get());
|
||||||
|
secure_time_get_stored_time(&stored_time);
|
||||||
|
TEST_ASSERT(stored_time > 0);
|
||||||
|
TEST_ASSERT_EQUAL_UINT64(set_time, stored_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
void normal_set_backward_no_drift(void)
|
||||||
|
{
|
||||||
|
uint64_t curr_time = SECURE_TIME_TEST_DEFAULT_TIME;
|
||||||
|
uint64_t set_time = curr_time - ((30 * SECURE_TIME_TEST_SECS_PER_MINUTE) + 100);
|
||||||
|
uint64_t back_time = set_time - (10 * SECURE_TIME_TEST_SECS_PER_DAY);
|
||||||
|
uint64_t stored_time = 0;
|
||||||
|
|
||||||
|
secure_time_update_boot_time(curr_time);
|
||||||
|
secure_time_set_stored_time(curr_time);
|
||||||
|
secure_time_set_stored_back_time(back_time);
|
||||||
|
|
||||||
|
secure_time_set(set_time);
|
||||||
|
TEST_ASSERT_UINT64_WITHIN(3, curr_time, secure_time_get());
|
||||||
|
secure_time_get_stored_time(&stored_time);
|
||||||
|
TEST_ASSERT(stored_time > 0);
|
||||||
|
TEST_ASSERT_EQUAL_UINT64(curr_time, stored_time);
|
||||||
|
secure_time_get_stored_back_time(&stored_time);
|
||||||
|
TEST_ASSERT(stored_time > 0);
|
||||||
|
TEST_ASSERT_EQUAL_UINT64(back_time, stored_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
void normal_set_backward_with_drift(void)
|
||||||
|
{
|
||||||
|
uint64_t curr_time = SECURE_TIME_TEST_DEFAULT_TIME;
|
||||||
|
uint64_t set_time = curr_time - ((30 * SECURE_TIME_TEST_SECS_PER_MINUTE) - 100);
|
||||||
|
uint64_t back_time = set_time - (10 * SECURE_TIME_TEST_SECS_PER_DAY);
|
||||||
|
uint64_t stored_time = 0;
|
||||||
|
|
||||||
|
secure_time_update_boot_time(curr_time);
|
||||||
|
secure_time_set_stored_time(curr_time);
|
||||||
|
|
||||||
|
// Can't set backwards if no STORED_BACK entry in storage
|
||||||
|
secure_time_set(set_time);
|
||||||
|
TEST_ASSERT_UINT64_WITHIN(3, curr_time, secure_time_get());
|
||||||
|
secure_time_get_stored_time(&stored_time);
|
||||||
|
TEST_ASSERT(stored_time > 0);
|
||||||
|
TEST_ASSERT_EQUAL_UINT64(curr_time, stored_time);
|
||||||
|
secure_time_get_stored_back_time(&stored_time);
|
||||||
|
TEST_ASSERT_EQUAL_UINT64(0, stored_time);
|
||||||
|
|
||||||
|
secure_time_set_stored_back_time(back_time);
|
||||||
|
secure_time_get_stored_back_time(&stored_time);
|
||||||
|
TEST_ASSERT(stored_time > 0);
|
||||||
|
TEST_ASSERT_EQUAL_UINT64(back_time, stored_time);
|
||||||
|
|
||||||
|
secure_time_set(set_time);
|
||||||
|
TEST_ASSERT_UINT64_WITHIN(3, set_time, secure_time_get());
|
||||||
|
secure_time_get_stored_time(&stored_time);
|
||||||
|
TEST_ASSERT(stored_time > 0);
|
||||||
|
TEST_ASSERT_EQUAL_UINT64(set_time, stored_time);
|
||||||
|
secure_time_get_stored_back_time(&stored_time);
|
||||||
|
TEST_ASSERT(stored_time > 0);
|
||||||
|
TEST_ASSERT_EQUAL_UINT64(set_time, stored_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t storage_setup(const Case *const source, const size_t index_of_case)
|
||||||
|
{
|
||||||
|
NVStore &nvstore = NVStore::get_instance();
|
||||||
|
TEST_ASSERT_EQUAL(NVSTORE_SUCCESS, nvstore.reset());
|
||||||
|
|
||||||
|
// Call the default handler for proper reporting
|
||||||
|
return greentea_case_setup_handler(source, index_of_case);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test cases
|
||||||
|
Case cases[] = {
|
||||||
|
Case("Set trusted: Blob with an empty delegation list", blob_without_delegations),
|
||||||
|
Case("Set trusted: Blob with non-empty delegation list", blob_with_delegations),
|
||||||
|
Case("Set trusted: Malformed blob signature", malformed_blob_signature),
|
||||||
|
Case("Set trusted: Malformed delegation signature", malformed_delegation_signature),
|
||||||
|
Case("Set trusted: Malformed blob signature size", malformed_blob_signature_size),
|
||||||
|
Case("Set trusted: Malformed blob signature size", malformed_delegation_signature_size),
|
||||||
|
Case("Set trusted: Delegation size too short", delegation_size_too_short),
|
||||||
|
Case("Set trusted: Delegation size too long", delegation_size_too_long),
|
||||||
|
Case("Set trusted: Wrong nonce #1", wrong_nonce),
|
||||||
|
Case("Set trusted: Wrong nonce #2", wrong_nonce2),
|
||||||
|
Case("Set trusted: Replay same blob", replay_blob),
|
||||||
|
//Case("Set trusted: Nonce timeout", nonce_timeout),
|
||||||
|
Case("Set normal: Forward time, no storage update", storage_setup, normal_set_forward_no_storage_update),
|
||||||
|
Case("Set normal: Forward time, with storage update #1", storage_setup, normal_set_forward_with_storage_update),
|
||||||
|
Case("Set normal: Forward time, with storage update #2", storage_setup, normal_set_forward_with_storage_update2),
|
||||||
|
Case("Set normal: Backward time, no clock drift", storage_setup, normal_set_backward_no_drift),
|
||||||
|
Case("Set normal: Backward time, clock drift", storage_setup, normal_set_backward_with_drift)
|
||||||
|
};
|
||||||
|
|
||||||
|
utest::v1::status_t test_setup(const size_t number_of_cases)
|
||||||
|
{
|
||||||
|
// Setup Greentea using a reasonable timeout in seconds
|
||||||
|
#ifndef NO_GREENTEA
|
||||||
|
GREENTEA_SETUP(120, "default_auto");
|
||||||
|
#endif
|
||||||
|
return verbose_test_setup_handler(number_of_cases);
|
||||||
|
}
|
||||||
|
|
||||||
|
Specification specification(test_setup, cases);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_LIBGCOV_PORT
|
||||||
|
on_exit(collect_coverage, NULL);
|
||||||
|
static_init();
|
||||||
|
#endif
|
||||||
|
!Harness::run(specification);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,192 @@
|
||||||
|
#include "secure_time_test_utils.h"
|
||||||
|
#include "secure_time_client_spe.h"
|
||||||
|
#include "unity.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "mbedtls/pk.h"
|
||||||
|
#include "mbedtls/md.h"
|
||||||
|
#include "mbedtls/entropy.h"
|
||||||
|
#include "mbedtls/ctr_drbg.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
mbedtls_entropy_context entropy = {0};
|
||||||
|
|
||||||
|
void provision_data(
|
||||||
|
const uint8_t *ca_pubkey,
|
||||||
|
size_t ca_pubkey_size
|
||||||
|
)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_EQUAL_HEX(0, secure_time_set_stored_public_key(ca_pubkey, ca_pubkey_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sign_data(
|
||||||
|
const uint8_t *data,
|
||||||
|
size_t data_size,
|
||||||
|
const uint8_t *prvkey,
|
||||||
|
size_t prvkey_size,
|
||||||
|
uint8_t *sign,
|
||||||
|
size_t *sign_size
|
||||||
|
)
|
||||||
|
{
|
||||||
|
mbedtls_pk_context pk = {0};
|
||||||
|
mbedtls_pk_init(&pk);
|
||||||
|
TEST_ASSERT_EQUAL_HEX(0, mbedtls_pk_parse_key(&pk, prvkey, prvkey_size, NULL, 0));
|
||||||
|
|
||||||
|
mbedtls_md_context_t md_ctx = {0};
|
||||||
|
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
|
||||||
|
|
||||||
|
// The below variables were made static to prevent stack overflow when compiling with ARMCC.
|
||||||
|
static unsigned char hash[MBEDTLS_MD_MAX_SIZE];
|
||||||
|
static mbedtls_ctr_drbg_context ctr_drbg;
|
||||||
|
memset(hash, 0, sizeof(hash));
|
||||||
|
memset(&ctr_drbg, 0, sizeof(ctr_drbg));
|
||||||
|
|
||||||
|
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type);
|
||||||
|
TEST_ASSERT_NOT_NULL(md_info);
|
||||||
|
|
||||||
|
mbedtls_md_init(&md_ctx);
|
||||||
|
TEST_ASSERT_EQUAL_HEX(0, mbedtls_md_setup(&md_ctx, md_info, 0));
|
||||||
|
TEST_ASSERT_EQUAL_HEX(0, mbedtls_md_starts(&md_ctx));
|
||||||
|
TEST_ASSERT_EQUAL_HEX(0, mbedtls_md_update(&md_ctx, data, data_size));
|
||||||
|
TEST_ASSERT_EQUAL_HEX(0, mbedtls_md_finish(&md_ctx, hash));
|
||||||
|
mbedtls_md_free(&md_ctx);
|
||||||
|
|
||||||
|
mbedtls_entropy_init(&entropy);
|
||||||
|
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||||
|
TEST_ASSERT_EQUAL_HEX(0, mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0));
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_HEX(0, mbedtls_pk_sign(&pk, md_type, hash, 0, sign, sign_size, mbedtls_ctr_drbg_random, &ctr_drbg));
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t signature[SECURE_TIME_TESTS_MAX_SIGN_SIZE_BYTES] = {0}; // define it global static to avoid stack overflow
|
||||||
|
|
||||||
|
static size_t create_delegation_record(
|
||||||
|
const uint8_t *delegation_pubkey,
|
||||||
|
size_t delegation_pubkey_size,
|
||||||
|
const uint8_t *prvkey,
|
||||||
|
size_t prvkey_size,
|
||||||
|
uint8_t *record_buffer,
|
||||||
|
size_t record_buffer_size
|
||||||
|
)
|
||||||
|
{
|
||||||
|
uint8_t *delegation_record_start = record_buffer;
|
||||||
|
size_t signature_size = 0;
|
||||||
|
|
||||||
|
size_t record_size = SECURE_TIME_PUBKEY_LENGTH_SIZE_BYTES;
|
||||||
|
TEST_ASSERT(record_size <= record_buffer_size);
|
||||||
|
record_buffer[0] = (uint8_t)(delegation_pubkey_size & 0xff);
|
||||||
|
record_buffer[1] = (uint8_t)(delegation_pubkey_size >> 8);
|
||||||
|
record_buffer += SECURE_TIME_PUBKEY_LENGTH_SIZE_BYTES;
|
||||||
|
|
||||||
|
record_size += delegation_pubkey_size;
|
||||||
|
TEST_ASSERT(record_size <= record_buffer_size);
|
||||||
|
memcpy(record_buffer, delegation_pubkey, delegation_pubkey_size);
|
||||||
|
record_buffer += delegation_pubkey_size;
|
||||||
|
|
||||||
|
sign_data(
|
||||||
|
delegation_record_start,
|
||||||
|
SECURE_TIME_PUBKEY_LENGTH_SIZE_BYTES + delegation_pubkey_size,
|
||||||
|
prvkey,
|
||||||
|
prvkey_size,
|
||||||
|
signature,
|
||||||
|
&signature_size
|
||||||
|
);
|
||||||
|
TEST_ASSERT(SECURE_TIME_TESTS_MAX_SIGN_SIZE_BYTES >= signature_size);
|
||||||
|
|
||||||
|
record_size += SECURE_TIME_SIGNATURE_LENGTH_SIZE_BYTES;
|
||||||
|
TEST_ASSERT(record_size <= record_buffer_size);
|
||||||
|
record_buffer[0] = (uint8_t)(signature_size & 0xff);
|
||||||
|
record_buffer[1] = (uint8_t)(signature_size >> 8);
|
||||||
|
record_buffer += SECURE_TIME_SIGNATURE_LENGTH_SIZE_BYTES;
|
||||||
|
|
||||||
|
record_size += signature_size;
|
||||||
|
TEST_ASSERT(record_size <= record_buffer_size);
|
||||||
|
memcpy(record_buffer, signature, signature_size);
|
||||||
|
|
||||||
|
return record_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t create_blob(
|
||||||
|
uint64_t time,
|
||||||
|
uint64_t nonce,
|
||||||
|
const data_buffer_t *delegation_pubkeys,
|
||||||
|
const data_buffer_t *prvkeys,
|
||||||
|
uint32_t delegation_list_length,
|
||||||
|
uint8_t *blob_buffer,
|
||||||
|
size_t blob_buffer_size
|
||||||
|
)
|
||||||
|
{
|
||||||
|
uint32_t blob_size = 0;
|
||||||
|
|
||||||
|
// Make sure the necessary buffers aren't NULL (delegation_pubkeys is allowed to be NULL).
|
||||||
|
TEST_ASSERT(NULL != prvkeys);
|
||||||
|
TEST_ASSERT(NULL != blob_buffer);
|
||||||
|
|
||||||
|
// Construct the blob.
|
||||||
|
uint8_t *blob_start = blob_buffer;
|
||||||
|
size_t signature_size = 0;
|
||||||
|
|
||||||
|
// Add the timestamp top the blob.
|
||||||
|
blob_size += SECURE_TIME_TIMESTAMP_SIZE_BYTES;
|
||||||
|
TEST_ASSERT(blob_size <= blob_buffer_size);
|
||||||
|
memcpy(blob_buffer, &time, SECURE_TIME_TIMESTAMP_SIZE_BYTES);
|
||||||
|
blob_buffer += SECURE_TIME_TIMESTAMP_SIZE_BYTES;
|
||||||
|
|
||||||
|
// Add nonce to the blob.
|
||||||
|
blob_size += SECURE_TIME_NONCE_SIZE_BYTES;
|
||||||
|
TEST_ASSERT(blob_size <= blob_buffer_size);
|
||||||
|
memcpy(blob_buffer, &nonce, SECURE_TIME_NONCE_SIZE_BYTES);
|
||||||
|
blob_buffer += SECURE_TIME_NONCE_SIZE_BYTES;
|
||||||
|
|
||||||
|
// Reserve space in the blob for the overall delegation record size which is still unknown.
|
||||||
|
blob_size += SECURE_TIME_DELEGATION_LENGTH_SIZE_BYTES;
|
||||||
|
TEST_ASSERT(blob_size <= blob_buffer_size);
|
||||||
|
uint8_t *blob_delegation_length = blob_buffer;
|
||||||
|
blob_buffer += SECURE_TIME_DELEGATION_LENGTH_SIZE_BYTES;
|
||||||
|
|
||||||
|
// Add all the delegation records to the blob.
|
||||||
|
uint8_t *delegation_section_start = blob_buffer;
|
||||||
|
uint32_t i = 0;
|
||||||
|
size_t delegation_record_length = 0;
|
||||||
|
for (i = 0; delegation_pubkeys != NULL && i < delegation_list_length; i++) {
|
||||||
|
delegation_record_length = create_delegation_record(
|
||||||
|
delegation_pubkeys[i].data,
|
||||||
|
delegation_pubkeys[i].size,
|
||||||
|
prvkeys[i].data,
|
||||||
|
prvkeys[i].size,
|
||||||
|
blob_buffer,
|
||||||
|
blob_buffer_size - blob_size
|
||||||
|
);
|
||||||
|
blob_size += delegation_record_length;
|
||||||
|
blob_buffer += delegation_record_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the overall delegation section size to the blob.
|
||||||
|
uint16_t delegation_length = blob_buffer - delegation_section_start;
|
||||||
|
blob_delegation_length[0] = (uint8_t)(delegation_length & 0xff);
|
||||||
|
blob_delegation_length[1] = (uint8_t)(delegation_length >> 8);
|
||||||
|
|
||||||
|
// Sign the blob.
|
||||||
|
sign_data(
|
||||||
|
blob_start,
|
||||||
|
blob_size,
|
||||||
|
prvkeys[i].data,
|
||||||
|
prvkeys[i].size,
|
||||||
|
signature,
|
||||||
|
&signature_size
|
||||||
|
);
|
||||||
|
TEST_ASSERT(SECURE_TIME_TESTS_MAX_SIGN_SIZE_BYTES >= signature_size);
|
||||||
|
|
||||||
|
blob_size += SECURE_TIME_SIGNATURE_LENGTH_SIZE_BYTES;
|
||||||
|
TEST_ASSERT(blob_size <= blob_buffer_size);
|
||||||
|
blob_buffer[0] = (uint8_t)(signature_size & 0xff);
|
||||||
|
blob_buffer[1] = (uint8_t)(signature_size >> 8);
|
||||||
|
blob_buffer += SECURE_TIME_SIGNATURE_LENGTH_SIZE_BYTES;
|
||||||
|
|
||||||
|
blob_size += signature_size;
|
||||||
|
TEST_ASSERT(blob_size <= blob_buffer_size);
|
||||||
|
memcpy(blob_buffer, signature, signature_size);
|
||||||
|
|
||||||
|
return blob_size;
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef __SECURE_TIME_TEST_UTILS__
|
||||||
|
#define __SECURE_TIME_TEST_UTILS__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define SECURE_TIME_TESTS_MAX_SIGN_SIZE_BYTES (128UL)
|
||||||
|
#define SECURE_TIME_TESTS_MAX_BLOB_SIZE_BYTES (1024UL)
|
||||||
|
|
||||||
|
typedef struct data_buffer {
|
||||||
|
const uint8_t *data;
|
||||||
|
size_t size;
|
||||||
|
} data_buffer_t;
|
||||||
|
|
||||||
|
void provision_data(
|
||||||
|
const uint8_t *ca_pubkey,
|
||||||
|
size_t ca_pubkey_size
|
||||||
|
);
|
||||||
|
|
||||||
|
size_t create_blob(
|
||||||
|
uint64_t time,
|
||||||
|
uint64_t nonce,
|
||||||
|
const data_buffer *delegation_pubkeys,
|
||||||
|
const data_buffer *prvkeys,
|
||||||
|
uint32_t pub_key_number,
|
||||||
|
uint8_t *blob_buffer,
|
||||||
|
size_t blob_buffer_size
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif // __SECURE_TIME_TEST_UTILS__
|
|
@ -49,7 +49,10 @@ typedef enum {
|
||||||
|
|
||||||
// All predefined keys used for internal features should be defined here
|
// All predefined keys used for internal features should be defined here
|
||||||
|
|
||||||
|
NVSTORE_STORED_TIME_KEY = 2,
|
||||||
|
NVSTORE_STORED_BACK_TIME_KEY = 3,
|
||||||
NVSTORE_DEVICEKEY_KEY = 4,
|
NVSTORE_DEVICEKEY_KEY = 4,
|
||||||
|
NVSTORE_CA_PUBKEY_KEY = 9,
|
||||||
|
|
||||||
NVSTORE_LAST_PREDEFINED_KEY = 15,
|
NVSTORE_LAST_PREDEFINED_KEY = 15,
|
||||||
NVSTORE_NUM_PREDEFINED_KEYS
|
NVSTORE_NUM_PREDEFINED_KEYS
|
||||||
|
|
|
@ -0,0 +1,144 @@
|
||||||
|
# Secure time
|
||||||
|
|
||||||
|
## Table of Contents:
|
||||||
|
|
||||||
|
- [Overview](#overview).
|
||||||
|
- [Setting Regular time](#setting-regular-time).
|
||||||
|
- [Setting Trusted time](#setting-trusted-time).
|
||||||
|
- [Getting current time](#getting-current-time).
|
||||||
|
- [Code example](#code-example).
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
In IoT applications, a trusted source of time is needed to, among other things, ensure the confidentiality and integrity
|
||||||
|
of network connections. This is largely due to the fact that X.509 certificates are used by TLS stack to establish a secure
|
||||||
|
connection between the device and any services. TLS stack enforces X.509 certificate expiration with a required accuracy of up to one hour.
|
||||||
|
|
||||||
|
To protect against an attacker who might use an expired certificate to pretend to be a trusted web service,
|
||||||
|
IoT devices need a mechanism for ensuring that they have an internal system time that is accurate to a specified fidelity.
|
||||||
|
|
||||||
|
The secure time module supports setting the time from both trusted and regular time sources.
|
||||||
|
|
||||||
|
## Setting regular time
|
||||||
|
|
||||||
|
For regular operations, time source does not require trust requirements.
|
||||||
|
|
||||||
|
When setting the time from a regular time source:
|
||||||
|
|
||||||
|
* Time data is plain 64-bit value of seconds since UNIX epoch.
|
||||||
|
* The user can move time forward with no restrictions.
|
||||||
|
* The user can move time backward only slightly. Up to 3 minutes per day or 1 second per 8 minutes.
|
||||||
|
This is used for natural clock drift adjustment.
|
||||||
|
|
||||||
|
See `secure_time_set()` in [secure_time_client.h](secure_time_client.h).
|
||||||
|
|
||||||
|
## Setting trusted time
|
||||||
|
|
||||||
|
For operations that must trust the current time of the device, time source must be a trusted one.
|
||||||
|
|
||||||
|
Setting the time, obtained from a trusted time source (e.g. trusted time server):
|
||||||
|
|
||||||
|
* Time data is 64-bit value of seconds since UNIX epoch, which is encapsulated inside a [signed blob](#signed-blob-content),
|
||||||
|
which a trusted authority signs.
|
||||||
|
* The user can move time forward and backward with no restrictions.
|
||||||
|
* Time is valid only if the blob passes verification for authenticity and freshness.
|
||||||
|
* Verifying the signature with the aid of a factory-provisioned public key guarantees authenticity.
|
||||||
|
* Using a nonce guarantees freshness. The device generates the nonce, saves it and sends it to the trusted time
|
||||||
|
source to be encapsulated in the blob and verified when the time blob reaches the device.
|
||||||
|
|
||||||
|
See `secure_time_set_trusted_init()` and `secure_time_set_trusted_commit()` in
|
||||||
|
[secure_time_client.h](secure_time_client.h).
|
||||||
|
|
||||||
|
### Signed blob content
|
||||||
|
|
||||||
|
```text
|
||||||
|
|---------- signed fields -------------------|
|
||||||
|
v v
|
||||||
|
|---------|-----|----------------|-----------|---------|----|
|
||||||
|
|timestamp|nonce|delegations_size|delegations|sign_size|sign|
|
||||||
|
|---------|-----|----------------|-----------|---------|----|
|
||||||
|
^ ^ ^ ^ ^ ^
|
||||||
|
| | | | | |
|
||||||
|
| | | | | --- DER-encoded signature
|
||||||
|
| | | | | over the signed fields.
|
||||||
|
| | | | |
|
||||||
|
| | | | --- Size of the following
|
||||||
|
| | | | signature, 16-bit unsigned
|
||||||
|
| | | | integer in Little Endian format.
|
||||||
|
| | | |
|
||||||
|
| | | --- 0 or more delegation records.
|
||||||
|
| | |
|
||||||
|
| | --- Size of the following delegation records,
|
||||||
|
| | 16-bit unsigned integer in Little Endian format.
|
||||||
|
| |
|
||||||
|
| -------- 64-bit nonce generated by Secure Time code.
|
||||||
|
|
|
||||||
|
------ 64-bit value of seconds since UNIX epoch in Little Endian format.
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Blob content description
|
||||||
|
|
||||||
|
- timestamp - 64-bit value of seconds since UNIX epoch in **Little Endian** format.
|
||||||
|
- nonce - 64-bit nonce **generated by Secure Time code** for validating time blob freshness.
|
||||||
|
- delegations_size - size of following delegation records, 16-bit unsigned
|
||||||
|
integer in Little Endian format. 0 size means no delegations are provided.
|
||||||
|
- delegations - 0 (delegations_size==0) or more delegation records for
|
||||||
|
supporting trust chains.
|
||||||
|
- sign_size - 16-bit **Little Endian** size in bytes of the following
|
||||||
|
DER-encoded signature.
|
||||||
|
- signature - DER-encoded signature over signed fields using either CA
|
||||||
|
(delegations_size==0) or delegation private key.
|
||||||
|
|
||||||
|
Each delegation record consists of:
|
||||||
|
|
||||||
|
- key_len - 16-bit **Little Endian** size in bytes of the following DER-encoded
|
||||||
|
public key.
|
||||||
|
- DER-encoded public key.
|
||||||
|
- Signature size - 16-bit **Little Endian** size in bytes of the following
|
||||||
|
DER-encoded signature.
|
||||||
|
- DER-encoded signature over key size and key fields.
|
||||||
|
|
||||||
|
```text
|
||||||
|
|------------------ First delegation ---------| |----------------- N-th delegation -------------|
|
||||||
|
| | | |
|
||||||
|
|-- Signed fields -----| | |-- Signed fields -----| |
|
||||||
|
v v v v v v
|
||||||
|
|-----------|----------|-------------|--------| .. |-----------|----------|------------- |---------|
|
||||||
|
|Key_size(1)|Pub_key(1)|Sign_size(CA)|Sign(CA)| .. |Key_size(N)|Pub_key(N)|Sign_size(N-1)|Sign(N-1)|
|
||||||
|
|-----------|----------|-------------|--------| .. |-----------|----------|------------- |---------|
|
||||||
|
^ ^ ^ ^ ^
|
||||||
|
| | | | |
|
||||||
|
| | | | Signature using Nth-1 private key over ---
|
||||||
|
| | | | Nth public key & size fields
|
||||||
|
| | | |
|
||||||
|
| | | --- DER-encoded signature over the signed
|
||||||
|
| | | fields using CA private key.
|
||||||
|
| | |
|
||||||
|
| | --- Signature size - 16-bit value in Little Endian format.
|
||||||
|
| |
|
||||||
|
| --- First public key.
|
||||||
|
|
|
||||||
|
--- 16-bit value in Little Endian format.
|
||||||
|
```
|
||||||
|
|
||||||
|
In case no delegation records are present (delegations_size==0) - the time blob is signed by CA using its private key.
|
||||||
|
> CA public key expected to be available on the device using factory provisioning.
|
||||||
|
|
||||||
|
A single delegation record is combined from the size of DER-encoded public key, DER-encoded public key,
|
||||||
|
size of DER-encoded signature and DER-encoded signature
|
||||||
|
over that public key and size fields using private key belonging to signing authority located downstream
|
||||||
|
on the trust chain. The signature is represented using signature size and signature data.
|
||||||
|
|
||||||
|
Secure Time code performing blob's authenticity verification acts as follows:
|
||||||
|
- Delegation records are processed from left to right.
|
||||||
|
- The blob's signature is validated using the CA public key in case no delegations are provided.
|
||||||
|
Alternatively, in case when one or more delegation records are present, the last (rightmost) public
|
||||||
|
key in the delegation chain is used to verify time blob signature.
|
||||||
|
|
||||||
|
## Getting current time
|
||||||
|
|
||||||
|
See `secure_time_get()` in [secure_time_client.h](secure_time_client.h).
|
||||||
|
|
||||||
|
## Code example
|
||||||
|
|
||||||
|
[Secure time example on GitHub](https://github.com/ARMmbed/mbed-os-example-secure-time)
|
|
@ -0,0 +1,57 @@
|
||||||
|
/* 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 __SECURE_TIME_CRYPTO_H__
|
||||||
|
#define __SECURE_TIME_CRYPTO_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify the data buffer signature.
|
||||||
|
*
|
||||||
|
* @param[in] data Data buffer.
|
||||||
|
* @param[in] data_size Size in bytes of buffer.
|
||||||
|
* @param[in] sign Data buffer's signature
|
||||||
|
* @param[in] sign_size Signature size
|
||||||
|
* @param[in] pubkey Buffer which holds the public key.
|
||||||
|
* @param[in] pubkey_size Size in bytes of the public key.
|
||||||
|
* @return SECURE_TIME_SUCCESS or negative error code if failed.
|
||||||
|
*/
|
||||||
|
int32_t secure_time_verify_signature(
|
||||||
|
const void *data,
|
||||||
|
size_t data_size,
|
||||||
|
const void *sign,
|
||||||
|
size_t sign_size,
|
||||||
|
const void *pubkey,
|
||||||
|
size_t pubkey_size
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate a sequence of random bytes.
|
||||||
|
*
|
||||||
|
* @param[in] size Size in bytes of the random buffer
|
||||||
|
* @param[out] random_buf Buffer to fill with the generated random bytes.
|
||||||
|
*/
|
||||||
|
void secure_time_generate_random_bytes(size_t size, void *random_buf);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __SECURE_TIME_CRYPTO_H__
|
|
@ -0,0 +1,167 @@
|
||||||
|
/* 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 "secure_time_crypto.h"
|
||||||
|
#include "secure_time_client_spe.h"
|
||||||
|
#include "mbed_error.h"
|
||||||
|
|
||||||
|
#include "mbedtls/pk.h"
|
||||||
|
#include "mbedtls/md.h"
|
||||||
|
#include "mbedtls/entropy.h"
|
||||||
|
#include "mbedtls/ctr_drbg.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure containing contexts for random number generation.
|
||||||
|
*/
|
||||||
|
typedef struct secure_time_random_ctx {
|
||||||
|
mbedtls_ctr_drbg_context ctr_drbg_ctx; /* CTR_DRBG context structure. */
|
||||||
|
mbedtls_entropy_context entropy_ctx; /* Entropy context structure. */
|
||||||
|
} secure_time_random_ctx_t;
|
||||||
|
|
||||||
|
static mbedtls_md_type_t md_type_from_signature_alg(SignatureAlg alg)
|
||||||
|
{
|
||||||
|
switch(alg) {
|
||||||
|
case SIGNATURE_ALG_SHA256_ECDSA:
|
||||||
|
return MBEDTLS_MD_SHA256;
|
||||||
|
default:
|
||||||
|
return MBEDTLS_MD_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static mbedtls_pk_type_t pk_type_from_signature_alg(SignatureAlg alg)
|
||||||
|
{
|
||||||
|
switch(alg) {
|
||||||
|
case SIGNATURE_ALG_SHA256_ECDSA:
|
||||||
|
return MBEDTLS_PK_ECDSA;
|
||||||
|
default:
|
||||||
|
return MBEDTLS_PK_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void calculate_hash(
|
||||||
|
const void *data,
|
||||||
|
size_t data_size,
|
||||||
|
mbedtls_md_type_t md_type,
|
||||||
|
uint8_t *hash
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rc = SECURE_TIME_SUCCESS;
|
||||||
|
mbedtls_md_context_t md_ctx = {0};
|
||||||
|
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type);
|
||||||
|
if (NULL == md_info) {
|
||||||
|
error("mbedtls_md_info_from_type() returned NULL!");
|
||||||
|
}
|
||||||
|
|
||||||
|
mbedtls_md_init(&md_ctx);
|
||||||
|
rc = mbedtls_md_setup(&md_ctx, md_info, 0);
|
||||||
|
if (SECURE_TIME_SUCCESS != rc) {
|
||||||
|
error("mbedtls_md_setup() failed! (rc=%d)", rc);
|
||||||
|
}
|
||||||
|
rc = mbedtls_md_starts(&md_ctx);
|
||||||
|
if (SECURE_TIME_SUCCESS != rc) {
|
||||||
|
error("mbedtls_md_starts() failed! (rc=%d)", rc);
|
||||||
|
}
|
||||||
|
rc = mbedtls_md_update(&md_ctx, (const unsigned char *)data, data_size);
|
||||||
|
if (SECURE_TIME_SUCCESS != rc) {
|
||||||
|
error("mbedtls_md_update() failed! (rc=%d)", rc);
|
||||||
|
}
|
||||||
|
rc = mbedtls_md_finish(&md_ctx, hash);
|
||||||
|
if (SECURE_TIME_SUCCESS != rc) {
|
||||||
|
error("mbedtls_md_finish() failed! (rc=%d)", rc);
|
||||||
|
}
|
||||||
|
mbedtls_md_free(&md_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void random_ctx_init(secure_time_random_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
int rc = SECURE_TIME_SUCCESS;
|
||||||
|
|
||||||
|
mbedtls_entropy_init(&(ctx->entropy_ctx));
|
||||||
|
mbedtls_ctr_drbg_init(&(ctx->ctr_drbg_ctx));
|
||||||
|
rc = mbedtls_ctr_drbg_seed(
|
||||||
|
&(ctx->ctr_drbg_ctx),
|
||||||
|
mbedtls_entropy_func,
|
||||||
|
&(ctx->entropy_ctx),
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
if (SECURE_TIME_SUCCESS != rc) {
|
||||||
|
error("mbedtls_ctr_drbg_seed() failed! (rc=%d)", rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t secure_time_verify_signature(
|
||||||
|
const void *data,
|
||||||
|
size_t data_size,
|
||||||
|
const void *sign,
|
||||||
|
size_t sign_size,
|
||||||
|
const void *pubkey,
|
||||||
|
size_t pubkey_size
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rc = SECURE_TIME_SUCCESS;
|
||||||
|
uint8_t hash[MBEDTLS_MD_MAX_SIZE] = {0};
|
||||||
|
mbedtls_pk_context pubkey_ctx = {0};
|
||||||
|
|
||||||
|
mbedtls_md_type_t md_type = md_type_from_signature_alg(SIGNATURE_ALG_SHA256_ECDSA);
|
||||||
|
mbedtls_pk_type_t pk_type = pk_type_from_signature_alg(SIGNATURE_ALG_SHA256_ECDSA);
|
||||||
|
if ((MBEDTLS_MD_NONE == md_type) || (MBEDTLS_PK_NONE == pk_type)) {
|
||||||
|
error("Failed to determine the signature algorithm!");
|
||||||
|
}
|
||||||
|
|
||||||
|
calculate_hash(data, data_size, md_type, hash);
|
||||||
|
mbedtls_pk_init(&pubkey_ctx);
|
||||||
|
|
||||||
|
rc = mbedtls_pk_parse_public_key(&pubkey_ctx, pubkey, pubkey_size);
|
||||||
|
if (0 != rc) {
|
||||||
|
error("Failed to parse public key! (rc=%d)", rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mbedtls_pk_can_do(&pubkey_ctx, pk_type)) {
|
||||||
|
error("Unable to verify signature");
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = mbedtls_pk_verify(
|
||||||
|
&pubkey_ctx,
|
||||||
|
md_type,
|
||||||
|
hash,
|
||||||
|
0,
|
||||||
|
(const unsigned char *)sign,
|
||||||
|
sign_size
|
||||||
|
);
|
||||||
|
if (SECURE_TIME_SUCCESS != rc) {
|
||||||
|
rc = SECURE_TIME_SIGNATURE_VERIFICATION_FAILED;
|
||||||
|
}
|
||||||
|
mbedtls_pk_free(&pubkey_ctx);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void secure_time_generate_random_bytes(size_t size, void *random_buf)
|
||||||
|
{
|
||||||
|
int rc = SECURE_TIME_SUCCESS;
|
||||||
|
secure_time_random_ctx_t *random_ctx =
|
||||||
|
(secure_time_random_ctx_t *)malloc(sizeof(*random_ctx));
|
||||||
|
if (NULL == random_ctx) {
|
||||||
|
error("Failed to allocate memory for random_ctx!");
|
||||||
|
}
|
||||||
|
random_ctx_init(random_ctx);
|
||||||
|
|
||||||
|
rc = mbedtls_ctr_drbg_random(&(random_ctx->ctr_drbg_ctx), (unsigned char *)random_buf, size);
|
||||||
|
if (SECURE_TIME_SUCCESS != rc) {
|
||||||
|
error("mbedtls_ctr_drbg_random() failed! (rc=%d)", rc);
|
||||||
|
}
|
||||||
|
free(random_ctx);
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
/* 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 __SECURE_TIME_CLIENT_H__
|
||||||
|
#define __SECURE_TIME_CLIENT_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/** @addtogroup Secure-Time-API
|
||||||
|
* The C interface for setting and getting secure time.
|
||||||
|
* All functions are blocking.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Error codes */
|
||||||
|
#define SECURE_TIME_SUCCESS (0UL)
|
||||||
|
#define SECURE_TIME_BAD_PARAMS (-1L)
|
||||||
|
#define SECURE_TIME_INVALID_BLOB_SIZE (-2L)
|
||||||
|
#define SECURE_TIME_SIGNATURE_VERIFICATION_FAILED (-3L)
|
||||||
|
#define SECURE_TIME_NONCE_MISSING (-4L)
|
||||||
|
#define SECURE_TIME_NONCE_NOT_MATCH (-5L)
|
||||||
|
#define SECURE_TIME_NONCE_TIMEOUT (-6L)
|
||||||
|
#define SECURE_TIME_NOT_ALLOWED (-7L)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize secure time setting from a trusted time source.
|
||||||
|
*
|
||||||
|
* The function generates 64-bit nonce that will be used in the next invocation
|
||||||
|
* of ::secure_time_set_trusted_commit() to verify the trusted time blob freshness.
|
||||||
|
*
|
||||||
|
* @param[out] nonce The generated nonce.
|
||||||
|
* @return 0 or negative error code if failed.
|
||||||
|
*/
|
||||||
|
int32_t secure_time_set_trusted_init(uint64_t *nonce);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the secure time from a trusted time source.
|
||||||
|
*
|
||||||
|
* The time is encapsulated inside blob which is signed with the trusted time
|
||||||
|
* sources' private key.
|
||||||
|
* The blob will be verified with the trusted time sources' public key.
|
||||||
|
* The signatuire to verify is located within the blob's data.
|
||||||
|
*
|
||||||
|
* @param[in] blob Buffer which holds the blob.
|
||||||
|
* @param[in] blob_size Size in bytes of blob.
|
||||||
|
* @return 0 or negative error code if failed.
|
||||||
|
*/
|
||||||
|
int32_t secure_time_set_trusted_commit(const void *blob, size_t blob_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the secure time from an arbitrary time source.
|
||||||
|
*
|
||||||
|
* @param[in] new_time Time value in seconds since EPOCH.
|
||||||
|
* @return 0 or negative error code if failed.
|
||||||
|
*/
|
||||||
|
int32_t secure_time_set(uint64_t new_time);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the current secure-time value.
|
||||||
|
*
|
||||||
|
* This function will return 0 in case secure time was never set.
|
||||||
|
*
|
||||||
|
* @return 64-bit value which can be:\n
|
||||||
|
* @a time in seconds since EPOCH.\n
|
||||||
|
* @a 0 in case of en error
|
||||||
|
*/
|
||||||
|
uint64_t secure_time_get(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @}*/ // end of Secure-Time-API group
|
||||||
|
|
||||||
|
#endif // __SECURE_TIME_CLIENT_H__
|
|
@ -0,0 +1,42 @@
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This is the direct API call implementation of the Secure Time NSPE client
|
||||||
|
// interface.
|
||||||
|
// It can be used to built standalone Secure Time module without requiring SPM
|
||||||
|
// implementation.
|
||||||
|
|
||||||
|
#include "secure_time_client.h"
|
||||||
|
#include "secure_time_impl.h"
|
||||||
|
|
||||||
|
int32_t secure_time_set_trusted_init(uint64_t *nonce)
|
||||||
|
{
|
||||||
|
return secure_time_set_trusted_init_impl(nonce);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t secure_time_set_trusted_commit(const void *blob, size_t blob_size)
|
||||||
|
{
|
||||||
|
return secure_time_set_trusted_commit_impl(blob, blob_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t secure_time_set(uint64_t new_time)
|
||||||
|
{
|
||||||
|
return secure_time_set_impl(new_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t secure_time_get(void)
|
||||||
|
{
|
||||||
|
return secure_time_get_impl();
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
/* 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 __SECURE_TIME_CLIENT_SPE_H__
|
||||||
|
#define __SECURE_TIME_CLIENT_SPE_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "secure_time_client.h"
|
||||||
|
|
||||||
|
/** @addtogroup Secure-Time-API-SPE
|
||||||
|
* SPE only C interface for setting and getting secure time.
|
||||||
|
* All functions are blocking.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**< Maximal allowed blob size in bytes. */
|
||||||
|
#define SECURE_TIME_MAX_BLOB_SIZE_BYTES (10 * 1024UL)
|
||||||
|
|
||||||
|
/**< Timestamp size in bytes. */
|
||||||
|
#define SECURE_TIME_TIMESTAMP_SIZE_BYTES (8UL)
|
||||||
|
|
||||||
|
/**< Nonce size in bytes. */
|
||||||
|
#define SECURE_TIME_NONCE_SIZE_BYTES (8UL)
|
||||||
|
|
||||||
|
/**< The size of delegation length in bytes. */
|
||||||
|
#define SECURE_TIME_DELEGATION_LENGTH_SIZE_BYTES (2UL)
|
||||||
|
|
||||||
|
/**< The size of public key length field in bytes. */
|
||||||
|
#define SECURE_TIME_PUBKEY_LENGTH_SIZE_BYTES (2UL)
|
||||||
|
|
||||||
|
/**< The size of signature length field in bytes. */
|
||||||
|
#define SECURE_TIME_SIGNATURE_LENGTH_SIZE_BYTES (2UL)
|
||||||
|
|
||||||
|
/**< The size of public key length field in bytes. */
|
||||||
|
#define SECURE_TIME_PUBKEY_LENGTH_SIZE_BYTES (2UL)
|
||||||
|
|
||||||
|
/**< The size of the constant length blob header. */
|
||||||
|
#define SECURE_TIME_BLOB_HEADER_SIZE_BYTES \
|
||||||
|
( \
|
||||||
|
SECURE_TIME_TIMESTAMP_SIZE_BYTES + \
|
||||||
|
SECURE_TIME_NONCE_SIZE_BYTES + \
|
||||||
|
SECURE_TIME_DELEGATION_LENGTH_SIZE_BYTES \
|
||||||
|
)
|
||||||
|
|
||||||
|
/**< The location of the delegation length field in the blob. */
|
||||||
|
#define SECURE_TIME_DELEGATION_LENGTH_OFFSET \
|
||||||
|
( \
|
||||||
|
SECURE_TIME_TIMESTAMP_SIZE_BYTES + \
|
||||||
|
SECURE_TIME_NONCE_SIZE_BYTES \
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeration for the possible blob signature algorithms
|
||||||
|
*/
|
||||||
|
typedef enum signature_alg {
|
||||||
|
SIGNATURE_ALG_INVALID = 0, /**< Invalid algorithm type */
|
||||||
|
SIGNATURE_ALG_SHA256_ECDSA = 1, /**< ECDSA on a SHA256 hash */
|
||||||
|
SIGNATURE_ALG_MAX = SIGNATURE_ALG_SHA256_ECDSA
|
||||||
|
} SignatureAlg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory-setup provisioning of public key to be used by secure_time_set_trusted().
|
||||||
|
* Defined as a weak function which by default tries to write the public key to NVStore.
|
||||||
|
* If the user wants to provision the public key differently than this function needs
|
||||||
|
* to be implemented by the user according to the provisioning method, as well as
|
||||||
|
* secure_time_get_stored_public_key().
|
||||||
|
*
|
||||||
|
* @param[in] pubkey Public key for blob verification.
|
||||||
|
* @param[in] key_size Size in bytes of public key.
|
||||||
|
* @return 0 or negative error code if failed.
|
||||||
|
*/
|
||||||
|
int32_t secure_time_set_stored_public_key(const void* pubkey, size_t key_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the previously-provisioned public key.
|
||||||
|
* Defined as a weak function which by default tries to read the public key from NVStore.
|
||||||
|
* If the user provisioned the public key differently (By implementing secure_time_set_stored_public_key())
|
||||||
|
* than this function also needs to be implemented.
|
||||||
|
*
|
||||||
|
* @param[out] pubkey Buffer to fill with the public key.
|
||||||
|
* @param[in] size Size in bytes of the buffer.
|
||||||
|
* @param[out] actual_size Actual size in bytes of the returned public key.
|
||||||
|
* @return 0 or negative error code if failed.
|
||||||
|
*/
|
||||||
|
int32_t secure_time_get_stored_public_key(uint8_t *pubkey, size_t size, size_t *actual_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the size in bytes of the previously-provisioned public key.
|
||||||
|
* Defined as a weak function which by default tries to read the public key from NVStore.
|
||||||
|
* If the user provisioned the public key differently (By implementing secure_time_set_stored_public_key())
|
||||||
|
* than this function also needs to be implemented.
|
||||||
|
*
|
||||||
|
* @param[out] actual_size Actual size in bytes of the returned public key.
|
||||||
|
* @return 0 or negative error code if failed.
|
||||||
|
*/
|
||||||
|
int32_t secure_time_get_stored_public_key_size(size_t *actual_size);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @}*/ // end of Secure-Time-API group
|
||||||
|
|
||||||
|
#endif // __SECURE_TIME_CLIENT_SPE_H__
|
|
@ -0,0 +1,43 @@
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This is the direct API call implementation of the Secure Time SPE client
|
||||||
|
// interface.
|
||||||
|
// This file extends NSPE interface implementation by implementing APIs
|
||||||
|
// available from SPE only.
|
||||||
|
// This file can be used to built standalone Secure Time module without
|
||||||
|
// requiring full SPM implementation.
|
||||||
|
|
||||||
|
#include "secure_time_client_spe.h"
|
||||||
|
#include "secure_time_impl.h"
|
||||||
|
|
||||||
|
int32_t secure_time_set_stored_public_key(const void* pubkey, size_t key_size)
|
||||||
|
{
|
||||||
|
return secure_time_set_stored_public_key_impl(pubkey, key_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t secure_time_get_stored_public_key(
|
||||||
|
uint8_t *pubkey,
|
||||||
|
size_t size,
|
||||||
|
size_t *actual_size
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return secure_time_get_stored_public_key_impl(pubkey, size, actual_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t secure_time_get_stored_public_key_size(size_t *actual_size)
|
||||||
|
{
|
||||||
|
return secure_time_get_stored_public_key_size_impl(actual_size);
|
||||||
|
}
|
|
@ -0,0 +1,407 @@
|
||||||
|
/* 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 "secure_time_utils.h"
|
||||||
|
#include "secure_time_impl.h"
|
||||||
|
#include "secure_time_client_spe.h"
|
||||||
|
#include "secure_time_storage.h"
|
||||||
|
#include "secure_time_crypto.h"
|
||||||
|
#include "mbed_error.h"
|
||||||
|
#include "platform/mbed_rtc_time.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define SECURE_TIME_NONCE_GENERATION_TIME_INVALID UINT64_MAX
|
||||||
|
|
||||||
|
#define EXTRACT_UINT16(buf) ((((uint16_t)(((uint8_t *)(buf))[1])) << 8) + (uint16_t)(((uint8_t *)(buf))[0]))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enumeration for the possible directions for setting the time.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
SECURE_TIME_FORWARD = 1,
|
||||||
|
SECURE_TIME_BACKWARDS = 2
|
||||||
|
} SecureTimeDirection;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure used during delegation record parsiong.
|
||||||
|
*/
|
||||||
|
typedef struct delegation_record_info {
|
||||||
|
const uint8_t *record_start;
|
||||||
|
uint16_t pubkey_size;
|
||||||
|
const uint8_t *pubkey;
|
||||||
|
uint16_t signature_size;
|
||||||
|
const uint8_t *signature;
|
||||||
|
} delegation_record_info_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure containing context of the NONCE.
|
||||||
|
*/
|
||||||
|
typedef struct nonce_ctx {
|
||||||
|
uint64_t generation_time; /* Timestamp of last generated NONCE. */
|
||||||
|
uint64_t nonce; /* The last generated nonce. */
|
||||||
|
} nonce_data_t;
|
||||||
|
|
||||||
|
static nonce_data_t g_trusted_time_nonce = {
|
||||||
|
.generation_time = SECURE_TIME_NONCE_GENERATION_TIME_INVALID,
|
||||||
|
.nonce = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
static void invalidate_nonce(nonce_data_t *nonce_data)
|
||||||
|
{
|
||||||
|
nonce_data->generation_time = SECURE_TIME_NONCE_GENERATION_TIME_INVALID;
|
||||||
|
nonce_data->nonce = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_nonce_valid(nonce_data_t *nonce)
|
||||||
|
{
|
||||||
|
return (SECURE_TIME_NONCE_GENERATION_TIME_INVALID != nonce->generation_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t extract_nonce_and_verify(const uint8_t *blob, size_t blob_size)
|
||||||
|
{
|
||||||
|
if (!is_nonce_valid(&g_trusted_time_nonce)) {
|
||||||
|
return SECURE_TIME_NONCE_MISSING;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t blob_nonce;
|
||||||
|
memcpy(&blob_nonce, blob + SECURE_TIME_TIMESTAMP_SIZE_BYTES, SECURE_TIME_NONCE_SIZE_BYTES);
|
||||||
|
|
||||||
|
if (blob_nonce != g_trusted_time_nonce.nonce) {
|
||||||
|
return SECURE_TIME_NONCE_NOT_MATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((secure_time_get_impl() - g_trusted_time_nonce.generation_time) > SECURE_TIME_NONCE_TIMEOUT_SECONDS) {
|
||||||
|
// If invalidation timeout expired, invalidate SPE nonce.
|
||||||
|
invalidate_nonce(&g_trusted_time_nonce);
|
||||||
|
return SECURE_TIME_NONCE_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SECURE_TIME_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t parse_delegation_record(
|
||||||
|
const uint8_t *record_ptr,
|
||||||
|
uint32_t bytes_left,
|
||||||
|
delegation_record_info_t *record_info
|
||||||
|
)
|
||||||
|
{
|
||||||
|
record_info->record_start = record_ptr;
|
||||||
|
|
||||||
|
// Make sure the delegation record is big enough for the public key length field.
|
||||||
|
if (bytes_left < SECURE_TIME_PUBKEY_LENGTH_SIZE_BYTES) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the public key length.
|
||||||
|
record_info->pubkey_size = EXTRACT_UINT16(record_ptr);
|
||||||
|
bytes_left -= SECURE_TIME_PUBKEY_LENGTH_SIZE_BYTES;
|
||||||
|
record_ptr += SECURE_TIME_PUBKEY_LENGTH_SIZE_BYTES;
|
||||||
|
|
||||||
|
// Make sure there're enough bytes left for the key.
|
||||||
|
if (record_info->pubkey_size == 0 || record_info->pubkey_size > bytes_left) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember the key location.
|
||||||
|
record_info->pubkey = record_ptr;
|
||||||
|
bytes_left -= record_info->pubkey_size;
|
||||||
|
record_ptr += record_info->pubkey_size;
|
||||||
|
|
||||||
|
// Make sure the delegation record is big enough for the signature length field.
|
||||||
|
if (bytes_left < SECURE_TIME_SIGNATURE_LENGTH_SIZE_BYTES) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the signature length.
|
||||||
|
record_info->signature_size = EXTRACT_UINT16(record_ptr);
|
||||||
|
bytes_left -= SECURE_TIME_SIGNATURE_LENGTH_SIZE_BYTES;
|
||||||
|
record_ptr += SECURE_TIME_SIGNATURE_LENGTH_SIZE_BYTES;
|
||||||
|
|
||||||
|
// Make sure there're enough bytes left for the signature.
|
||||||
|
if (record_info->signature_size == 0 || record_info->signature_size > bytes_left) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember the signature location.
|
||||||
|
record_info->signature = record_ptr;
|
||||||
|
record_ptr += record_info->signature_size;
|
||||||
|
|
||||||
|
// Return the record size.
|
||||||
|
return record_ptr - record_info->record_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t verify_blob(
|
||||||
|
const uint8_t *blob,
|
||||||
|
size_t blob_size,
|
||||||
|
const uint8_t *ca_pubkey,
|
||||||
|
size_t ca_pubkey_size
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rc = SECURE_TIME_SUCCESS;
|
||||||
|
|
||||||
|
// Make sure that the blob is big enough to contain at least the header.
|
||||||
|
if (blob_size < SECURE_TIME_BLOB_HEADER_SIZE_BYTES || blob_size > SECURE_TIME_MAX_BLOB_SIZE_BYTES) {
|
||||||
|
return SECURE_TIME_INVALID_BLOB_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the size of the delegation section.
|
||||||
|
uint16_t delegation_size = EXTRACT_UINT16(blob + SECURE_TIME_DELEGATION_LENGTH_OFFSET);
|
||||||
|
|
||||||
|
// Make sure the delegation section followed by the signature length field fits within the blob.
|
||||||
|
if (SECURE_TIME_BLOB_HEADER_SIZE_BYTES +
|
||||||
|
delegation_size +
|
||||||
|
SECURE_TIME_SIGNATURE_LENGTH_SIZE_BYTES > blob_size) {
|
||||||
|
return SECURE_TIME_INVALID_BLOB_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go over all the keys in the delegation records of the blob and verify
|
||||||
|
// their signatures.
|
||||||
|
const uint8_t *delegation_start = blob + SECURE_TIME_BLOB_HEADER_SIZE_BYTES;
|
||||||
|
const uint8_t *delegation_end = delegation_start + delegation_size;
|
||||||
|
uint32_t bytes_left = 0;
|
||||||
|
delegation_record_info_t prev_record_info = {0};
|
||||||
|
prev_record_info.pubkey = ca_pubkey;
|
||||||
|
prev_record_info.pubkey_size = ca_pubkey_size;
|
||||||
|
delegation_record_info_t cur_record_info = {0};
|
||||||
|
size_t cur_record_size = 0;
|
||||||
|
|
||||||
|
while (delegation_start < delegation_end) {
|
||||||
|
bytes_left = delegation_end - delegation_start;
|
||||||
|
|
||||||
|
cur_record_size = parse_delegation_record(delegation_start, bytes_left, &cur_record_info);
|
||||||
|
if (cur_record_size == 0) {
|
||||||
|
return SECURE_TIME_INVALID_BLOB_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = secure_time_verify_signature(
|
||||||
|
cur_record_info.record_start,
|
||||||
|
cur_record_info.pubkey_size + SECURE_TIME_PUBKEY_LENGTH_SIZE_BYTES,
|
||||||
|
cur_record_info.signature,
|
||||||
|
cur_record_info.signature_size,
|
||||||
|
prev_record_info.pubkey,
|
||||||
|
prev_record_info.pubkey_size
|
||||||
|
);
|
||||||
|
|
||||||
|
if (SECURE_TIME_SUCCESS != rc) {
|
||||||
|
return SECURE_TIME_SIGNATURE_VERIFICATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
delegation_start += cur_record_size;
|
||||||
|
prev_record_info = cur_record_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the size of the blob's signature.
|
||||||
|
uint16_t blob_signature_size = EXTRACT_UINT16(delegation_end);
|
||||||
|
const uint8_t *blob_signature = delegation_end + SECURE_TIME_SIGNATURE_LENGTH_SIZE_BYTES;
|
||||||
|
|
||||||
|
// Make sure the number of the remaining bytes is exactly as the blob's signature size.
|
||||||
|
if ((blob_size -
|
||||||
|
SECURE_TIME_BLOB_HEADER_SIZE_BYTES -
|
||||||
|
delegation_size -
|
||||||
|
SECURE_TIME_SIGNATURE_LENGTH_SIZE_BYTES) != blob_signature_size) {
|
||||||
|
return SECURE_TIME_INVALID_BLOB_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the overall blob signature.
|
||||||
|
// At this stage prev_record_info contains the public key that should be used for the verification.
|
||||||
|
rc = secure_time_verify_signature(
|
||||||
|
blob,
|
||||||
|
SECURE_TIME_BLOB_HEADER_SIZE_BYTES + delegation_size,
|
||||||
|
blob_signature,
|
||||||
|
blob_signature_size,
|
||||||
|
prev_record_info.pubkey,
|
||||||
|
prev_record_info.pubkey_size
|
||||||
|
);
|
||||||
|
|
||||||
|
if (SECURE_TIME_SUCCESS != rc) {
|
||||||
|
return SECURE_TIME_SIGNATURE_VERIFICATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t secure_time_set_trusted_init_impl(uint64_t *nonce)
|
||||||
|
{
|
||||||
|
if (!nonce) {
|
||||||
|
error("nonce is NULL!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalidate any existing nonce
|
||||||
|
invalidate_nonce(&g_trusted_time_nonce);
|
||||||
|
|
||||||
|
secure_time_generate_random_bytes(sizeof(uint64_t), &g_trusted_time_nonce.nonce);
|
||||||
|
*nonce = g_trusted_time_nonce.nonce;
|
||||||
|
g_trusted_time_nonce.generation_time = secure_time_get_impl();
|
||||||
|
return SECURE_TIME_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t secure_time_set_trusted_commit_impl(const void *blob, size_t blob_size)
|
||||||
|
{
|
||||||
|
int rc = SECURE_TIME_SUCCESS;
|
||||||
|
if (!blob || (0 == blob_size)) {
|
||||||
|
error("blob is NULL or size 0!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the CA public key from secure storage.
|
||||||
|
size_t ca_pubkey_size = 0;
|
||||||
|
|
||||||
|
rc = secure_time_get_stored_public_key_size(&ca_pubkey_size);
|
||||||
|
if (SECURE_TIME_SUCCESS != rc) {
|
||||||
|
error("Failed to read the CA public key size! (rc=%d)", rc);
|
||||||
|
}
|
||||||
|
uint8_t *ca_pubkey = (uint8_t *)malloc(ca_pubkey_size);
|
||||||
|
if (!ca_pubkey) {
|
||||||
|
error("Failed to allocate memory for CA public key data!");
|
||||||
|
}
|
||||||
|
rc = secure_time_get_stored_public_key(ca_pubkey, ca_pubkey_size, &ca_pubkey_size);
|
||||||
|
if (SECURE_TIME_SUCCESS != rc) {
|
||||||
|
error("Failed to read the CA public key! (rc=%d)", rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the blob's correctness.
|
||||||
|
rc = verify_blob(blob, blob_size, ca_pubkey, ca_pubkey_size);
|
||||||
|
free(ca_pubkey);
|
||||||
|
|
||||||
|
if (SECURE_TIME_SUCCESS == rc) {
|
||||||
|
// Extract the new time value from the blob according to the schema.
|
||||||
|
uint64_t new_time;
|
||||||
|
memcpy(&new_time, blob, SECURE_TIME_TIMESTAMP_SIZE_BYTES);
|
||||||
|
|
||||||
|
// Extract the nonce from the blob and verify its' correctness and freshness.
|
||||||
|
// In case the the nonce is different than the last generated nonce or is too old,
|
||||||
|
// the call is ignored.
|
||||||
|
rc = extract_nonce_and_verify((const uint8_t *)blob, blob_size);
|
||||||
|
if (SECURE_TIME_SUCCESS == rc) {
|
||||||
|
// Get current RTC time.
|
||||||
|
uint64_t rtc_time = (uint64_t)time(NULL);
|
||||||
|
|
||||||
|
// Set RTC with new time if it is around 1-2 minutes forward/backward
|
||||||
|
// than current RTC time.
|
||||||
|
if(llabs(new_time - rtc_time) > SECURE_TIME_MIN_RTC_LATENCY_SEC) {
|
||||||
|
set_time(new_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the current stored time from secure storage.
|
||||||
|
uint64_t stored_time = 0;
|
||||||
|
secure_time_get_stored_time(&stored_time);
|
||||||
|
|
||||||
|
SecureTimeDirection direction = (new_time > stored_time) ?
|
||||||
|
SECURE_TIME_FORWARD :
|
||||||
|
SECURE_TIME_BACKWARDS;
|
||||||
|
bool set_storage = false;
|
||||||
|
|
||||||
|
// If new time is less than 1 day forward or less than 1-2 minutes backwards
|
||||||
|
// do not update secure storage.
|
||||||
|
if (SECURE_TIME_FORWARD == direction) {
|
||||||
|
set_storage = (new_time - stored_time) > SECURE_TIME_MIN_STORAGE_FORWARD_LATENCY_SEC;
|
||||||
|
} else {
|
||||||
|
set_storage = (stored_time - new_time) > SECURE_TIME_MIN_STORAGE_BACKWARD_LATENCY_SEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set_storage) {
|
||||||
|
// Write the new time to secure storage entry of last backwards time.
|
||||||
|
secure_time_set_stored_back_time(new_time);
|
||||||
|
|
||||||
|
// Write the new time to secure storage entry of current stored time.
|
||||||
|
secure_time_set_stored_time(new_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the SPE delta value as the new time minus current SPE tick count.
|
||||||
|
secure_time_update_boot_time(new_time);
|
||||||
|
|
||||||
|
// Invalidate nonce
|
||||||
|
invalidate_nonce(&g_trusted_time_nonce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_time_forward(uint64_t new_time, uint64_t curr_os_time)
|
||||||
|
{
|
||||||
|
// Update the SPE delta value as the new time minus current SPE tick count.
|
||||||
|
secure_time_update_boot_time(new_time);
|
||||||
|
|
||||||
|
// Set RTC with new time if it is around 1-2 minutes forward than current time.
|
||||||
|
uint64_t rtc_time = (uint64_t)time(NULL);
|
||||||
|
if((new_time - rtc_time) > SECURE_TIME_MIN_RTC_LATENCY_SEC) {
|
||||||
|
set_time(new_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write new time to secure storage entry of current stored time if it's more than 1 day forward
|
||||||
|
// than current OS time.
|
||||||
|
bool set_storage = (new_time - curr_os_time) > SECURE_TIME_MIN_STORAGE_FORWARD_LATENCY_SEC;
|
||||||
|
if (set_storage) {
|
||||||
|
secure_time_set_stored_time(new_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t set_time_backwards(uint64_t new_time, uint64_t curr_os_time)
|
||||||
|
{
|
||||||
|
uint64_t stored_back_time = 0;
|
||||||
|
secure_time_get_stored_back_time(&stored_back_time);
|
||||||
|
bool stored_back_time_exist = (stored_back_time > 0);
|
||||||
|
|
||||||
|
// For each day between stored_back_time and new_time we can move backwards by up to 3 minutes:
|
||||||
|
// Which is same as up to 480 seconds for each second in this interval.
|
||||||
|
// So: (A) MAX_BACK_SECONDS = (new_time - stored_back_time)/480
|
||||||
|
// (B) (curr_os_time - new_time) <= MAX_BACK_SECONDS
|
||||||
|
// (A & B) (curr_os_time - new_time) <= (new_time - stored_back_time)/480
|
||||||
|
bool set_back = ( stored_back_time_exist &&
|
||||||
|
(new_time > stored_back_time) &&
|
||||||
|
((curr_os_time - new_time) <= (new_time - stored_back_time)/480) );
|
||||||
|
if (set_back) {
|
||||||
|
// Update the SPE delta value as the new time minus current SPE tick count.
|
||||||
|
secure_time_update_boot_time(new_time);
|
||||||
|
|
||||||
|
// Write the new time to secure storage entry of last backwards time and current stored time.
|
||||||
|
secure_time_set_stored_back_time(new_time);
|
||||||
|
secure_time_set_stored_time(new_time);
|
||||||
|
return SECURE_TIME_SUCCESS;
|
||||||
|
}
|
||||||
|
return SECURE_TIME_NOT_ALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t secure_time_set_impl(uint64_t new_time)
|
||||||
|
{
|
||||||
|
// Get the current time in the device.
|
||||||
|
uint64_t curr_os_time = secure_time_get_impl();
|
||||||
|
SecureTimeDirection direction = (new_time > curr_os_time) ?
|
||||||
|
SECURE_TIME_FORWARD :
|
||||||
|
SECURE_TIME_BACKWARDS;
|
||||||
|
|
||||||
|
if (SECURE_TIME_FORWARD == direction) {
|
||||||
|
set_time_forward(new_time, curr_os_time);
|
||||||
|
} else {
|
||||||
|
return set_time_backwards(new_time, curr_os_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t stored_time = 0;
|
||||||
|
secure_time_get_stored_time(&stored_time);
|
||||||
|
|
||||||
|
// Write the new time to secure storage entry of current stored time
|
||||||
|
// if new time is more than around 5-6 days forward than current stored time.
|
||||||
|
if ( (new_time > stored_time) &&
|
||||||
|
((new_time - stored_time) > SECURE_TIME_MIN_STORAGE_IDLE_LATENCY_SEC) ) {
|
||||||
|
secure_time_set_stored_time(new_time);
|
||||||
|
}
|
||||||
|
return SECURE_TIME_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t secure_time_get_impl(void)
|
||||||
|
{
|
||||||
|
uint64_t boot_time = secure_time_get_boot_time();
|
||||||
|
uint64_t secs_since_boot = secure_time_get_seconds_since_boot();
|
||||||
|
return (boot_time > 0) ? (boot_time + secs_since_boot) : 0;
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/* 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 __SECURE_TIME_IMPL_H__
|
||||||
|
#define __SECURE_TIME_IMPL_H__
|
||||||
|
|
||||||
|
#include "secure_time_client_spe.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**< Maximum time a nonce is valid after generation.*/
|
||||||
|
#define SECURE_TIME_NONCE_TIMEOUT_SECONDS (300UL)
|
||||||
|
|
||||||
|
int32_t secure_time_set_trusted_init_impl(uint64_t *nonce);
|
||||||
|
|
||||||
|
int32_t secure_time_set_trusted_commit_impl(const void *blob, size_t blob_size);
|
||||||
|
|
||||||
|
int32_t secure_time_set_impl(uint64_t new_time);
|
||||||
|
|
||||||
|
uint64_t secure_time_get_impl(void);
|
||||||
|
|
||||||
|
int32_t secure_time_set_stored_public_key_impl(const void* pubkey, size_t key_size);
|
||||||
|
|
||||||
|
int32_t secure_time_get_stored_public_key_impl(
|
||||||
|
uint8_t *pubkey,
|
||||||
|
size_t size,
|
||||||
|
size_t *actual_size
|
||||||
|
);
|
||||||
|
|
||||||
|
int32_t secure_time_get_stored_public_key_size_impl(size_t *actual_size);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __SECURE_TIME_IMPL_H__
|
|
@ -0,0 +1,39 @@
|
||||||
|
/* 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 <secure_time_utils.h>
|
||||||
|
#include "secure_time_client_spe.h"
|
||||||
|
#include "mbed_error.h"
|
||||||
|
#include "cmsis_os2.h"
|
||||||
|
#include "rtos/Kernel.h"
|
||||||
|
|
||||||
|
using namespace rtos;
|
||||||
|
|
||||||
|
static uint64_t g_boot_time_in_secs = 0;
|
||||||
|
|
||||||
|
uint64_t secure_time_get_seconds_since_boot(void)
|
||||||
|
{
|
||||||
|
uint32_t freq = osKernelGetTickFreq();
|
||||||
|
return Kernel::get_ms_count() / freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
void secure_time_update_boot_time(uint64_t new_time)
|
||||||
|
{
|
||||||
|
g_boot_time_in_secs = new_time - secure_time_get_seconds_since_boot();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t secure_time_get_boot_time(void)
|
||||||
|
{
|
||||||
|
return g_boot_time_in_secs;
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
/* 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 __SECURE_TIME_INTERNAL_H__
|
||||||
|
#define __SECURE_TIME_INTERNAL_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SECURE_TIME_MIN_RTC_LATENCY_SEC (100UL)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the device boot time in seconds since EPOCH.
|
||||||
|
*
|
||||||
|
* @return 64-bit value of seconds.
|
||||||
|
*/
|
||||||
|
uint64_t secure_time_get_boot_time(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update the device boot time according to the new time.
|
||||||
|
*
|
||||||
|
* @param[in] new_time Time value in seconds since EPOCH to update boot time.\n
|
||||||
|
* updated_boot_time = new_time - seconds_since_last_boot
|
||||||
|
*/
|
||||||
|
void secure_time_update_boot_time(uint64_t new_time);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return how many seconds have passed since last boot.
|
||||||
|
*
|
||||||
|
* @return 64-bit value of seconds.
|
||||||
|
*/
|
||||||
|
uint64_t secure_time_get_seconds_since_boot(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __SECURE_TIME_INTERNAL_H__
|
|
@ -0,0 +1,125 @@
|
||||||
|
/* 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 <secure_time_utils.h>
|
||||||
|
#include "secure_time_storage.h"
|
||||||
|
#include "secure_time_client_spe.h"
|
||||||
|
#include "secure_time_impl.h"
|
||||||
|
#include "nvstore.h"
|
||||||
|
#include "mbed_toolchain.h"
|
||||||
|
#include "mbed_error.h"
|
||||||
|
|
||||||
|
#if !NVSTORE_ENABLED
|
||||||
|
#error [NOT_SUPPORTED] NVSTORE needs to be enabled
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MBED_WEAK int32_t secure_time_set_stored_public_key_impl(const void* pubkey, size_t key_size)
|
||||||
|
{
|
||||||
|
if (NULL == pubkey) {
|
||||||
|
error("pubkey is NULL!");
|
||||||
|
}
|
||||||
|
NVStore &nvstore = NVStore::get_instance();
|
||||||
|
int rc = nvstore.set(NVSTORE_CA_PUBKEY_KEY, key_size, pubkey);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
MBED_WEAK int32_t secure_time_get_stored_public_key_impl(uint8_t *pubkey, size_t size, size_t *actual_size)
|
||||||
|
{
|
||||||
|
if (NULL == pubkey) {
|
||||||
|
error("pubkey is NULL!");
|
||||||
|
}
|
||||||
|
if (NULL == actual_size) {
|
||||||
|
error("actual_size is NULL!");
|
||||||
|
}
|
||||||
|
uint16_t len = 0;
|
||||||
|
NVStore &nvstore = NVStore::get_instance();
|
||||||
|
int rc = nvstore.get(
|
||||||
|
NVSTORE_CA_PUBKEY_KEY,
|
||||||
|
size,
|
||||||
|
pubkey,
|
||||||
|
len
|
||||||
|
);
|
||||||
|
*actual_size = (size_t)len;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
MBED_WEAK int32_t secure_time_get_stored_public_key_size_impl(size_t *actual_size)
|
||||||
|
{
|
||||||
|
if (NULL == actual_size) {
|
||||||
|
error("actual_size is NULL!");
|
||||||
|
}
|
||||||
|
uint16_t len = 0;
|
||||||
|
NVStore &nvstore = NVStore::get_instance();
|
||||||
|
int rc = nvstore.get_item_size(NVSTORE_CA_PUBKEY_KEY, len);
|
||||||
|
*actual_size = (size_t)len;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void secure_time_set_stored_time(uint64_t new_time)
|
||||||
|
{
|
||||||
|
NVStore &nvstore = NVStore::get_instance();
|
||||||
|
int rc = nvstore.set(NVSTORE_STORED_TIME_KEY, sizeof(new_time), &new_time);
|
||||||
|
if (NVSTORE_SUCCESS != rc) {
|
||||||
|
error("Failed to set STORED_TIME to NVStore! (rc=%d)", rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void secure_time_get_stored_time(uint64_t *stored_time)
|
||||||
|
{
|
||||||
|
if (NULL == stored_time) {
|
||||||
|
error("stored_time is NULL!");
|
||||||
|
}
|
||||||
|
NVStore &nvstore = NVStore::get_instance();
|
||||||
|
uint16_t len = 0;
|
||||||
|
int rc = nvstore.get(NVSTORE_STORED_TIME_KEY, sizeof(*stored_time), stored_time, len);
|
||||||
|
if ((NVSTORE_SUCCESS != rc) && (NVSTORE_NOT_FOUND != rc)) {
|
||||||
|
error("Failed to get STORED_TIME from NVStore! (rc=%d)", rc);
|
||||||
|
}
|
||||||
|
else if ((sizeof(*stored_time) != len) && (NVSTORE_NOT_FOUND != rc)) {
|
||||||
|
error("Length of STORED_TIME entry too short! (%uh)", len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NVSTORE_NOT_FOUND == rc) {
|
||||||
|
*stored_time = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void secure_time_set_stored_back_time(uint64_t new_time)
|
||||||
|
{
|
||||||
|
NVStore &nvstore = NVStore::get_instance();
|
||||||
|
int rc = nvstore.set(NVSTORE_STORED_BACK_TIME_KEY, sizeof(new_time), &new_time);
|
||||||
|
if (NVSTORE_SUCCESS != rc) {
|
||||||
|
error("Failed to set STORED_BACK_TIME to NVStore! (rc=%d)", rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void secure_time_get_stored_back_time(uint64_t *stored_back_time)
|
||||||
|
{
|
||||||
|
if (NULL == stored_back_time) {
|
||||||
|
error("stored_back_time is NULL!");
|
||||||
|
}
|
||||||
|
NVStore &nvstore = NVStore::get_instance();
|
||||||
|
uint16_t len = 0;
|
||||||
|
int rc = nvstore.get(NVSTORE_STORED_BACK_TIME_KEY, sizeof(*stored_back_time), stored_back_time, len);
|
||||||
|
if ((NVSTORE_SUCCESS != rc) && (NVSTORE_NOT_FOUND != rc)) {
|
||||||
|
error("Failed to get STORED_BACK_TIME from NVStore! (rc=%d)", rc);
|
||||||
|
}
|
||||||
|
else if ((sizeof(*stored_back_time) != len) && (NVSTORE_NOT_FOUND != rc)) {
|
||||||
|
error("Length of STORED_BACK_TIME entry too short! (%uh)", len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NVSTORE_NOT_FOUND == rc) {
|
||||||
|
*stored_back_time = 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/* 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 __SECURE_TIME_STORAGE_H__
|
||||||
|
#define __SECURE_TIME_STORAGE_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Storage latency defines
|
||||||
|
#define SECURE_TIME_MIN_STORAGE_FORWARD_LATENCY_SEC (100000UL)
|
||||||
|
#define SECURE_TIME_MIN_STORAGE_BACKWARD_LATENCY_SEC (100UL)
|
||||||
|
#define SECURE_TIME_MIN_STORAGE_IDLE_LATENCY_SEC (500000UL)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set storage entry of last set time.
|
||||||
|
*
|
||||||
|
* @param[in] new_time Time value in seconds since EPOCH.
|
||||||
|
*/
|
||||||
|
void secure_time_set_stored_time(uint64_t new_time);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get storage entry of last set time.
|
||||||
|
*
|
||||||
|
* @param[out] stored_time Time value in seconds since EPOCH, 0 if not exists.
|
||||||
|
*/
|
||||||
|
void secure_time_get_stored_time(uint64_t *stored_time);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set storage entry of last set-backwards time.
|
||||||
|
*
|
||||||
|
* @param[in] new_time Time value in seconds since EPOCH.
|
||||||
|
*/
|
||||||
|
void secure_time_set_stored_back_time(uint64_t new_time);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get storage entry of last set-backwards time.
|
||||||
|
*
|
||||||
|
* @param[out] stored_back_time Time value in seconds since EPOCH, 0 if not exists.
|
||||||
|
*/
|
||||||
|
void secure_time_get_stored_back_time(uint64_t *stored_back_time);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __SECURE_TIME_STORAGE_H__
|
Loading…
Reference in New Issue