1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2019, Linaro Limited
*/
#include <crypto/crypto.h>
#include <kernel/huk_subkey.h>
#include <kernel/tee_common_otp.h>
#include <tee/tee_fs_key_manager.h>
static TEE_Result mac_usage(void *ctx, uint32_t usage)
{
return crypto_mac_update(ctx, TEE_ALG_HMAC_SHA256,
(const void *)&usage, sizeof(usage));
}
#ifdef CFG_CORE_HUK_SUBKEY_COMPAT
/*
* This gives the result of the default tee_otp_get_die_id()
* implementation.
*/
static void get_dummy_die_id(uint8_t *buffer, size_t len)
{
static const char pattern[4] = { 'B', 'E', 'E', 'F' };
size_t i;
for (i = 0; i < len; i++)
buffer[i] = pattern[i % 4];
}
/*
* This does special treatment for RPMB and SSK key derivations to give
* the same result as when huk_subkey_derive() wasn't used.
*/
static TEE_Result huk_compat(void *ctx, enum huk_subkey_usage usage)
{
TEE_Result res = TEE_SUCCESS;
uint8_t chip_id[TEE_FS_KM_CHIP_ID_LENGTH] = { 0 };
static uint8_t ssk_str[] = "ONLY_FOR_tee_fs_ssk";
switch (usage) {
case HUK_SUBKEY_RPMB:
return TEE_SUCCESS;
case HUK_SUBKEY_SSK:
get_dummy_die_id(chip_id, sizeof(chip_id));
res = crypto_mac_update(ctx, TEE_ALG_HMAC_SHA256,
chip_id, sizeof(chip_id));
if (res)
return res;
return crypto_mac_update(ctx, TEE_ALG_HMAC_SHA256,
ssk_str, sizeof(ssk_str));
default:
return mac_usage(ctx, usage);
}
}
#endif /*CFG_CORE_HUK_SUBKEY_COMPAT*/
TEE_Result huk_subkey_derive(enum huk_subkey_usage usage,
const void *const_data, size_t const_data_len,
uint8_t *subkey, size_t subkey_len)
{
void *ctx = NULL;
struct tee_hw_unique_key huk = { };
TEE_Result res = TEE_SUCCESS;
if (subkey_len > HUK_SUBKEY_MAX_LEN)
return TEE_ERROR_BAD_PARAMETERS;
if (!const_data && const_data_len)
return TEE_ERROR_BAD_PARAMETERS;
res = crypto_mac_alloc_ctx(&ctx, TEE_ALG_HMAC_SHA256);
if (res)
return res;
res = tee_otp_get_hw_unique_key(&huk);
if (res)
goto out;
res = crypto_mac_init(ctx, TEE_ALG_HMAC_SHA256, huk.data,
sizeof(huk.data));
if (res)
goto out;
#ifdef CFG_CORE_HUK_SUBKEY_COMPAT
res = huk_compat(ctx, usage);
#else
res = mac_usage(ctx, usage);
#endif
if (res)
goto out;
if (const_data) {
res = crypto_mac_update(ctx, TEE_ALG_HMAC_SHA256, const_data,
const_data_len);
if (res)
goto out;
}
res = crypto_mac_final(ctx, TEE_ALG_HMAC_SHA256, subkey, subkey_len);
out:
if (res)
memset(subkey, 0, subkey_len);
memset(&huk, 0, sizeof(huk));
crypto_mac_free_ctx(ctx, TEE_ALG_HMAC_SHA256);
return res;
}
|