1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2014, Linaro Limited
4 */
5
6 #include <crypto/crypto.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <tee/tee_cryp_hkdf.h>
10 #include <tee/tee_cryp_utl.h>
11 #include <utee_defines.h>
12
13
14 static const uint8_t zero_salt[TEE_MAX_HASH_SIZE];
15
hkdf_extract(uint32_t hash_id,const uint8_t * ikm,size_t ikm_len,const uint8_t * salt,size_t salt_len,uint8_t * prk,size_t * prk_len)16 static TEE_Result hkdf_extract(uint32_t hash_id, const uint8_t *ikm,
17 size_t ikm_len, const uint8_t *salt,
18 size_t salt_len, uint8_t *prk, size_t *prk_len)
19 {
20 TEE_Result res;
21 void *ctx = NULL;
22 uint32_t hash_algo = TEE_ALG_HASH_ALGO(hash_id);
23 uint32_t hmac_algo = (TEE_OPERATION_MAC << 28) | hash_id;
24
25 if (!salt || !salt_len) {
26 /*
27 * RFC 5869 section 2.2:
28 * If not provided, [the salt] is set to a string of HashLen
29 * zeros
30 */
31 salt = zero_salt;
32 res = tee_alg_get_digest_size(hash_algo, &salt_len);
33 if (res != TEE_SUCCESS)
34 goto out;
35 }
36
37 res = crypto_mac_alloc_ctx(&ctx, hmac_algo);
38 if (res)
39 goto out;
40
41 /*
42 * RFC 5869 section 2.1: "Note that in the extract step, 'IKM' is used
43 * as the HMAC input, not as the HMAC key."
44 * Therefore, salt is the HMAC key in the formula from section 2.2:
45 * "PRK = HMAC-Hash(salt, IKM)"
46 */
47 res = crypto_mac_init(ctx, salt, salt_len);
48 if (res != TEE_SUCCESS)
49 goto out;
50
51 res = crypto_mac_update(ctx, ikm, ikm_len);
52 if (res != TEE_SUCCESS)
53 goto out;
54
55 res = crypto_mac_final(ctx, prk, *prk_len);
56 if (res != TEE_SUCCESS)
57 goto out;
58
59 res = tee_alg_get_digest_size(hash_algo, prk_len);
60 out:
61 crypto_mac_free_ctx(ctx);
62 return res;
63 }
64
hkdf_expand(uint32_t hash_id,const uint8_t * prk,size_t prk_len,const uint8_t * info,size_t info_len,uint8_t * okm,size_t okm_len)65 static TEE_Result hkdf_expand(uint32_t hash_id, const uint8_t *prk,
66 size_t prk_len, const uint8_t *info,
67 size_t info_len, uint8_t *okm, size_t okm_len)
68 {
69 uint8_t tn[TEE_MAX_HASH_SIZE];
70 size_t tn_len, hash_len, i, n, where;
71 TEE_Result res = TEE_SUCCESS;
72 void *ctx = NULL;
73 uint32_t hash_algo = TEE_ALG_HASH_ALGO(hash_id);
74 uint32_t hmac_algo = TEE_ALG_HMAC_ALGO(hash_id);
75
76 res = tee_alg_get_digest_size(hash_algo, &hash_len);
77 if (res != TEE_SUCCESS)
78 goto out;
79
80 if (!okm || prk_len < hash_len) {
81 res = TEE_ERROR_BAD_STATE;
82 goto out;
83 }
84
85 if (!info)
86 info_len = 0;
87
88 res = crypto_mac_alloc_ctx(&ctx, hmac_algo);
89 if (res)
90 goto out;
91
92 /* N = ceil(L/HashLen) */
93 n = okm_len / hash_len;
94 if ((okm_len % hash_len) != 0)
95 n++;
96
97 if (n > 255) {
98 res = TEE_ERROR_BAD_PARAMETERS;
99 goto out;
100 }
101
102
103 /*
104 * RFC 5869 section 2.3
105 * T = T(1) | T(2) | T(3) | ... | T(N)
106 * OKM = first L octets of T
107 * T(0) = empty string (zero length)
108 * T(1) = HMAC-Hash(PRK, T(0) | info | 0x01)
109 * T(2) = HMAC-Hash(PRK, T(1) | info | 0x02)
110 * T(3) = HMAC-Hash(PRK, T(2) | info | 0x03)
111 * ...
112 */
113 tn_len = 0;
114 where = 0;
115 for (i = 1; i <= n; i++) {
116 uint8_t c = i;
117
118 res = crypto_mac_init(ctx, prk, prk_len);
119 if (res != TEE_SUCCESS)
120 goto out;
121 res = crypto_mac_update(ctx, tn, tn_len);
122 if (res != TEE_SUCCESS)
123 goto out;
124 res = crypto_mac_update(ctx, info, info_len);
125 if (res != TEE_SUCCESS)
126 goto out;
127 res = crypto_mac_update(ctx, &c, 1);
128 if (res != TEE_SUCCESS)
129 goto out;
130 res = crypto_mac_final(ctx, tn, sizeof(tn));
131 if (res != TEE_SUCCESS)
132 goto out;
133
134 memcpy(okm + where, tn, (i < n) ? hash_len : (okm_len - where));
135 where += hash_len;
136 tn_len = hash_len;
137 }
138
139 out:
140 crypto_mac_free_ctx(ctx);
141 return res;
142 }
143
tee_cryp_hkdf(uint32_t hash_id,const uint8_t * ikm,size_t ikm_len,const uint8_t * salt,size_t salt_len,const uint8_t * info,size_t info_len,uint8_t * okm,size_t okm_len)144 TEE_Result tee_cryp_hkdf(uint32_t hash_id, const uint8_t *ikm, size_t ikm_len,
145 const uint8_t *salt, size_t salt_len,
146 const uint8_t *info, size_t info_len, uint8_t *okm,
147 size_t okm_len)
148 {
149 TEE_Result res;
150 uint8_t prk[TEE_MAX_HASH_SIZE];
151 size_t prk_len = sizeof(prk);
152
153 res = hkdf_extract(hash_id, ikm, ikm_len, salt, salt_len, prk,
154 &prk_len);
155 if (res != TEE_SUCCESS)
156 return res;
157 res = hkdf_expand(hash_id, prk, prk_len, info, info_len, okm,
158 okm_len);
159
160 return res;
161 }
162