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