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