blob: 25a98da8e59d332218a2156872b6c66dbf890b7a [file] [log] [blame]
Louis Mayencourt7a36f782018-09-24 14:00:57 +01001/*
2 * Copyright (c) 2019, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8#include "secure_fw/core/secure_utilities.h"
9#include "tfm_crypto_defs.h"
10
11#include "psa_crypto.h"
12
13#include "tfm_crypto_struct.h"
14
15#include "tfm_crypto_api.h"
16#include "crypto_utils.h"
17
18static void mac_zeroize(void *data, size_t size)
19{
20 tfm_memset(data, 0, size);
21}
22
23static size_t get_hash_block_size(psa_algorithm_t alg)
24{
25 switch (alg) {
26 case PSA_ALG_MD2:
27 return 16;
28 case PSA_ALG_MD4:
29 return 64;
30 case PSA_ALG_MD5:
31 return 64;
32 case PSA_ALG_RIPEMD160:
33 return 64;
34 case PSA_ALG_SHA_1:
35 return 64;
36 case PSA_ALG_SHA_224:
37 return 64;
38 case PSA_ALG_SHA_256:
39 return 64;
40 case PSA_ALG_SHA_384:
41 return 128;
42 case PSA_ALG_SHA_512:
43 return 128;
44 default:
45 return 0;
46 }
47}
48
49static enum tfm_crypto_err_t tfm_crypto_hmac_setup(
50 struct tfm_mac_operation_s *ctx,
51 psa_key_slot_t key,
52 psa_algorithm_t alg)
53{
54 enum tfm_crypto_err_t err;
55 psa_key_type_t key_type;
56 size_t key_size;
57 uint8_t key_data[TFM_CRYPTO_MAX_KEY_LENGTH];
58 uint8_t hashed_key[PSA_HMAC_MAX_HASH_BLOCK_SIZE];
59 size_t block_size;
60 uint8_t ipad[PSA_HMAC_MAX_HASH_BLOCK_SIZE];
61 uint8_t *opad = ctx->ctx.hmac.opad;
62 size_t i;
Jamie Foxefd82732018-11-26 10:34:32 +000063 psa_key_usage_t usage;
Louis Mayencourt7a36f782018-09-24 14:00:57 +010064
65 /* Check provided key */
66 err = tfm_crypto_get_key_information(key, &key_type, &key_size);
67 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
68 return err;
69 }
70
71 if (key_type != PSA_KEY_TYPE_HMAC){
72 return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
73 }
74
Jamie Foxefd82732018-11-26 10:34:32 +000075 /* Set the key usage based on whether this is a sign or verify operation */
76 if ((ctx->key_usage_sign == 1) && (ctx->key_usage_verify == 0)) {
77 usage = PSA_KEY_USAGE_SIGN;
78 } else if ((ctx->key_usage_sign == 0) && (ctx->key_usage_verify == 1)) {
79 usage = PSA_KEY_USAGE_VERIFY;
80 } else {
81 return TFM_CRYPTO_ERR_PSA_ERROR_BAD_STATE;
82 }
83
Louis Mayencourt7a36f782018-09-24 14:00:57 +010084 /* Get the key data to start the HMAC */
Jamie Foxefd82732018-11-26 10:34:32 +000085 err = tfm_crypto_get_key(key,
86 usage,
87 alg,
88 key_data,
89 TFM_CRYPTO_MAX_KEY_LENGTH,
90 &key_size);
Louis Mayencourt7a36f782018-09-24 14:00:57 +010091 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
92 return err;
93 }
94
95 /* Bind the digest size to the MAC operation */
96 ctx->mac_size = PSA_HASH_SIZE(PSA_ALG_HMAC_HASH(alg));
97
98 block_size = get_hash_block_size(PSA_ALG_HMAC_HASH(alg));
99
100 /* The HMAC algorithm is the standard procedure as described in
101 * RFC-2104 (https://tools.ietf.org/html/rfc2104)
102 */
103 if (key_size > block_size) {
104 /* Hash the key to reduce it to block size */
105 err = tfm_crypto_hash_setup(&(ctx->ctx.hmac.hash_operation),
106 PSA_ALG_HMAC_HASH(alg));
107 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
108 return err;
109 }
110
111 err = tfm_crypto_hash_update(&(ctx->ctx.hmac.hash_operation),
112 &key_data[0],
113 key_size);
114 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
115 tfm_crypto_hash_abort(&(ctx->ctx.hmac.hash_operation));
116 return err;
117 }
118
119 /* Replace the key with the hashed key */
120 err = tfm_crypto_hash_finish(&(ctx->ctx.hmac.hash_operation),
121 hashed_key, sizeof(hashed_key),
122 &key_size);
123 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
124 tfm_crypto_hash_abort(&(ctx->ctx.hmac.hash_operation));
125 return err;
126 }
127 } else {
128 /* Copy the key inside the hashed_key buffer */
129 for (i=0; i<key_size; i++) {
130 hashed_key[i] = key_data[i];
131 }
132 }
133
134 /* Create ipad = hashed_key XOR 0x36 and opad = hashed_key XOR 0x5C */
135 for (i=0; i<key_size; i++) {
136 ipad[i] = hashed_key[i] ^ 0x36;
137 opad[i] = hashed_key[i] ^ 0x5C;
138 }
139 /* Fill ipad and opad to match block size */
140 for (i=key_size; i<block_size; i++) {
141 ipad[i] = 0x36;
142 opad[i] = 0x5C;
143 }
144
145 /* Start hash1 = H(i_key_pad || message) */
146 err = tfm_crypto_hash_setup(&(ctx->ctx.hmac.hash_operation),
147 PSA_ALG_HMAC_HASH(alg));
148 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
149 /* Clear key information on stack */
150 for (i=0; i<key_size; i++) {
151 hashed_key[i] = 0;
152 ipad[i] = 0;
153 }
154 return err;
155 }
156
157 err = tfm_crypto_hash_update(&(ctx->ctx.hmac.hash_operation),
158 ipad,
159 block_size);
160 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
161 tfm_crypto_hash_abort(&(ctx->ctx.hmac.hash_operation));
162 return err;
163 }
164
165 return TFM_CRYPTO_ERR_PSA_SUCCESS;
166}
167
168static enum tfm_crypto_err_t tfm_crypto_mac_setup(psa_mac_operation_t *operation,
169 psa_key_slot_t key,
170 psa_algorithm_t alg,
171 uint8_t sign_operation)
172{
173 enum tfm_crypto_err_t err;
174
175 struct tfm_mac_operation_s *ctx = NULL;
176
177 if (!PSA_ALG_IS_MAC(alg)) {
178 return TFM_CRYPTO_ERR_PSA_ERROR_NOT_SUPPORTED;
179 }
180
181 /* Validate pointers */
182 err = tfm_crypto_memory_check(operation,
183 sizeof(psa_mac_operation_t),
184 TFM_MEMORY_ACCESS_RW);
185 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
186 return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
187 }
188
189 /* Allocate the operation context in the secure world */
190 err = tfm_crypto_operation_alloc(TFM_CRYPTO_MAC_OPERATION,
191 &(operation->handle));
192 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
193 return err;
194 }
195
196 /* Look up the corresponding operation context */
197 err = tfm_crypto_operation_lookup(TFM_CRYPTO_MAC_OPERATION,
198 operation->handle,
199 (void **)&ctx);
200 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
201 /* Release the operation context */
202 tfm_crypto_operation_release(&(operation->handle));
203 return err;
204 }
205
206 /* Bind the algorithm to the mac operation */
207 ctx->alg = alg;
208
209 /* Specify if this will be used for a sign or verify operation */
210 if (sign_operation) {
211 ctx->key_usage_verify = 0;
212 ctx->key_usage_sign = 1;
213 } else {
214 ctx->key_usage_verify = 1;
215 ctx->key_usage_sign = 0;
216 }
217
218 if (PSA_ALG_IS_HMAC(alg)) {
219 err = tfm_crypto_hmac_setup(ctx, key, alg);
220 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
221 /* Release the operation context */
222 tfm_crypto_operation_release(&(operation->handle));
223 return err;
224 }
225
226 ctx->key_set = 1;
227 } else {
228 /* Other MAC types constructions are not supported */
229 /* Release the operation context */
230 tfm_crypto_operation_release(&(operation->handle));
231 return TFM_CRYPTO_ERR_PSA_ERROR_NOT_SUPPORTED;
232 }
233
234 return TFM_CRYPTO_ERR_PSA_SUCCESS;
235}
236
237static enum tfm_crypto_err_t tfm_crypto_mac_finish(
238 struct tfm_mac_operation_s *ctx,
239 uint8_t *mac,
240 size_t mac_size,
241 size_t *mac_length)
242{
243 enum tfm_crypto_err_t err;
244 uint8_t hash1[PSA_HASH_MAX_SIZE];
245 size_t hash_size;
246 uint8_t *opad;
247 size_t block_size;
248
249 /* Sanity checks */
250 if (mac_size < ctx->mac_size) {
251 return TFM_CRYPTO_ERR_PSA_ERROR_BUFFER_TOO_SMALL;
252 }
253
254 if (!(ctx->has_input)) {
255 return TFM_CRYPTO_ERR_PSA_ERROR_BAD_STATE;
256 }
257
258 if (PSA_ALG_IS_HMAC(ctx->alg)) {
259 opad = ctx->ctx.hmac.opad;
260 block_size = get_hash_block_size(PSA_ALG_HMAC_HASH(ctx->alg));
261
262 /* finish the hash1 = H(ipad || message) */
263 err = tfm_crypto_hash_finish(&(ctx->ctx.hmac.hash_operation),
264 hash1,
265 sizeof(hash1),
266 &hash_size);
267 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
268 return err;
269 }
270
271 /* compute the final mac value = H(opad || hash1) */
272 err = tfm_crypto_hash_setup(&(ctx->ctx.hmac.hash_operation),
273 PSA_ALG_HMAC_HASH(ctx->alg));
274 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
275 mac_zeroize(hash1, sizeof(hash1));
276 return err;
277 }
278
279 err = tfm_crypto_hash_update(&(ctx->ctx.hmac.hash_operation),
280 opad,
281 block_size);
282 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
283 mac_zeroize(hash1, sizeof(hash1));
284 return err;
285 }
286
287 err = tfm_crypto_hash_update(&(ctx->ctx.hmac.hash_operation),
288 hash1,
289 hash_size);
290 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
291 mac_zeroize(hash1, sizeof(hash1));
292 return err;
293 }
294
295 err = tfm_crypto_hash_finish(&(ctx->ctx.hmac.hash_operation),
296 mac,
297 mac_size,
298 mac_length);
299 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
300 mac_zeroize(hash1, sizeof(hash1));
301 return err;
302 }
303
304 /* Clear intermediate hash value */
305 mac_zeroize(hash1, sizeof(hash1));
306
307 } else {
308 return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
309 }
310
311 /* Clear the mac context */
312 mac_zeroize(ctx, sizeof(struct tfm_mac_operation_s));
313
314 return TFM_CRYPTO_ERR_PSA_SUCCESS;
315}
316
317/*!
318 * \defgroup public_psa Public functions, PSA
319 *
320 */
321
322/*!@{*/
323enum tfm_crypto_err_t tfm_crypto_mac_sign_setup(psa_mac_operation_t *operation,
324 psa_key_slot_t key,
325 psa_algorithm_t alg)
326{
327 return tfm_crypto_mac_setup(operation, key, alg, 1);
328}
329
330enum tfm_crypto_err_t tfm_crypto_mac_verify_setup(
331 psa_mac_operation_t *operation,
332 psa_key_slot_t key,
333 psa_algorithm_t alg)
334{
335 return tfm_crypto_mac_setup(operation, key, alg, 0);
336}
337
338enum tfm_crypto_err_t tfm_crypto_mac_update(psa_mac_operation_t *operation,
339 const uint8_t *input,
340 size_t input_length)
341{
342 enum tfm_crypto_err_t err;
343
344 struct tfm_mac_operation_s *ctx = NULL;
345
346 if (input_length == 0) {
347 return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
348 }
349
350 /* Validate pointers */
351 err = tfm_crypto_memory_check(operation,
352 sizeof(psa_mac_operation_t),
353 TFM_MEMORY_ACCESS_RW);
354 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
355 return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
356 }
357
358 err = tfm_crypto_memory_check((void *)input,
359 input_length,
360 TFM_MEMORY_ACCESS_RO);
361 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
362 return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
363 }
364
365 /* Look up the corresponding operation context */
366 err = tfm_crypto_operation_lookup(TFM_CRYPTO_MAC_OPERATION,
367 operation->handle,
368 (void **)&ctx);
369 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
370 return err;
371 }
372
373 /* Sanity check */
374 if (!(ctx->key_set)) {
375 return TFM_CRYPTO_ERR_PSA_ERROR_BAD_STATE;
376 }
377
378 /* Process the input chunk */
379 if (PSA_ALG_IS_HMAC(ctx->alg)) {
380 err = tfm_crypto_hash_update(&(ctx->ctx.hmac.hash_operation),
381 input,
382 input_length);
383 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
384 return err;
385 }
386
387 /* Set this flag to avoid HMAC without data */
388 ctx->has_input = 1;
389 } else {
390 return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
391 }
392
393 return TFM_CRYPTO_ERR_PSA_SUCCESS;
394}
395
396enum tfm_crypto_err_t tfm_crypto_mac_sign_finish(psa_mac_operation_t *operation,
397 uint8_t *mac,
398 size_t mac_size,
399 size_t *mac_length)
400{
401 enum tfm_crypto_err_t err;
402 struct tfm_mac_operation_s *ctx = NULL;
403
404 if (mac_size == 0) {
405 return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
406 }
407
408 /* Validate pointers */
409 err = tfm_crypto_memory_check(operation,
410 sizeof(psa_mac_operation_t),
411 TFM_MEMORY_ACCESS_RW);
412 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
413 return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
414 }
415
416 err = tfm_crypto_memory_check((void *)mac,
417 mac_size,
418 TFM_MEMORY_ACCESS_RW);
419 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
420 return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
421 }
422
423 err = tfm_crypto_memory_check(mac_length,
424 sizeof(size_t),
425 TFM_MEMORY_ACCESS_RW);
426 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
427 return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
428 }
429
430 /* Look up the corresponding operation context */
431 err = tfm_crypto_operation_lookup(TFM_CRYPTO_MAC_OPERATION,
432 operation->handle,
433 (void **)&ctx);
434 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
435 return err;
436 }
437
438 if ((ctx->key_usage_sign == 1) && (ctx->key_usage_verify == 0)) {
439 /* Finalise the mac operation */
440 err = tfm_crypto_mac_finish(ctx, mac, mac_size, mac_length);
441 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
442 return err;
443 }
444 /* Release the operation context */
445 err = tfm_crypto_operation_release(&(operation->handle));
446 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
447 return err;
448 }
449 } else {
450 return TFM_CRYPTO_ERR_PSA_ERROR_BAD_STATE;
451 }
452
453 return TFM_CRYPTO_ERR_PSA_SUCCESS;
454}
455
456enum tfm_crypto_err_t tfm_crypto_mac_verify_finish(
457 psa_mac_operation_t *operation,
458 const uint8_t *mac,
459 size_t mac_length)
460{
461 enum tfm_crypto_err_t err;
462 struct tfm_mac_operation_s *ctx = NULL;
463 uint8_t computed_mac[PSA_HMAC_MAX_HASH_BLOCK_SIZE];
464 size_t computed_mac_length;
465 size_t i;
466 uint32_t comp_mismatch = 0;
467
468 if (mac_length == 0) {
469 return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
470 }
471
472 /* Validate pointers */
473 err = tfm_crypto_memory_check(operation,
474 sizeof(psa_mac_operation_t),
475 TFM_MEMORY_ACCESS_RW);
476 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
477 return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
478 }
479
480 err = tfm_crypto_memory_check((void *)mac,
481 mac_length,
482 TFM_MEMORY_ACCESS_RO);
483 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
484 return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
485 }
486
487 /* Look up the corresponding operation context */
488 err = tfm_crypto_operation_lookup(TFM_CRYPTO_MAC_OPERATION,
489 operation->handle,
490 (void **)&ctx);
491 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
492 return err;
493 }
494
495 if ((ctx->key_usage_sign == 0) && (ctx->key_usage_verify == 1)) {
496 /* Finalise the mac operation */
497 err = tfm_crypto_mac_finish(ctx,
498 computed_mac,
499 sizeof(computed_mac),
500 &computed_mac_length);
501 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
502 return err;
503 }
504 /* Release the operation context */
505 err = tfm_crypto_operation_release(&(operation->handle));
506 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
507 return err;
508 }
509
510 /* Check that the computed mac match the expected one */
511 if (computed_mac_length != mac_length) {
512 return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_SIGNATURE;
513 }
514
515 for (i=0; i<computed_mac_length ; i++) {
516 if (computed_mac[i] != mac[i]) {
517 comp_mismatch = 1;
518 }
519 }
520
521 if (comp_mismatch == 1) {
522 return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_SIGNATURE;
523 }
524 } else {
525 return TFM_CRYPTO_ERR_PSA_ERROR_BAD_STATE;
526 }
527
528 return TFM_CRYPTO_ERR_PSA_SUCCESS;
529}
530
531enum tfm_crypto_err_t tfm_crypto_mac_abort(psa_mac_operation_t *operation)
532{
533 enum tfm_crypto_err_t err;
534 struct tfm_mac_operation_s *ctx = NULL;
535
536 /* Validate pointers */
537 err = tfm_crypto_memory_check(operation,
538 sizeof(psa_mac_operation_t),
539 TFM_MEMORY_ACCESS_RW);
540 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
541 return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
542 }
543
544 /* Look up the corresponding operation context */
545 err = tfm_crypto_operation_lookup(TFM_CRYPTO_MAC_OPERATION,
546 operation->handle,
547 (void **)&ctx);
548 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
549 return err;
550 }
551
552 if (PSA_ALG_IS_HMAC(ctx->alg)){
553 /* Check if the HMAC internal context needs to be deallocated */
554 if (ctx->ctx.hmac.hash_operation.handle != TFM_CRYPTO_INVALID_HANDLE) {
555 /* Clear hash context */
556 err = tfm_crypto_hash_abort(&(ctx->ctx.hmac.hash_operation));
557 if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
558 return err;
559 }
560 }
561
562 /* Release the operation context */
563 tfm_crypto_operation_release(&(operation->handle));
564 } else {
565 /* MACs other than HMACs not currently supported */
566 return TFM_CRYPTO_ERR_PSA_ERROR_NOT_SUPPORTED;
567 }
568
569 return TFM_CRYPTO_ERR_PSA_SUCCESS;
570}
571/*!@}*/