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