1fb7ef469SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2064663e8SJens Wiklander /*
3c34d0d91SJens Wiklander * Copyright (c) 2015-2022, Linaro Limited
4064663e8SJens Wiklander */
5064663e8SJens Wiklander
6064663e8SJens Wiklander #include <crypto/crypto.h>
78a697013SJens Wiklander #include <fault_mitigation.h>
8c34d0d91SJens Wiklander #include <kernel/panic.h>
9c34d0d91SJens Wiklander #include <mempool.h>
10064663e8SJens Wiklander #include <signed_hdr.h>
11064663e8SJens Wiklander #include <stdlib.h>
12064663e8SJens Wiklander #include <string.h>
13064663e8SJens Wiklander #include <ta_pub_key.h>
14064663e8SJens Wiklander #include <tee_api_types.h>
15064663e8SJens Wiklander #include <tee/tee_cryp_utl.h>
16c34d0d91SJens Wiklander #include <tee/uuid.h>
17064663e8SJens Wiklander #include <utee_defines.h>
18062765e4SJerome Forissier #include <util.h>
19064663e8SJens Wiklander
shdr_alloc_and_copy(size_t offs,const void * img,size_t img_size)20ec1aa4faSJens Wiklander struct shdr *shdr_alloc_and_copy(size_t offs, const void *img, size_t img_size)
21064663e8SJens Wiklander {
22064663e8SJens Wiklander size_t shdr_size;
23064663e8SJens Wiklander struct shdr *shdr;
24062765e4SJerome Forissier vaddr_t img_va = (vaddr_t)img;
25062765e4SJerome Forissier vaddr_t tmp = 0;
26ec1aa4faSJens Wiklander size_t end = 0;
27064663e8SJens Wiklander
28ec1aa4faSJens Wiklander if (ADD_OVERFLOW(offs, sizeof(struct shdr), &end) || end > img_size)
294ca9e426SJoakim Bech return NULL;
304ca9e426SJoakim Bech
31ec1aa4faSJens Wiklander shdr_size = SHDR_GET_SIZE((const struct shdr *)(img_va + offs));
326b5d1120SJens Wiklander if (!shdr_size || ADD_OVERFLOW(offs, shdr_size, &end) || end > img_size)
334ca9e426SJoakim Bech return NULL;
34064663e8SJens Wiklander
35062765e4SJerome Forissier if (ADD_OVERFLOW(img_va, shdr_size, &tmp))
36062765e4SJerome Forissier return NULL;
37062765e4SJerome Forissier
38064663e8SJens Wiklander shdr = malloc(shdr_size);
39064663e8SJens Wiklander if (!shdr)
40064663e8SJens Wiklander return NULL;
41ec1aa4faSJens Wiklander memcpy(shdr, (const uint8_t *)img + offs, shdr_size);
42064663e8SJens Wiklander
43064663e8SJens Wiklander /* Check that the data wasn't modified before the copy was completed */
44064663e8SJens Wiklander if (shdr_size != SHDR_GET_SIZE(shdr)) {
45064663e8SJens Wiklander free(shdr);
46064663e8SJens Wiklander return NULL;
47064663e8SJens Wiklander }
48064663e8SJens Wiklander
49064663e8SJens Wiklander return shdr;
50064663e8SJens Wiklander }
51064663e8SJens Wiklander
is_weak_hash_algo(uint32_t algo)52bef7d11dSJens Wiklander static bool is_weak_hash_algo(uint32_t algo)
53bef7d11dSJens Wiklander {
54bef7d11dSJens Wiklander return algo == TEE_ALG_MD5 || algo == TEE_ALG_SHA1 ||
55c5a0587fSJoakim Bech algo == TEE_ALG_MD5SHA1 || algo == TEE_ALG_SHA224;
56bef7d11dSJens Wiklander }
57bef7d11dSJens Wiklander
58*c999bfc6SJoakim Bech /*
59*c999bfc6SJoakim Bech * Checks for key sizes in bits, that are depracted.
60*c999bfc6SJoakim Bech */
is_weak_key_size(uint32_t algo,size_t key_size_bits)61*c999bfc6SJoakim Bech static bool is_weak_key_size(uint32_t algo, size_t key_size_bits)
62*c999bfc6SJoakim Bech {
63*c999bfc6SJoakim Bech if (TEE_ALG_GET_MAIN_ALG(algo) == TEE_MAIN_ALGO_RSA &&
64*c999bfc6SJoakim Bech key_size_bits < 2048)
65*c999bfc6SJoakim Bech return true;
66*c999bfc6SJoakim Bech
67*c999bfc6SJoakim Bech return false;
68*c999bfc6SJoakim Bech }
69*c999bfc6SJoakim Bech
shdr_verify_signature(const struct shdr * shdr)70064663e8SJens Wiklander TEE_Result shdr_verify_signature(const struct shdr *shdr)
71064663e8SJens Wiklander {
72bef7d11dSJens Wiklander struct rsa_public_key key = { };
73bef7d11dSJens Wiklander TEE_Result res = TEE_SUCCESS;
74064663e8SJens Wiklander uint32_t e = TEE_U32_TO_BIG_ENDIAN(ta_pub_key_exponent);
758a697013SJens Wiklander struct ftmn ftmn = { };
768a697013SJens Wiklander unsigned int err_incr = 2;
77bef7d11dSJens Wiklander size_t hash_size = 0;
78bef7d11dSJens Wiklander size_t hash_algo = 0;
79064663e8SJens Wiklander
80064663e8SJens Wiklander if (shdr->magic != SHDR_MAGIC)
818a697013SJens Wiklander goto err;
82064663e8SJens Wiklander
83064663e8SJens Wiklander if (TEE_ALG_GET_MAIN_ALG(shdr->algo) != TEE_MAIN_ALGO_RSA)
848a697013SJens Wiklander goto err;
85064663e8SJens Wiklander
86bef7d11dSJens Wiklander hash_algo = TEE_DIGEST_HASH_TO_ALGO(shdr->algo);
87bef7d11dSJens Wiklander if (is_weak_hash_algo(hash_algo))
888a697013SJens Wiklander goto err;
89bef7d11dSJens Wiklander
90*c999bfc6SJoakim Bech if (is_weak_key_size(shdr->algo, ta_pub_key_modulus_size * 8))
91*c999bfc6SJoakim Bech goto err;
92*c999bfc6SJoakim Bech
93bef7d11dSJens Wiklander res = tee_alg_get_digest_size(hash_algo, &hash_size);
94064663e8SJens Wiklander if (res)
958a697013SJens Wiklander goto err;
96064663e8SJens Wiklander if (hash_size != shdr->hash_size)
978a697013SJens Wiklander goto err;
98064663e8SJens Wiklander
9944c8e3cbSCedric Neveux res = crypto_acipher_alloc_rsa_public_key(&key,
10044c8e3cbSCedric Neveux ta_pub_key_modulus_size * 8);
101064663e8SJens Wiklander if (res)
1028a697013SJens Wiklander goto err;
103064663e8SJens Wiklander
104064663e8SJens Wiklander res = crypto_bignum_bin2bn((uint8_t *)&e, sizeof(e), key.e);
105064663e8SJens Wiklander if (res)
1068a697013SJens Wiklander goto err;
107064663e8SJens Wiklander res = crypto_bignum_bin2bn(ta_pub_key_modulus, ta_pub_key_modulus_size,
108064663e8SJens Wiklander key.n);
109064663e8SJens Wiklander if (res)
1108a697013SJens Wiklander goto err;
111064663e8SJens Wiklander
1128a697013SJens Wiklander FTMN_CALL_FUNC(res, &ftmn, FTMN_INCR0,
1138a697013SJens Wiklander crypto_acipher_rsassa_verify, shdr->algo, &key,
1148a697013SJens Wiklander shdr->hash_size, SHDR_GET_HASH(shdr), shdr->hash_size,
115064663e8SJens Wiklander SHDR_GET_SIG(shdr), shdr->sig_size);
1168a697013SJens Wiklander if (!res) {
1178a697013SJens Wiklander ftmn_checkpoint(&ftmn, FTMN_INCR0);
1188a697013SJens Wiklander goto out;
1198a697013SJens Wiklander }
1208a697013SJens Wiklander err_incr = 1;
1218a697013SJens Wiklander err:
1228a697013SJens Wiklander res = TEE_ERROR_SECURITY;
1238a697013SJens Wiklander FTMN_SET_CHECK_RES_NOT_ZERO(&ftmn, err_incr * FTMN_INCR0, res);
124064663e8SJens Wiklander out:
1258a697013SJens Wiklander FTMN_CALLEE_DONE_CHECK(&ftmn, FTMN_INCR0, FTMN_STEP_COUNT(2), res);
126064663e8SJens Wiklander crypto_acipher_free_rsa_public_key(&key);
1278a697013SJens Wiklander return res;
128064663e8SJens Wiklander }
129c34d0d91SJens Wiklander
130c34d0d91SJens Wiklander static const struct shdr_subkey_attr *
find_attr(const struct shdr_subkey * subkey,uint32_t id)131c34d0d91SJens Wiklander find_attr(const struct shdr_subkey *subkey, uint32_t id)
132c34d0d91SJens Wiklander {
133c34d0d91SJens Wiklander size_t n = 0;
134c34d0d91SJens Wiklander
135c34d0d91SJens Wiklander for (n = 0; n < subkey->attr_count; n++)
136c34d0d91SJens Wiklander if (subkey->attrs[n].id == id)
137c34d0d91SJens Wiklander return subkey->attrs + n;
138c34d0d91SJens Wiklander
139c34d0d91SJens Wiklander return NULL;
140c34d0d91SJens Wiklander }
141c34d0d91SJens Wiklander
load_rsa_key(const struct shdr_subkey * subkey,struct rsa_public_key ** key_pp)142c34d0d91SJens Wiklander static TEE_Result load_rsa_key(const struct shdr_subkey *subkey,
143c34d0d91SJens Wiklander struct rsa_public_key **key_pp)
144c34d0d91SJens Wiklander {
145c34d0d91SJens Wiklander const uint8_t *base = (const uint8_t *)subkey;
146c34d0d91SJens Wiklander const struct shdr_subkey_attr *pub_exp = NULL;
147c34d0d91SJens Wiklander const struct shdr_subkey_attr *modulus = NULL;
148c34d0d91SJens Wiklander struct rsa_public_key *key = NULL;
149c34d0d91SJens Wiklander TEE_Result res = TEE_SUCCESS;
150c34d0d91SJens Wiklander
151c34d0d91SJens Wiklander pub_exp = find_attr(subkey, TEE_ATTR_RSA_PUBLIC_EXPONENT);
152c34d0d91SJens Wiklander if (!pub_exp)
153c34d0d91SJens Wiklander return TEE_ERROR_SECURITY;
154c34d0d91SJens Wiklander modulus = find_attr(subkey, TEE_ATTR_RSA_MODULUS);
155c34d0d91SJens Wiklander if (!modulus)
156c34d0d91SJens Wiklander return TEE_ERROR_SECURITY;
157c34d0d91SJens Wiklander
158c34d0d91SJens Wiklander key = calloc(1, sizeof(*key));
159c34d0d91SJens Wiklander if (!key)
160c34d0d91SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY;
161c34d0d91SJens Wiklander res = crypto_acipher_alloc_rsa_public_key(key, modulus->size * 8);
162c34d0d91SJens Wiklander if (res)
163c34d0d91SJens Wiklander goto err_key;
164c34d0d91SJens Wiklander
165c34d0d91SJens Wiklander res = crypto_bignum_bin2bn(base + pub_exp->offs, pub_exp->size, key->e);
166c34d0d91SJens Wiklander if (res)
167c34d0d91SJens Wiklander goto err;
168c34d0d91SJens Wiklander res = crypto_bignum_bin2bn(base + modulus->offs, modulus->size, key->n);
169c34d0d91SJens Wiklander if (res)
170c34d0d91SJens Wiklander goto err;
171c34d0d91SJens Wiklander
172c34d0d91SJens Wiklander *key_pp = key;
173c34d0d91SJens Wiklander return TEE_SUCCESS;
174c34d0d91SJens Wiklander err:
175c34d0d91SJens Wiklander crypto_acipher_free_rsa_public_key(key);
176c34d0d91SJens Wiklander err_key:
177c34d0d91SJens Wiklander free(key);
178c34d0d91SJens Wiklander return TEE_ERROR_SECURITY;
179c34d0d91SJens Wiklander }
180c34d0d91SJens Wiklander
check_attrs(const struct shdr_subkey * subkey,size_t img_size)181c34d0d91SJens Wiklander static TEE_Result check_attrs(const struct shdr_subkey *subkey, size_t img_size)
182c34d0d91SJens Wiklander {
183c34d0d91SJens Wiklander const struct shdr_subkey_attr *attrs = subkey->attrs;
184c34d0d91SJens Wiklander size_t end = 0;
185c34d0d91SJens Wiklander size_t n = 0;
186c34d0d91SJens Wiklander
187c34d0d91SJens Wiklander if (MUL_OVERFLOW(subkey->attr_count, sizeof(*attrs), &end) ||
188c34d0d91SJens Wiklander ADD_OVERFLOW(end, sizeof(*subkey), &end) ||
189c34d0d91SJens Wiklander end > img_size)
190c34d0d91SJens Wiklander return TEE_ERROR_SECURITY;
191c34d0d91SJens Wiklander
192c34d0d91SJens Wiklander for (n = 0; n < subkey->attr_count; n++)
193c34d0d91SJens Wiklander if (ADD_OVERFLOW(attrs[n].offs, attrs[n].size, &end) ||
194c34d0d91SJens Wiklander end > img_size)
195c34d0d91SJens Wiklander return TEE_ERROR_SECURITY;
196c34d0d91SJens Wiklander
197c34d0d91SJens Wiklander return TEE_SUCCESS;
198c34d0d91SJens Wiklander }
199c34d0d91SJens Wiklander
calc_next_uuid(uint8_t uuid[sizeof (TEE_UUID)],const uint8_t my_uuid[sizeof (TEE_UUID)],const void * ns_name,size_t name_size)200c34d0d91SJens Wiklander static TEE_Result calc_next_uuid(uint8_t uuid[sizeof(TEE_UUID)],
201c34d0d91SJens Wiklander const uint8_t my_uuid[sizeof(TEE_UUID)],
202c34d0d91SJens Wiklander const void *ns_name, size_t name_size)
203c34d0d91SJens Wiklander {
204c34d0d91SJens Wiklander TEE_Result res = TEE_ERROR_SECURITY;
205c34d0d91SJens Wiklander void *ctx = NULL;
206c34d0d91SJens Wiklander struct {
207c34d0d91SJens Wiklander uint8_t digest[TEE_SHA1_HASH_SIZE];
208c34d0d91SJens Wiklander TEE_UUID uuid;
209c34d0d91SJens Wiklander char name_str[];
210c34d0d91SJens Wiklander } *tmp = NULL;
211c34d0d91SJens Wiklander
212c34d0d91SJens Wiklander if (!name_size) {
213c34d0d91SJens Wiklander memcpy(uuid, my_uuid, sizeof(TEE_UUID));
214c34d0d91SJens Wiklander return TEE_SUCCESS;
215c34d0d91SJens Wiklander }
216c34d0d91SJens Wiklander
217c34d0d91SJens Wiklander /*
218c34d0d91SJens Wiklander * RFC 4122 requires a SHA-1 digest for UUID v5. Use SHA-512
219c34d0d91SJens Wiklander * instead for better collision resistance.
220c34d0d91SJens Wiklander */
221c34d0d91SJens Wiklander if (crypto_hash_alloc_ctx(&ctx, TEE_ALG_SHA512))
222c34d0d91SJens Wiklander return TEE_ERROR_SECURITY;
223c34d0d91SJens Wiklander
224c34d0d91SJens Wiklander tmp = mempool_alloc(mempool_default, sizeof(*tmp) + name_size);
225c34d0d91SJens Wiklander if (!tmp)
226c34d0d91SJens Wiklander goto out_ctx;
227c34d0d91SJens Wiklander memcpy(tmp->name_str, ns_name, name_size);
228c34d0d91SJens Wiklander
229c34d0d91SJens Wiklander if (crypto_hash_init(ctx) ||
230c34d0d91SJens Wiklander crypto_hash_update(ctx, my_uuid, sizeof(TEE_UUID)) ||
231c34d0d91SJens Wiklander crypto_hash_update(ctx, (const void *)tmp->name_str,
232c34d0d91SJens Wiklander strnlen(tmp->name_str, name_size)) ||
233c34d0d91SJens Wiklander crypto_hash_final(ctx, tmp->digest, sizeof(tmp->digest)))
234c34d0d91SJens Wiklander goto out_mempool;
235c34d0d91SJens Wiklander
236c34d0d91SJens Wiklander tee_uuid_from_octets(&tmp->uuid, tmp->digest);
237c34d0d91SJens Wiklander /*
238c34d0d91SJens Wiklander * Set the four most significant bits (bits 12 through 15) of the
239c34d0d91SJens Wiklander * time_hi_and_version field to 5.
240c34d0d91SJens Wiklander */
241c34d0d91SJens Wiklander tmp->uuid.timeHiAndVersion &= ~SHIFT_U32(0xf, 12);
242c34d0d91SJens Wiklander tmp->uuid.timeHiAndVersion |= SHIFT_U32(5, 12);
243c34d0d91SJens Wiklander /*
244c34d0d91SJens Wiklander * Set the two most significant bits (bits 6 and 7) of the
245c34d0d91SJens Wiklander * clock_seq_hi_and_reserved to zero and one, respectively.
246c34d0d91SJens Wiklander */
247c34d0d91SJens Wiklander tmp->uuid.clockSeqAndNode[0] &= ~BIT(6);
248c34d0d91SJens Wiklander tmp->uuid.clockSeqAndNode[0] |= BIT(7);
249c34d0d91SJens Wiklander
250c34d0d91SJens Wiklander tee_uuid_to_octets(uuid, &tmp->uuid);
251c34d0d91SJens Wiklander res = TEE_SUCCESS;
252c34d0d91SJens Wiklander
253c34d0d91SJens Wiklander out_mempool:
254c34d0d91SJens Wiklander mempool_free(mempool_default, tmp);
255c34d0d91SJens Wiklander out_ctx:
256c34d0d91SJens Wiklander crypto_hash_free_ctx(ctx);
257c34d0d91SJens Wiklander
258c34d0d91SJens Wiklander return res;
259c34d0d91SJens Wiklander }
260c34d0d91SJens Wiklander
shdr_load_pub_key(const struct shdr * shdr,size_t offs,const uint8_t * ns_img,size_t ns_img_size,const uint8_t next_uuid[sizeof (TEE_UUID)],uint32_t max_depth,struct shdr_pub_key * key)261c34d0d91SJens Wiklander TEE_Result shdr_load_pub_key(const struct shdr *shdr, size_t offs,
262c34d0d91SJens Wiklander const uint8_t *ns_img, size_t ns_img_size,
263c34d0d91SJens Wiklander const uint8_t next_uuid[sizeof(TEE_UUID)],
264c34d0d91SJens Wiklander uint32_t max_depth, struct shdr_pub_key *key)
265c34d0d91SJens Wiklander {
266c34d0d91SJens Wiklander struct shdr_subkey *subkey = NULL;
267c34d0d91SJens Wiklander TEE_Result res = TEE_SUCCESS;
268c34d0d91SJens Wiklander void *digest = NULL;
269c34d0d91SJens Wiklander uint8_t *img = NULL;
270c34d0d91SJens Wiklander void *ctx = NULL;
271c34d0d91SJens Wiklander size_t end = 0;
272c34d0d91SJens Wiklander
273c34d0d91SJens Wiklander if (shdr->img_type != SHDR_SUBKEY)
274c34d0d91SJens Wiklander return TEE_ERROR_SECURITY;
275c34d0d91SJens Wiklander
276c34d0d91SJens Wiklander if (shdr->img_size < sizeof(*subkey))
277c34d0d91SJens Wiklander return TEE_ERROR_SECURITY;
278c34d0d91SJens Wiklander
279c34d0d91SJens Wiklander if (ADD_OVERFLOW(shdr->img_size, offs, &end) || end > ns_img_size)
280c34d0d91SJens Wiklander return TEE_ERROR_SECURITY;
281c34d0d91SJens Wiklander
282c34d0d91SJens Wiklander img = mempool_alloc(mempool_default, shdr->img_size + shdr->hash_size);
283c34d0d91SJens Wiklander if (!img)
284c34d0d91SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY;
285c34d0d91SJens Wiklander memcpy(img + shdr->hash_size, ns_img + offs, shdr->img_size);
286c34d0d91SJens Wiklander subkey = (void *)(img + shdr->hash_size);
287c34d0d91SJens Wiklander digest = img;
288c34d0d91SJens Wiklander
289c34d0d91SJens Wiklander if (crypto_hash_alloc_ctx(&ctx, TEE_DIGEST_HASH_TO_ALGO(shdr->algo))) {
290c34d0d91SJens Wiklander res = TEE_ERROR_SECURITY;
291c34d0d91SJens Wiklander goto out_mempool;
292c34d0d91SJens Wiklander }
293c34d0d91SJens Wiklander
294c34d0d91SJens Wiklander if (crypto_hash_init(ctx) ||
295c34d0d91SJens Wiklander crypto_hash_update(ctx, (const void *)shdr, sizeof(*shdr)) ||
296c34d0d91SJens Wiklander crypto_hash_update(ctx, (const void *)subkey, shdr->img_size) ||
297c34d0d91SJens Wiklander crypto_hash_final(ctx, digest, shdr->hash_size) ||
298c34d0d91SJens Wiklander memcmp(digest, SHDR_GET_HASH(shdr), shdr->hash_size)) {
299c34d0d91SJens Wiklander res = TEE_ERROR_SECURITY;
300c34d0d91SJens Wiklander goto out_ctx;
301c34d0d91SJens Wiklander }
302c34d0d91SJens Wiklander
303c34d0d91SJens Wiklander res = check_attrs(subkey, shdr->img_size);
304c34d0d91SJens Wiklander if (res)
305c34d0d91SJens Wiklander goto out_ctx;
306c34d0d91SJens Wiklander
307c34d0d91SJens Wiklander if (subkey->max_depth >= max_depth) {
308c34d0d91SJens Wiklander res = TEE_ERROR_SECURITY;
309c34d0d91SJens Wiklander goto out_ctx;
310c34d0d91SJens Wiklander }
311c34d0d91SJens Wiklander if (next_uuid && memcmp(next_uuid, subkey->uuid, sizeof(TEE_UUID))) {
312c34d0d91SJens Wiklander res = TEE_ERROR_SECURITY;
313c34d0d91SJens Wiklander goto out_ctx;
314c34d0d91SJens Wiklander }
315c34d0d91SJens Wiklander
316c34d0d91SJens Wiklander key->max_depth = subkey->max_depth;
317c34d0d91SJens Wiklander key->name_size = subkey->name_size;
318c34d0d91SJens Wiklander memcpy(key->uuid, subkey->uuid, sizeof(TEE_UUID));
319c34d0d91SJens Wiklander if (ADD_OVERFLOW(key->name_size, offs + shdr->img_size, &end) ||
320c34d0d91SJens Wiklander end > ns_img_size) {
321c34d0d91SJens Wiklander res = TEE_ERROR_SECURITY;
322c34d0d91SJens Wiklander goto out_ctx;
323c34d0d91SJens Wiklander }
324c34d0d91SJens Wiklander res = calc_next_uuid(key->next_uuid, key->uuid,
325c34d0d91SJens Wiklander ns_img + offs + shdr->img_size, key->name_size);
326c34d0d91SJens Wiklander if (res)
327c34d0d91SJens Wiklander goto out_ctx;
328c34d0d91SJens Wiklander
329c34d0d91SJens Wiklander key->main_algo = TEE_ALG_GET_MAIN_ALG(subkey->algo);
330c34d0d91SJens Wiklander switch (key->main_algo) {
331c34d0d91SJens Wiklander case TEE_MAIN_ALGO_RSA:
332c34d0d91SJens Wiklander res = load_rsa_key(subkey, &key->pub_key.rsa);
333c34d0d91SJens Wiklander break;
334c34d0d91SJens Wiklander default:
335c34d0d91SJens Wiklander res = TEE_ERROR_SECURITY;
336c34d0d91SJens Wiklander break;
337c34d0d91SJens Wiklander }
338c34d0d91SJens Wiklander
339c34d0d91SJens Wiklander out_ctx:
340c34d0d91SJens Wiklander crypto_hash_free_ctx(ctx);
341c34d0d91SJens Wiklander out_mempool:
342c34d0d91SJens Wiklander mempool_free(mempool_default, img);
343c34d0d91SJens Wiklander return res;
344c34d0d91SJens Wiklander }
345c34d0d91SJens Wiklander
shdr_free_pub_key(struct shdr_pub_key * key)346c34d0d91SJens Wiklander void shdr_free_pub_key(struct shdr_pub_key *key)
347c34d0d91SJens Wiklander {
348c34d0d91SJens Wiklander if (key) {
349c34d0d91SJens Wiklander switch (key->main_algo) {
350c34d0d91SJens Wiklander case TEE_MAIN_ALGO_RSA:
351c34d0d91SJens Wiklander crypto_acipher_free_rsa_public_key(key->pub_key.rsa);
352c34d0d91SJens Wiklander free(key->pub_key.rsa);
353c34d0d91SJens Wiklander break;
354c34d0d91SJens Wiklander default:
355c34d0d91SJens Wiklander panic();
356c34d0d91SJens Wiklander }
357c34d0d91SJens Wiklander }
358c34d0d91SJens Wiklander }
359c34d0d91SJens Wiklander
shdr_verify_signature2(struct shdr_pub_key * key,const struct shdr * shdr)360c34d0d91SJens Wiklander TEE_Result shdr_verify_signature2(struct shdr_pub_key *key,
361c34d0d91SJens Wiklander const struct shdr *shdr)
362c34d0d91SJens Wiklander {
3638a697013SJens Wiklander TEE_Result res = TEE_SUCCESS;
3648a697013SJens Wiklander unsigned int err_incr = 2;
3658a697013SJens Wiklander struct ftmn ftmn = { };
366c34d0d91SJens Wiklander size_t hash_size = 0;
367bef7d11dSJens Wiklander size_t hash_algo = 0;
368c34d0d91SJens Wiklander
369c34d0d91SJens Wiklander if (shdr->magic != SHDR_MAGIC)
3708a697013SJens Wiklander goto err;
371c34d0d91SJens Wiklander
372c34d0d91SJens Wiklander if (TEE_ALG_GET_MAIN_ALG(shdr->algo) != key->main_algo)
3738a697013SJens Wiklander goto err;
374c34d0d91SJens Wiklander
375bef7d11dSJens Wiklander hash_algo = TEE_DIGEST_HASH_TO_ALGO(shdr->algo);
376bef7d11dSJens Wiklander if (is_weak_hash_algo(hash_algo))
3778a697013SJens Wiklander goto err;
378bef7d11dSJens Wiklander
379*c999bfc6SJoakim Bech if (is_weak_key_size(shdr->algo, ta_pub_key_modulus_size * 8))
380*c999bfc6SJoakim Bech goto err;
381*c999bfc6SJoakim Bech
382bef7d11dSJens Wiklander if (tee_alg_get_digest_size(hash_algo, &hash_size) ||
383c34d0d91SJens Wiklander hash_size != shdr->hash_size)
3848a697013SJens Wiklander goto err;
385c34d0d91SJens Wiklander
386c34d0d91SJens Wiklander switch (key->main_algo) {
387c34d0d91SJens Wiklander case TEE_MAIN_ALGO_RSA:
3888a697013SJens Wiklander FTMN_CALL_FUNC(res, &ftmn, FTMN_INCR0,
3898a697013SJens Wiklander crypto_acipher_rsassa_verify, shdr->algo,
3908a697013SJens Wiklander key->pub_key.rsa, shdr->hash_size,
3918a697013SJens Wiklander SHDR_GET_HASH(shdr), shdr->hash_size,
3928a697013SJens Wiklander SHDR_GET_SIG(shdr), shdr->sig_size);
393c34d0d91SJens Wiklander break;
394c34d0d91SJens Wiklander default:
395c34d0d91SJens Wiklander panic();
396c34d0d91SJens Wiklander }
397c34d0d91SJens Wiklander
3988a697013SJens Wiklander if (!res) {
3998a697013SJens Wiklander ftmn_checkpoint(&ftmn, FTMN_INCR0);
4008a697013SJens Wiklander goto out;
4018a697013SJens Wiklander }
4028a697013SJens Wiklander err_incr = 1;
4038a697013SJens Wiklander err:
4048a697013SJens Wiklander res = TEE_ERROR_SECURITY;
4058a697013SJens Wiklander FTMN_SET_CHECK_RES_NOT_ZERO(&ftmn, err_incr * FTMN_INCR0, res);
4068a697013SJens Wiklander out:
4078a697013SJens Wiklander FTMN_CALLEE_DONE_CHECK(&ftmn, FTMN_INCR0, FTMN_STEP_COUNT(2), res);
4088a697013SJens Wiklander return res;
409c34d0d91SJens Wiklander }
410