1 /*
2  * Copyright (c) 2023-2024, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "rse_key_derivation.h"
9 
10 #include "device_definition.h"
11 #include "tfm_plat_otp.h"
12 #include "dpa_hardened_word_copy.h"
13 #include "cc3xx_drv.h"
14 #include "kmu_drv.h"
15 
16 #include <stdint.h>
17 #include <string.h>
18 
19 extern uint8_t computed_bl1_2_hash[];
20 
21 static struct kmu_key_export_config_t kmu_key0_export_config = {
22     CC3XX_BASE_S + 0x400, /* CC3XX AES_KEY_0 register */
23     0, /* No delay */
24     0x01, /* Increment by 4 bytes with each write */
25     KMU_DESTINATION_PORT_WIDTH_32_BITS, /* Write 32 bits with each write */
26     KMU_DESTINATION_PORT_WIDTH_8_WRITES, /* Perform 8 writes (total 256 bits) */
27     true,  /* refresh the masking */
28     false, /* Don't disable the masking */
29 };
30 
31 static struct kmu_key_export_config_t kmu_key1_export_config = {
32     CC3XX_BASE_S + 0x420, /* CC3XX AES_KEY_1 register */
33     0, /* No delay */
34     0x01, /* Increment by 4 bytes with each write */
35     KMU_DESTINATION_PORT_WIDTH_32_BITS, /* Write 32 bits with each write */
36     KMU_DESTINATION_PORT_WIDTH_8_WRITES, /* Perform 8 writes (total 256 bits) */
37     true,  /* refresh the masking */
38     false, /* Don't disable the masking */
39 };
40 
41 
rse_get_boot_state(uint8_t * state,size_t state_buf_len,size_t * state_size)42 static int rse_get_boot_state(uint8_t *state, size_t state_buf_len,
43                               size_t *state_size)
44 {
45     int rc;
46     enum lcm_error_t lcm_err;
47     cc3xx_err_t err;
48 
49     enum plat_otp_lcs_t lcs;
50     enum lcm_tp_mode_t tp_mode;
51     uint32_t reprovisioning_bits;
52 
53     if (state_buf_len < 32) {
54         return 1;
55     }
56 
57     rc = tfm_plat_otp_read(PLAT_OTP_ID_LCS, sizeof(lcs), (uint8_t *)&lcs);
58     if (rc) {
59         return rc;
60     }
61 
62     rc = tfm_plat_otp_read(PLAT_OTP_ID_REPROVISIONING_BITS,
63                            sizeof(reprovisioning_bits),
64                            (uint8_t *)&reprovisioning_bits);
65     if (rc) {
66         return rc;
67     }
68 
69     lcm_err = lcm_get_tp_mode(&LCM_DEV_S, &tp_mode);
70     if (lcm_err != LCM_ERROR_NONE) {
71         return lcm_err;
72     }
73 
74     err = cc3xx_lowlevel_hash_init(CC3XX_HASH_ALG_SHA256);
75     if (err != CC3XX_ERR_SUCCESS) {
76         return -1;
77     }
78 
79     err = cc3xx_lowlevel_hash_update((uint8_t *)&lcs, sizeof(lcs));
80     if (err != CC3XX_ERR_SUCCESS) {
81         return -1;
82     }
83 
84     err = cc3xx_lowlevel_hash_update((uint8_t *)&tp_mode, sizeof(tp_mode));
85     if (err != CC3XX_ERR_SUCCESS) {
86         return -1;
87     }
88 
89     err = cc3xx_lowlevel_hash_update((uint8_t *)&reprovisioning_bits, sizeof(reprovisioning_bits));
90     if (err != CC3XX_ERR_SUCCESS) {
91         return -1;
92     }
93     err = cc3xx_lowlevel_hash_update(computed_bl1_2_hash, 32);
94     if (err != CC3XX_ERR_SUCCESS) {
95         return -1;
96     }
97 
98     cc3xx_lowlevel_hash_finish((uint32_t *)state, SHA256_OUTPUT_SIZE);
99     *state_size = SHA256_OUTPUT_SIZE;
100 
101     return 0;
102 }
103 
rse_derive_key(enum kmu_hardware_keyslot_t key_id,uint32_t * key_buf,const uint8_t * label,size_t label_len,enum rse_kmu_slot_id_t slot,bool duplicate_into_next_slot)104 static int rse_derive_key(enum kmu_hardware_keyslot_t key_id, uint32_t *key_buf,
105                           const uint8_t *label, size_t label_len,
106                           enum rse_kmu_slot_id_t slot,
107                           bool duplicate_into_next_slot)
108 {
109     int rc;
110     uint8_t context[32] = {0};
111     size_t context_len;
112     enum kmu_error_t kmu_err;
113     volatile uint32_t *p_kmu_slot_buf;
114     volatile uint32_t *p_kmu_secondary_slot_buf;
115     size_t kmu_slot_size;
116 
117     rc = rse_get_boot_state(context, sizeof(context), &context_len);
118     if (rc) {
119         return rc;
120     }
121 
122     kmu_err = kmu_get_key_buffer_ptr(&KMU_DEV_S, slot,
123                                      &p_kmu_slot_buf, &kmu_slot_size);
124     if (kmu_err != KMU_ERROR_NONE) {
125         return -1;
126     }
127 
128     rc = cc3xx_lowlevel_kdf_cmac(key_id, key_buf, CC3XX_AES_KEYSIZE_256, label,
129                                  label_len, context, context_len,
130                                  (uint32_t *)p_kmu_slot_buf, 32);
131     if (rc) {
132         return rc;
133     }
134 
135     /* Due to limitations in CryptoCell, any key that needs to be used for
136      * AES-CCM needs to be duplicated into a second slot.
137      */
138     if (duplicate_into_next_slot) {
139         kmu_err = kmu_get_key_buffer_ptr(&KMU_DEV_S, slot + 1,
140                                          &p_kmu_secondary_slot_buf,
141                                          &kmu_slot_size);
142         if (kmu_err != KMU_ERROR_NONE) {
143             return -2;
144         }
145 
146         dpa_hardened_word_copy(p_kmu_secondary_slot_buf, p_kmu_slot_buf,
147                         kmu_slot_size / sizeof(uint32_t));
148 
149         /* TODO lock keyslots once the runtime CC3XX driver supports locked KMU
150          * keyslots
151          */
152         /* kmu_err = kmu_set_key_locked(&KMU_DEV_S, slot + 1); */
153         /* if (kmu_err != KMU_ERROR_NONE) { */
154         /*     return -3; */
155         /* } */
156 
157         kmu_err = kmu_set_key_export_config(&KMU_DEV_S, slot + 1,
158                                             &kmu_key1_export_config);
159         if (kmu_err != KMU_ERROR_NONE) {
160             return -4;
161         }
162 
163         kmu_err = kmu_set_key_export_config_locked(&KMU_DEV_S, slot + 1);
164         if (kmu_err != KMU_ERROR_NONE) {
165             return -5;
166         }
167     }
168 
169     /* TODO lock keyslots once the runtime CC3XX driver supports locked KMU
170      * keyslots
171      */
172     /* kmu_err = kmu_set_key_locked(&KMU_DEV_S, slot); */
173     /* if (kmu_err != KMU_ERROR_NONE) { */
174     /*     return -6; */
175     /* } */
176 
177 
178     kmu_err = kmu_set_key_export_config(&KMU_DEV_S, slot,
179                                         &kmu_key0_export_config);
180     if (kmu_err != KMU_ERROR_NONE) {
181         return -7;
182     }
183 
184     kmu_err = kmu_set_key_export_config_locked(&KMU_DEV_S, slot);
185     if (kmu_err != KMU_ERROR_NONE) {
186         return -8;
187     }
188 
189     return rc;
190 }
191 
rse_derive_cpak_seed(enum rse_kmu_slot_id_t slot)192 int rse_derive_cpak_seed(enum rse_kmu_slot_id_t slot)
193 {
194     uint8_t cpak_seed_label[] = "BL1_CPAK_SEED_DERIVATION";
195 
196     return rse_derive_key(KMU_HW_SLOT_GUK, NULL, cpak_seed_label,
197                           sizeof(cpak_seed_label), slot, false);
198 }
199 
rse_derive_dak_seed(enum rse_kmu_slot_id_t slot)200 int rse_derive_dak_seed(enum rse_kmu_slot_id_t slot)
201 {
202     uint8_t dak_seed_label[]  = "BL1_DAK_SEED_DERIVATION";
203 
204     return rse_derive_key(KMU_HW_SLOT_GUK, NULL, dak_seed_label,
205                           sizeof(dak_seed_label), slot, false);
206 }
207 
rse_derive_rot_cdi(enum rse_kmu_slot_id_t slot)208 int rse_derive_rot_cdi(enum rse_kmu_slot_id_t slot)
209 {
210     uint8_t rot_cdi_label[] = "BL1_ROT_CDI_DERIVATION";
211 
212     return rse_derive_key(KMU_HW_SLOT_HUK, NULL, rot_cdi_label,
213                           sizeof(rot_cdi_label), slot, false);
214 }
215 
rse_derive_vhuk_seed(uint32_t * vhuk_seed,size_t vhuk_seed_buf_len,size_t * vhuk_seed_size)216 int rse_derive_vhuk_seed(uint32_t *vhuk_seed, size_t vhuk_seed_buf_len,
217                          size_t *vhuk_seed_size)
218 {
219     uint8_t vhuk_seed_label[]  = "VHUK_SEED_DERIVATION";
220     int rc;
221 
222     if (vhuk_seed_buf_len < 32) {
223         return 1;
224     }
225 
226     rc = cc3xx_lowlevel_kdf_cmac(KMU_HW_SLOT_HUK, NULL, CC3XX_AES_KEYSIZE_256,
227                                  vhuk_seed_label, sizeof(vhuk_seed_label), NULL, 0,
228                                  vhuk_seed, 32);
229     if (rc) {
230         return rc;
231     }
232 
233     *vhuk_seed_size = 32;
234 
235     return 0;
236 }
237 
rse_derive_vhuk(const uint8_t * vhuk_seeds,size_t vhuk_seeds_len,enum rse_kmu_slot_id_t slot)238 int rse_derive_vhuk(const uint8_t *vhuk_seeds, size_t vhuk_seeds_len,
239                     enum rse_kmu_slot_id_t slot)
240 {
241     return rse_derive_key(KMU_HW_SLOT_GUK, NULL, vhuk_seeds, vhuk_seeds_len,
242                           slot, false);
243 }
244 
rse_derive_session_key(const uint8_t * ivs,size_t ivs_len,enum rse_kmu_slot_id_t slot)245 int rse_derive_session_key(const uint8_t *ivs, size_t ivs_len,
246                            enum rse_kmu_slot_id_t slot)
247 {
248     int rc;
249     enum kmu_error_t kmu_err;
250 
251     rc = rse_derive_key(KMU_HW_SLOT_GUK, NULL, ivs, ivs_len, slot, true);
252     if (rc) {
253         return rc;
254     }
255 
256     /* TODO: Should be removed once rse_derive_key properly locks KMU slots */
257     kmu_err = kmu_set_key_locked(&KMU_DEV_S, slot);
258     if (kmu_err != KMU_ERROR_NONE) {
259         return -1;
260     }
261 
262     kmu_err = kmu_set_key_locked(&KMU_DEV_S, slot + 1);
263     if (kmu_err != KMU_ERROR_NONE) {
264         return -1;
265     }
266 
267     return 0;
268 }
269 
derive_using_krtl_or_zero_key(uint8_t * label,size_t label_len,enum rse_kmu_slot_id_t output_slot)270 int derive_using_krtl_or_zero_key(uint8_t *label, size_t label_len,
271                                   enum rse_kmu_slot_id_t output_slot)
272 {
273     int rc;
274     uint32_t zero_key[8] = {0};
275     enum kmu_error_t kmu_err;
276     enum lcm_tp_mode_t tp_mode;
277     enum lcm_error_t lcm_err;
278     enum rse_kmu_slot_id_t input_slot;
279     uint32_t *key_buf;
280 
281     lcm_err = lcm_get_tp_mode(&LCM_DEV_S, &tp_mode);
282     if (lcm_err != LCM_ERROR_NONE) {
283         return TFM_PLAT_ERR_SYSTEM_ERR;
284     }
285 
286     switch(tp_mode) {
287     case LCM_TP_MODE_PCI:
288         input_slot = (enum rse_kmu_slot_id_t)KMU_HW_SLOT_KRTL;
289         key_buf = NULL;
290         break;
291     case LCM_TP_MODE_TCI:
292         input_slot = (enum rse_kmu_slot_id_t)0;
293         key_buf = zero_key;
294         break;
295     default:
296         return -1;
297     }
298 
299     rc = rse_derive_key(input_slot, key_buf, label, label_len,
300                         output_slot, true);
301     if (rc) {
302         return rc;
303     }
304 
305     /* Until we can lock all the keys, just lock the ones only used in
306      * BL1/provisioning.
307      */
308     kmu_err = kmu_set_key_locked(&KMU_DEV_S, output_slot);
309     if (kmu_err != KMU_ERROR_NONE) {
310         return -1;
311     }
312 
313     kmu_err = kmu_set_key_locked(&KMU_DEV_S, output_slot + 1);
314     if (kmu_err != KMU_ERROR_NONE) {
315         return -1;
316     }
317 
318     return 0;
319 }
320 
rse_derive_cm_provisioning_key(enum rse_kmu_slot_id_t slot)321 int rse_derive_cm_provisioning_key(enum rse_kmu_slot_id_t slot)
322 {
323     uint8_t cm_provisioning_label[] = "CM_PROVISIONING";
324 
325     return derive_using_krtl_or_zero_key(cm_provisioning_label,
326                                          sizeof(cm_provisioning_label), slot);
327 }
328 
rse_derive_dm_provisioning_key(enum rse_kmu_slot_id_t slot)329 int rse_derive_dm_provisioning_key(enum rse_kmu_slot_id_t slot)
330 {
331     uint8_t dm_provisioning_label[] = "DM_PROVISIONING";
332 
333     return derive_using_krtl_or_zero_key(dm_provisioning_label,
334                                          sizeof(dm_provisioning_label), slot);
335 }
336