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