blob: 64778e8da1edc02837307b58d9d05450795b269e [file] [log] [blame]
Manish V Badarkhe8fbea622023-09-06 10:22:19 +01001/*
2 * Copyright (c) 2023, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
8#include <stddef.h>
9#include <string.h>
10
11/* mbed TLS headers */
12#include <mbedtls/gcm.h>
13#include <mbedtls/md.h>
14#include <mbedtls/memory_buffer_alloc.h>
15#include <mbedtls/oid.h>
16#include <mbedtls/platform.h>
17#include <mbedtls/version.h>
18#include <mbedtls/x509.h>
Manish V Badarkhef179aa92023-09-06 11:01:37 +010019#include <psa/crypto.h>
20#include <psa/crypto_platform.h>
21#include <psa/crypto_types.h>
22#include <psa/crypto_values.h>
Manish V Badarkhe8fbea622023-09-06 10:22:19 +010023
24#include <common/debug.h>
25#include <drivers/auth/crypto_mod.h>
26#include <drivers/auth/mbedtls/mbedtls_common.h>
Manish V Badarkhe8fbea622023-09-06 10:22:19 +010027#include <plat/common/platform.h>
28
29#define LIB_NAME "mbed TLS PSA"
30
31#if CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
32CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
33/*
34 * CRYPTO_MD_MAX_SIZE value is as per current stronger algorithm available
35 * so make sure that mbed TLS MD maximum size must be lesser than this.
36 */
37CASSERT(CRYPTO_MD_MAX_SIZE >= MBEDTLS_MD_MAX_SIZE,
38 assert_mbedtls_md_size_overflow);
39
40#endif /*
41 * CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
42 * CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
43 */
44
45/*
46 * AlgorithmIdentifier ::= SEQUENCE {
47 * algorithm OBJECT IDENTIFIER,
48 * parameters ANY DEFINED BY algorithm OPTIONAL
49 * }
50 *
51 * SubjectPublicKeyInfo ::= SEQUENCE {
52 * algorithm AlgorithmIdentifier,
53 * subjectPublicKey BIT STRING
54 * }
55 *
56 * DigestInfo ::= SEQUENCE {
57 * digestAlgorithm AlgorithmIdentifier,
58 * digest OCTET STRING
59 * }
60 */
Manish V Badarkhef179aa92023-09-06 11:01:37 +010061
62/*
63 * We pretend using an external RNG (through MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
64 * mbedTLS config option) so we need to provide an implementation of
65 * mbedtls_psa_external_get_random(). Provide a fake one, since we do not
66 * actually have any external RNG and TF-A itself doesn't engage in
67 * cryptographic operations that demands randomness.
68 */
69psa_status_t mbedtls_psa_external_get_random(
70 mbedtls_psa_external_random_context_t *context,
71 uint8_t *output, size_t output_size,
72 size_t *output_length)
73{
74 return PSA_ERROR_INSUFFICIENT_ENTROPY;
75}
Manish V Badarkhe8fbea622023-09-06 10:22:19 +010076
77/*
78 * Initialize the library and export the descriptor
79 */
80static void init(void)
81{
82 /* Initialize mbed TLS */
83 mbedtls_init();
Manish V Badarkhef179aa92023-09-06 11:01:37 +010084
85 /* Initialise PSA mbedTLS */
86 psa_status_t status = psa_crypto_init();
87
88 if (status != PSA_SUCCESS) {
89 ERROR("Failed to initialize %s crypto (%d).\n", LIB_NAME, status);
90 panic();
91 }
92
93 INFO("PSA crypto initialized successfully!\n");
Manish V Badarkhe8fbea622023-09-06 10:22:19 +010094}
95
96#if CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
97CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
98/*
99 * Verify a signature.
100 *
101 * Parameters are passed using the DER encoding format following the ASN.1
102 * structures detailed above.
103 */
104static int verify_signature(void *data_ptr, unsigned int data_len,
105 void *sig_ptr, unsigned int sig_len,
106 void *sig_alg, unsigned int sig_alg_len,
107 void *pk_ptr, unsigned int pk_len)
108{
109 mbedtls_asn1_buf sig_oid, sig_params;
110 mbedtls_asn1_buf signature;
111 mbedtls_md_type_t md_alg;
112 mbedtls_pk_type_t pk_alg;
113 mbedtls_pk_context pk = {0};
114 int rc;
115 void *sig_opts = NULL;
116 const mbedtls_md_info_t *md_info;
117 unsigned char *p, *end;
118 unsigned char hash[MBEDTLS_MD_MAX_SIZE];
119
120 /* Get pointers to signature OID and parameters */
121 p = (unsigned char *)sig_alg;
122 end = (unsigned char *)(p + sig_alg_len);
123 rc = mbedtls_asn1_get_alg(&p, end, &sig_oid, &sig_params);
124 if (rc != 0) {
125 return CRYPTO_ERR_SIGNATURE;
126 }
127
128 /* Get the actual signature algorithm (MD + PK) */
129 rc = mbedtls_x509_get_sig_alg(&sig_oid, &sig_params, &md_alg, &pk_alg, &sig_opts);
130 if (rc != 0) {
131 return CRYPTO_ERR_SIGNATURE;
132 }
133
134 /* Parse the public key */
135 mbedtls_pk_init(&pk);
136 p = (unsigned char *)pk_ptr;
137 end = (unsigned char *)(p + pk_len);
138 rc = mbedtls_pk_parse_subpubkey(&p, end, &pk);
139 if (rc != 0) {
140 rc = CRYPTO_ERR_SIGNATURE;
141 goto end2;
142 }
143
144 /* Get the signature (bitstring) */
145 p = (unsigned char *)sig_ptr;
146 end = (unsigned char *)(p + sig_len);
147 signature.tag = *p;
148 rc = mbedtls_asn1_get_bitstring_null(&p, end, &signature.len);
149 if ((rc != 0) || ((size_t)(end - p) != signature.len)) {
150 rc = CRYPTO_ERR_SIGNATURE;
151 goto end1;
152 }
153 signature.p = p;
154
155 /* Calculate the hash of the data */
156 md_info = mbedtls_md_info_from_type(md_alg);
157 if (md_info == NULL) {
158 rc = CRYPTO_ERR_SIGNATURE;
159 goto end1;
160 }
161 p = (unsigned char *)data_ptr;
162 rc = mbedtls_md(md_info, p, data_len, hash);
163 if (rc != 0) {
164 rc = CRYPTO_ERR_SIGNATURE;
165 goto end1;
166 }
167
168 /* Verify the signature */
169 rc = mbedtls_pk_verify_ext(pk_alg, sig_opts, &pk, md_alg, hash,
170 mbedtls_md_get_size(md_info),
171 signature.p, signature.len);
172 if (rc != 0) {
173 rc = CRYPTO_ERR_SIGNATURE;
174 goto end1;
175 }
176
177 /* Signature verification success */
178 rc = CRYPTO_SUCCESS;
179
180end1:
181 mbedtls_pk_free(&pk);
182end2:
183 mbedtls_free(sig_opts);
184 return rc;
185}
186
187/*
188 * Match a hash
189 *
190 * Digest info is passed in DER format following the ASN.1 structure detailed
191 * above.
192 */
193static int verify_hash(void *data_ptr, unsigned int data_len,
194 void *digest_info_ptr, unsigned int digest_info_len)
195{
196 mbedtls_asn1_buf hash_oid, params;
197 mbedtls_md_type_t md_alg;
198 const mbedtls_md_info_t *md_info;
199 unsigned char *p, *end, *hash;
200 unsigned char data_hash[MBEDTLS_MD_MAX_SIZE];
201 size_t len;
202 int rc;
203
204 /*
205 * Digest info should be an MBEDTLS_ASN1_SEQUENCE, but padding after
206 * it is allowed. This is necessary to support multiple hash
207 * algorithms.
208 */
209 p = (unsigned char *)digest_info_ptr;
210 end = p + digest_info_len;
211 rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
212 MBEDTLS_ASN1_SEQUENCE);
213 if (rc != 0) {
214 return CRYPTO_ERR_HASH;
215 }
216
217 end = p + len;
218
219 /* Get the hash algorithm */
220 rc = mbedtls_asn1_get_alg(&p, end, &hash_oid, &params);
221 if (rc != 0) {
222 return CRYPTO_ERR_HASH;
223 }
224
225 rc = mbedtls_oid_get_md_alg(&hash_oid, &md_alg);
226 if (rc != 0) {
227 return CRYPTO_ERR_HASH;
228 }
229
230 md_info = mbedtls_md_info_from_type(md_alg);
231 if (md_info == NULL) {
232 return CRYPTO_ERR_HASH;
233 }
234
235 /* Hash should be octet string type and consume all bytes */
236 rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING);
237 if ((rc != 0) || ((size_t)(end - p) != len)) {
238 return CRYPTO_ERR_HASH;
239 }
240
241 /* Length of hash must match the algorithm's size */
242 if (len != mbedtls_md_get_size(md_info)) {
243 return CRYPTO_ERR_HASH;
244 }
245 hash = p;
246
247 /* Calculate the hash of the data */
248 p = (unsigned char *)data_ptr;
249 rc = mbedtls_md(md_info, p, data_len, data_hash);
250 if (rc != 0) {
251 return CRYPTO_ERR_HASH;
252 }
253
254 /* Compare values */
255 rc = memcmp(data_hash, hash, mbedtls_md_get_size(md_info));
256 if (rc != 0) {
257 return CRYPTO_ERR_HASH;
258 }
259
260 return CRYPTO_SUCCESS;
261}
262#endif /*
263 * CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
264 * CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
265 */
266
267#if CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
268CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
269/*
270 * Map a generic crypto message digest algorithm to the corresponding macro used
271 * by Mbed TLS.
272 */
273static inline mbedtls_md_type_t md_type(enum crypto_md_algo algo)
274{
275 switch (algo) {
276 case CRYPTO_MD_SHA512:
277 return MBEDTLS_MD_SHA512;
278 case CRYPTO_MD_SHA384:
279 return MBEDTLS_MD_SHA384;
280 case CRYPTO_MD_SHA256:
281 return MBEDTLS_MD_SHA256;
282 default:
283 /* Invalid hash algorithm. */
284 return MBEDTLS_MD_NONE;
285 }
286}
287
288/*
289 * Calculate a hash
290 *
291 * output points to the computed hash
292 */
293static int calc_hash(enum crypto_md_algo md_algo, void *data_ptr,
294 unsigned int data_len,
295 unsigned char output[CRYPTO_MD_MAX_SIZE])
296{
297 const mbedtls_md_info_t *md_info;
298
299 md_info = mbedtls_md_info_from_type(md_type(md_algo));
300 if (md_info == NULL) {
301 return CRYPTO_ERR_HASH;
302 }
303
304 /*
305 * Calculate the hash of the data, it is safe to pass the
306 * 'output' hash buffer pointer considering its size is always
307 * bigger than or equal to MBEDTLS_MD_MAX_SIZE.
308 */
309 return mbedtls_md(md_info, data_ptr, data_len, output);
310}
311#endif /*
312 * CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
313 * CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
314 */
315
316#if TF_MBEDTLS_USE_AES_GCM
317/*
318 * Stack based buffer allocation for decryption operation. It could
319 * be configured to balance stack usage vs execution speed.
320 */
321#define DEC_OP_BUF_SIZE 128
322
323static int aes_gcm_decrypt(void *data_ptr, size_t len, const void *key,
324 unsigned int key_len, const void *iv,
325 unsigned int iv_len, const void *tag,
326 unsigned int tag_len)
327{
328 mbedtls_gcm_context ctx;
329 mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES;
330 unsigned char buf[DEC_OP_BUF_SIZE];
331 unsigned char tag_buf[CRYPTO_MAX_TAG_SIZE];
332 unsigned char *pt = data_ptr;
333 size_t dec_len;
334 int diff, i, rc;
335 size_t output_length __unused;
336
337 mbedtls_gcm_init(&ctx);
338
339 rc = mbedtls_gcm_setkey(&ctx, cipher, key, key_len * 8);
340 if (rc != 0) {
341 rc = CRYPTO_ERR_DECRYPTION;
342 goto exit_gcm;
343 }
344
345#if (MBEDTLS_VERSION_MAJOR < 3)
346 rc = mbedtls_gcm_starts(&ctx, MBEDTLS_GCM_DECRYPT, iv, iv_len, NULL, 0);
347#else
348 rc = mbedtls_gcm_starts(&ctx, MBEDTLS_GCM_DECRYPT, iv, iv_len);
349#endif
350 if (rc != 0) {
351 rc = CRYPTO_ERR_DECRYPTION;
352 goto exit_gcm;
353 }
354
355 while (len > 0) {
356 dec_len = MIN(sizeof(buf), len);
357
358#if (MBEDTLS_VERSION_MAJOR < 3)
359 rc = mbedtls_gcm_update(&ctx, dec_len, pt, buf);
360#else
361 rc = mbedtls_gcm_update(&ctx, pt, dec_len, buf, sizeof(buf), &output_length);
362#endif
363
364 if (rc != 0) {
365 rc = CRYPTO_ERR_DECRYPTION;
366 goto exit_gcm;
367 }
368
369 memcpy(pt, buf, dec_len);
370 pt += dec_len;
371 len -= dec_len;
372 }
373
374#if (MBEDTLS_VERSION_MAJOR < 3)
375 rc = mbedtls_gcm_finish(&ctx, tag_buf, sizeof(tag_buf));
376#else
377 rc = mbedtls_gcm_finish(&ctx, NULL, 0, &output_length, tag_buf, sizeof(tag_buf));
378#endif
379
380 if (rc != 0) {
381 rc = CRYPTO_ERR_DECRYPTION;
382 goto exit_gcm;
383 }
384
385 /* Check tag in "constant-time" */
386 for (diff = 0, i = 0; i < tag_len; i++)
387 diff |= ((const unsigned char *)tag)[i] ^ tag_buf[i];
388
389 if (diff != 0) {
390 rc = CRYPTO_ERR_DECRYPTION;
391 goto exit_gcm;
392 }
393
394 /* GCM decryption success */
395 rc = CRYPTO_SUCCESS;
396
397exit_gcm:
398 mbedtls_gcm_free(&ctx);
399 return rc;
400}
401
402/*
403 * Authenticated decryption of an image
404 */
405static int auth_decrypt(enum crypto_dec_algo dec_algo, void *data_ptr,
406 size_t len, const void *key, unsigned int key_len,
407 unsigned int key_flags, const void *iv,
408 unsigned int iv_len, const void *tag,
409 unsigned int tag_len)
410{
411 int rc;
412
413 assert((key_flags & ENC_KEY_IS_IDENTIFIER) == 0);
414
415 switch (dec_algo) {
416 case CRYPTO_GCM_DECRYPT:
417 rc = aes_gcm_decrypt(data_ptr, len, key, key_len, iv, iv_len,
418 tag, tag_len);
419 if (rc != 0)
420 return rc;
421 break;
422 default:
423 return CRYPTO_ERR_DECRYPTION;
424 }
425
426 return CRYPTO_SUCCESS;
427}
428#endif /* TF_MBEDTLS_USE_AES_GCM */
429
430/*
431 * Register crypto library descriptor
432 */
433#if CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
434#if TF_MBEDTLS_USE_AES_GCM
435REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, calc_hash,
436 auth_decrypt, NULL);
437#else
438REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, calc_hash,
439 NULL, NULL);
440#endif
441#elif CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY
442#if TF_MBEDTLS_USE_AES_GCM
443REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, NULL,
444 auth_decrypt, NULL);
445#else
446REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, NULL,
447 NULL, NULL);
448#endif
449#elif CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY
450REGISTER_CRYPTO_LIB(LIB_NAME, init, NULL, NULL, calc_hash, NULL, NULL);
451#endif /* CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */