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