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