1 /*
2  * Copyright (c) 2023-2024, The TrustedFirmware-M Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "cc3xx_kdf.h"
9 
10 #include "cc3xx_rng.h"
11 #include "cc3xx_stdlib.h"
12 
13 #include <assert.h>
14 
15 /* This is a NIST SP-800-108 counter mode KDF with CMAC as the pseudo-random
16  * function, using the modified Label || 0x00 || Context || [L]2 || K (0)
17  * construction where K(0) = PRF(K IN, Label || 0x00 || Context || [L]2 )
18  * proposed as a countermeasure for CMAC KDFs in SP-800-108 section 4.1.
19  */
cc3xx_lowlevel_kdf_cmac(cc3xx_aes_key_id_t key_id,const uint32_t * key,cc3xx_aes_keysize_t key_size,const uint8_t * label,size_t label_length,const uint8_t * context,size_t context_length,uint32_t * output_key,size_t out_length)20 cc3xx_err_t cc3xx_lowlevel_kdf_cmac(
21     cc3xx_aes_key_id_t key_id, const uint32_t *key,
22     cc3xx_aes_keysize_t key_size,
23     const uint8_t *label, size_t label_length,
24     const uint8_t *context, size_t context_length,
25     uint32_t *output_key, size_t out_length)
26 {
27     uint32_t i_idx = 1;
28     uint32_t l_total_length = out_length;
29     uint8_t null_byte = 0;
30     cc3xx_err_t err;
31     uint32_t cmac_buf[AES_TAG_MAX_LEN / sizeof(uint32_t)];
32     uint32_t k0[AES_TAG_MAX_LEN / sizeof(uint32_t)];
33     size_t output_idx;
34 
35     /* Check alignment */
36     assert(((uintptr_t)output_key & 0b11) == 0);
37     assert((out_length / sizeof(cmac_buf)) != 0);
38 
39     err = cc3xx_lowlevel_aes_init(CC3XX_AES_DIRECTION_ENCRYPT, CC3XX_AES_MODE_CMAC,
40                                   key_id, key, key_size, NULL, 0);
41     if (err != CC3XX_ERR_SUCCESS) {
42         goto out;
43     }
44 
45     cc3xx_lowlevel_aes_set_tag_len(AES_TAG_MAX_LEN);
46 
47     cc3xx_lowlevel_aes_update_authed_data(label, label_length);
48     cc3xx_lowlevel_aes_update_authed_data(&null_byte, sizeof(null_byte));
49     cc3xx_lowlevel_aes_update_authed_data(context, context_length);
50     cc3xx_lowlevel_aes_update_authed_data((uint8_t *)&l_total_length,
51                                  sizeof(l_total_length));
52     cc3xx_lowlevel_aes_finish(k0, NULL);
53 
54     for(output_idx = 0; output_idx < out_length; output_idx += sizeof(cmac_buf)) {
55         err = cc3xx_lowlevel_aes_init(CC3XX_AES_DIRECTION_ENCRYPT, CC3XX_AES_MODE_CMAC,
56                                       key_id, key, key_size, NULL, 0);
57         if (err != CC3XX_ERR_SUCCESS) {
58             goto out;
59         }
60 
61         cc3xx_lowlevel_aes_set_tag_len(AES_TAG_MAX_LEN);
62 
63         cc3xx_lowlevel_aes_update_authed_data((uint8_t *)&i_idx, sizeof(i_idx));
64         cc3xx_lowlevel_aes_update_authed_data(label, label_length);
65         cc3xx_lowlevel_aes_update_authed_data(&null_byte, sizeof(null_byte));
66         cc3xx_lowlevel_aes_update_authed_data(context, context_length);
67         cc3xx_lowlevel_aes_update_authed_data((uint8_t *)&l_total_length,
68                                      sizeof(l_total_length));
69         cc3xx_lowlevel_aes_update_authed_data((uint8_t *)k0, sizeof(k0));
70         cc3xx_lowlevel_aes_finish(cmac_buf, NULL);
71 
72         cc3xx_dpa_hardened_word_copy((void *)output_key + output_idx, cmac_buf,
73                                      sizeof(cmac_buf) / sizeof(uint32_t));
74         i_idx += 1;
75     }
76 
77     err = CC3XX_ERR_SUCCESS;
78 out:
79     cc3xx_secure_erase_buffer(k0, sizeof(k0) / sizeof(uint32_t));
80     cc3xx_secure_erase_buffer(cmac_buf, sizeof(cmac_buf) / sizeof(uint32_t));
81 
82     if (err != CC3XX_ERR_SUCCESS) {
83         cc3xx_secure_erase_buffer(output_key, out_length / sizeof(uint32_t));
84     }
85 
86     return err;
87 }
88