Software APIs
keymgr_dpe_testutils.c
1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5// This #if define ... ensures backwards compatibility with darjeeling. Either
6// both tops will get their own testutils or this define guard can be
7// implemented at a more granular level (i.e. at function level).
8// TODO(#30919): Split the keymgr_dpe_testutil on a finer level.
9#if defined(OPENTITAN_IS_DARJEELING)
10
11#include "sw/device/lib/testing/keymgr_dpe_testutils.h"
12
13#include "hw/top/dt/keymgr_dpe.h"
14#include "hw/top/dt/otp_ctrl.h"
15#include "hw/top/dt/rstmgr.h"
21#include "sw/device/lib/testing/otp_ctrl_testutils.h"
22#include "sw/device/lib/testing/rstmgr_testutils.h"
23#include "sw/device/lib/testing/test_framework/check.h"
25
26status_t keymgr_dpe_testutils_startup(dif_keymgr_dpe_t *keymgr_dpe,
27 uint32_t slot_dst_sel) {
28 dif_rstmgr_t rstmgr;
30
31 TRY(dif_rstmgr_init_from_dt(kDtRstmgr, &rstmgr));
32 info = rstmgr_testutils_reason_get();
33
34 // POR reset.
35 if (info == kDifRstmgrResetInfoPor) {
37 "Powered up for the first time, lock SECRET2 and SECRET3 partitions");
39 TRY(dif_otp_ctrl_init_from_dt(kDtOtpCtrl, &otp));
40 TRY(otp_ctrl_testutils_lock_partition(&otp, kDifOtpCtrlPartitionSecret2,
41 0));
42 TRY(otp_ctrl_testutils_lock_partition(&otp, kDifOtpCtrlPartitionSecret3,
43 0));
44
45 // Reboot device.
46 rstmgr_testutils_reason_clear();
47 LOG_INFO("Triggering software reset");
48 TRY(dif_rstmgr_software_device_reset(&rstmgr));
49
50 // Wait here until device reset.
51 wait_for_interrupt();
52
53 } else {
54 TRY_CHECK(info == kDifRstmgrResetInfoSw, "Unexpected reset reason: %08x",
55 info);
57 "Powered up for the second time, actuate keymgr_dpe and perform test.");
58
59 // Initialize keymgr_dpe context.
60 TRY(dif_keymgr_dpe_init_from_dt(kDtKeymgrDpe, keymgr_dpe));
61
62 // Advance to Initialized state.
63 TRY(keymgr_dpe_testutils_check_state(keymgr_dpe, kDifKeymgrDpeStateReset));
64 TRY(dif_keymgr_dpe_initialize(keymgr_dpe, slot_dst_sel));
65 TRY(keymgr_dpe_testutils_wait_for_operation_done(keymgr_dpe));
66 TRY(keymgr_dpe_testutils_check_state(keymgr_dpe,
67 kDifKeymgrDpeStateAvailable));
68 LOG_INFO("UDS is latched.");
69 }
70 return OK_STATUS();
71}
72
73status_t keymgr_dpe_testutils_advance_state(
74 const dif_keymgr_dpe_t *keymgr_dpe,
75 const dif_keymgr_dpe_advance_params_t *params) {
76 TRY(dif_keymgr_dpe_advance_state(keymgr_dpe, params));
77 return keymgr_dpe_testutils_wait_for_operation_done(keymgr_dpe);
78}
79
80status_t keymgr_dpe_testutils_erase_slot(
81 const dif_keymgr_dpe_t *keymgr_dpe,
82 const dif_keymgr_dpe_erase_params_t *params) {
83 TRY(dif_keymgr_dpe_erase_slot(keymgr_dpe, params));
84 return keymgr_dpe_testutils_wait_for_operation_done(keymgr_dpe);
85}
86
87status_t keymgr_dpe_testutils_generate(
88 const dif_keymgr_dpe_t *keymgr_dpe,
91 TRY(dif_keymgr_dpe_generate(keymgr_dpe, params));
92 TRY(keymgr_dpe_testutils_wait_for_operation_done(keymgr_dpe));
93 TRY(dif_keymgr_dpe_read_output(keymgr_dpe, key));
94 return OK_STATUS();
95}
96
97status_t keymgr_dpe_testutils_check_state(
98 const dif_keymgr_dpe_t *keymgr_dpe,
99 const dif_keymgr_dpe_state_t exp_state) {
100 dif_keymgr_dpe_state_t act_state;
101 TRY(dif_keymgr_dpe_get_state(keymgr_dpe, &act_state));
102 TRY_CHECK(act_state == exp_state,
103 "KeymgrDPE in unexpected state: %x, expected to be %x", act_state,
104 exp_state);
105 return OK_STATUS();
106}
107
108status_t keymgr_dpe_testutils_wait_for_operation_done(
109 const dif_keymgr_dpe_t *keymgr_dpe) {
111 do {
112 TRY(dif_keymgr_dpe_get_status_codes(keymgr_dpe, &status));
113 } while (status == 0);
114 TRY_CHECK(status == kDifKeymgrDpeStatusCodeIdle, "Unexpected status: %x",
115 status);
116 return OK_STATUS();
117}
118
119#elif defined(OPENTITAN_IS_EARLGREY) || defined(OPENTITAN_IS_ENGLISHBREAKFAST)
120#include "hw/top/dt/otp_ctrl.h"
126#include "sw/device/lib/testing/entropy_testutils.h"
127#include "sw/device/lib/testing/keymgr_dpe_testutils.h"
128#include "sw/device/lib/testing/kmac_testutils.h"
129#include "sw/device/lib/testing/nvm_testutils.h"
130#include "sw/device/lib/testing/otp_ctrl_testutils.h"
131#include "sw/device/lib/testing/rstmgr_testutils.h"
132#include "sw/device/lib/testing/test_framework/check.h"
134#include "sw/device/silicon_creator/lib/drivers/retention_sram.h"
135
137
138#define MODULE_ID MAKE_MODULE_ID('k', 'm', 'd')
139
140const static char *kKeymgrStageNames[] = {
141 [kDifKeymgrDpeStateReset] = "Reset",
142 [kDifKeymgrDpeStateAvailable] = "Available",
143 [kDifKeymgrDpeStateDisabled] = "Disabled",
144 [kDifKeymgrDpeStateInvalid] = "Invalid"};
145
146status_t keymgr_dpe_testutils_nvm_init(
147 const keymgr_dpe_testutils_secret_t *creator_secret,
148 const keymgr_dpe_testutils_secret_t *owner_secret) {
149 // Initialize flash secrets.
150 if (creator_secret) {
151 TRY(nvm_testutils_info_page_setup(kNvmInfoPageCreatorSecret, kPageReadWrite,
152 kPageScrambleCfg));
153 TRY(nvm_testutils_write_info_page(kNvmInfoPageCreatorSecret,
154 /*byte_offset=*/0, creator_secret->value,
155 ARRAYSIZE(creator_secret->value),
156 /*erase_before_write=*/true,
157 /*readback=*/true));
158 }
159 TRY(nvm_testutils_info_page_setup(kNvmInfoPageOwnerSecret, kPageReadWrite,
160 kPageScrambleCfg));
161 return nvm_testutils_write_info_page(kNvmInfoPageOwnerSecret,
162 /*byte_offset=*/0, owner_secret->value,
163 ARRAYSIZE(owner_secret->value),
164 /*erase_before_write=*/true,
165 /*readback=*/true);
166}
167
168static status_t check_lock_otp_partition(void) {
169 dif_otp_ctrl_t otp;
170 TRY(dif_otp_ctrl_init_from_dt(kDtOtpCtrl, &otp));
171
172 bool is_computed;
173 TRY(dif_otp_ctrl_is_digest_computed(&otp, kDifOtpCtrlPartitionSecret2,
174 &is_computed));
175 if (is_computed) {
176 uint64_t digest;
177 TRY(dif_otp_ctrl_get_digest(&otp, kDifOtpCtrlPartitionSecret2, &digest));
178 LOG_INFO("OTP partition locked. Digest: %x-%x", ((uint32_t *)&digest)[0],
179 ((uint32_t *)&digest)[1]);
180 return OK_STATUS();
181 }
182
183 return otp_ctrl_testutils_lock_partition(&otp, kDifOtpCtrlPartitionSecret2,
184 0);
185}
186
187static status_t dif_init(dif_keymgr_dpe_t *keymgr_dpe, dif_kmac_t *kmac) {
188 // Initialize KMAC in preparation for keymgr use.
189 TRY(dif_kmac_init(mmio_region_from_addr(TOP_EARLGREY_KMAC_BASE_ADDR), kmac));
190
191 // We shouldn't use the KMAC block's default entropy setting for keymgr, so
192 // configure it to use software entropy (and a sideloaded key, although it
193 // shouldn't matter here and tests should reconfigure if needed).
194 TRY(kmac_testutils_config(kmac, /*sideload=*/true));
195
196 // Initialize keymgr context.
197 TRY(dif_keymgr_dpe_init(
198 mmio_region_from_addr(TOP_EARLGREY_KEYMGR_DPE_BASE_ADDR), keymgr_dpe));
199 return OK_STATUS();
200}
201
202/**
203 * Wrapper around the erase slot call.
204 */
205status_t keymgr_dpe_testutils_erase_slot(
206 const dif_keymgr_dpe_t *keymgr_dpe,
207 const dif_keymgr_dpe_erase_params_t *params) {
208 TRY(dif_keymgr_dpe_erase_slot(keymgr_dpe, params));
209 return keymgr_dpe_testutils_wait_for_operation_done(keymgr_dpe);
210}
211
212status_t keymgr_dpe_initialize_sim_dv(dif_keymgr_dpe_t *keymgr_dpe,
213 dif_kmac_t *kmac) {
214 // Initialize keymgr and advance to CreatorRootKey state.
215 TRY(keymgr_dpe_testutils_startup(keymgr_dpe, kmac));
216 LOG_INFO("Keymgr DPE generated the CreatorRootKey in slot %d",
217 kCreatorRootKeyParams.slot_dst_sel);
218 // Generate key at CreatorRootKey (to follow same sequence and reuse
219 // chip_sw_keymgr_key_derivation_vseq.sv).
220 TRY(keymgr_dpe_testutils_generate_key(keymgr_dpe, &kKeyVersionedParams));
221 LOG_INFO("Keymgr DPE generated key at CreatorRootKey State");
222
223 // Advance to OwnerIntermediateKey state and check that the state is correct.
224 // The sim_dv testbench expects this state.
225 TRY(keymgr_dpe_testutils_advance_state(keymgr_dpe, &kOwnerIntKeyParams));
226 LOG_INFO("Keymgr DPE generated the OwnerIntKey in slot %d",
227 kOwnerIntKeyParams.slot_dst_sel);
228 return OK_STATUS();
229}
230
231status_t keymgr_dpe_initialize_sival(dif_keymgr_dpe_t *keymgr_dpe,
232 dif_kmac_t *kmac) {
233 dif_keymgr_dpe_state_t keymgr_dpe_state;
234
235 // keymgr_dpe should have loaded the Creator Key after this function
236 TRY(keymgr_dpe_testutils_try_startup(keymgr_dpe, kmac, &keymgr_dpe_state));
237
238 // Advance the Creator Key to the Owner Int Key
239 TRY(keymgr_dpe_testutils_advance_state(keymgr_dpe, &kOwnerIntKeyParams));
240
241 // Advance the Owner Int Key to the Owner Key
242 TRY(keymgr_dpe_testutils_advance_state(keymgr_dpe, &kOwnerKeyParams));
243
244 return keymgr_dpe_testutils_check_state(keymgr_dpe,
245 kDifKeymgrDpeStateAvailable);
246}
247
248status_t keymgr_dpe_testutils_initialize(dif_keymgr_dpe_t *keymgr_dpe,
249 dif_kmac_t *kmac) {
251 return keymgr_dpe_initialize_sival(keymgr_dpe, kmac);
252 }
253 // All other configurations use the sim_dv initialization.
254 return keymgr_dpe_initialize_sim_dv(keymgr_dpe, kmac);
255}
256
257status_t keymgr_dpe_testutils_try_startup(
258 dif_keymgr_dpe_t *keymgr_dpe, dif_kmac_t *kmac,
259 dif_keymgr_dpe_state_t *keymgr_dpe_state) {
260 TRY(dif_init(keymgr_dpe, kmac));
261
262 // Check keymgr dpe state. If initialized, there is no need to proceed with
263 // the initialization process.
264 TRY(dif_keymgr_dpe_get_state(keymgr_dpe, keymgr_dpe_state));
265
266 TRY_CHECK(*keymgr_dpe_state != kDifKeymgrDpeStateInvalid &&
267 *keymgr_dpe_state != kDifKeymgrDpeStateDisabled,
268 "Unexpected keymgr dpe state: 0x%x", *keymgr_dpe_state);
269
270 if (*keymgr_dpe_state == kDifKeymgrDpeStateReset) {
271 TRY(keymgr_dpe_testutils_startup(keymgr_dpe, kmac));
272 TRY(dif_keymgr_dpe_get_state(keymgr_dpe, keymgr_dpe_state));
273 }
274
275 return OK_STATUS();
276}
277
278status_t keymgr_dpe_testutils_init_nvm_then_reset(void) {
279 dif_rstmgr_t rstmgr;
280 dif_otp_ctrl_t otp_ctrl;
281
282 TRY(dif_rstmgr_init(mmio_region_from_addr(TOP_EARLGREY_RSTMGR_BASE_ADDR),
283 &rstmgr));
284 const dif_rstmgr_reset_info_bitfield_t reset_info =
285 rstmgr_testutils_reason_get();
286
287 // POR reset.
288 if (reset_info == kDifRstmgrResetInfoPor) {
289 LOG_INFO("Powered up for the first time, program flash");
290
291 TRY(dif_otp_ctrl_init(
292 mmio_region_from_addr(TOP_EARLGREY_OTP_CTRL_CORE_BASE_ADDR),
293 &otp_ctrl));
294
295 bool secret2_computed = false;
296 TRY(dif_otp_ctrl_is_digest_computed(&otp_ctrl, kDifOtpCtrlPartitionSecret2,
297 &secret2_computed));
298
299 // Only initialise the creator secret if `SECRET2` digest has not been
300 // computed.
301 const keymgr_dpe_testutils_secret_t *creator_secret = NULL;
302 if (!secret2_computed) {
303 creator_secret = &kCreatorSecret;
304 }
305 TRY(keymgr_dpe_testutils_nvm_init(creator_secret, &kOwnerSecret));
306
307 TRY(check_lock_otp_partition());
308
309 // Reboot device.
310 LOG_INFO(
311 "Requesting a reset to make OTP partitions accessible to keymgr DPE");
312 rstmgr_testutils_reason_clear();
313 TRY(dif_rstmgr_software_device_reset(&rstmgr));
314
315 // Wait here until device reset.
316 wait_for_interrupt();
317
318 // Should never reach this.
319 return INTERNAL();
320
321 } else {
322 // Not POR reset: this function has done its job (or can't run because it's
323 // supposed to run after POR).
324 return OK_STATUS();
325 }
326}
327
328status_t keymgr_dpe_testutils_startup(dif_keymgr_dpe_t *keymgr_dpe,
329 dif_kmac_t *kmac) {
330 dif_rstmgr_t rstmgr;
331
332 // Check the last word of the retention SRAM creator area to determine the
333 // type of the ROM.
334 bool is_using_test_rom =
335 retention_sram_get()
336 ->creator
337 .reserved[ARRAYSIZE((retention_sram_t){0}.creator.reserved) - 1] ==
339
340 // Only init NVM when run from the test_rom. Real ROM should already
341 // have loaded all necessary secrets.
342 if (is_using_test_rom) {
343 TRY(keymgr_dpe_testutils_init_nvm_then_reset());
344
345 TRY(dif_rstmgr_init(mmio_region_from_addr(TOP_EARLGREY_RSTMGR_BASE_ADDR),
346 &rstmgr));
347 const dif_rstmgr_reset_info_bitfield_t info = rstmgr_testutils_reason_get();
348
349 TRY_CHECK(info == kDifRstmgrResetInfoSw, "Unexpected reset reason: %08x",
350 info);
351 }
352
353 LOG_INFO("Initializing entropy complex in Auto mode");
354
355 TRY(entropy_testutils_auto_mode_init());
356
357 TRY(dif_init(keymgr_dpe, kmac));
358
359 // Advance to CreatorRootKey state.
360 if (is_using_test_rom) {
361 // Verify keymgr_dpe state and load UDS into predefined hw slot
362 LOG_INFO("Using test_rom, setting inputs and advancing state...");
363 TRY(keymgr_dpe_testutils_check_state(keymgr_dpe, kDifKeymgrDpeStateReset));
364 TRY(keymgr_dpe_testutils_initial_load_uds(keymgr_dpe, &kInitialParams));
365 TRY(keymgr_dpe_testutils_check_state(keymgr_dpe,
366 kDifKeymgrDpeStateAvailable));
367 // DV sync message (keymgr_dpe_key_derivation_vseq)
368 LOG_INFO("Keymgr DPE loaded the UDS and entered Available state.");
369
370 // Generate the creator root key
371 TRY(keymgr_dpe_testutils_advance_state(keymgr_dpe, &kCreatorRootKeyParams));
372 LOG_INFO("Keymgr DPE testutils derived the CreatorRootKey");
373 } else {
374 LOG_INFO("Using ROM");
375 LOG_INFO(
376 "The Keymgr DPE should already contain the derived CreatorRootKey");
377 }
378
379 // Key generation is not really necessary for all tests, but it is
380 // added to make sure each test using this function is also compatible with
381 // the DV_WAIT sequences from keymgr_key_derivation vseq
382 TRY(keymgr_dpe_testutils_generate_key(keymgr_dpe, &kKeyVersionedParams));
383 LOG_INFO("Keymgr DPE generated sw key from the CreatorRootKey");
384
385 return OK_STATUS();
386}
387
388/**
389 * Wrapper around the initial advance call. It is not possible to subsidize
390 * this call with a normal advance call as the rtl does not handle them
391 * equally. If writing to any lockable register (sw-binding, max key version,
392 * policy register) then these locks are not removed after the initial advance
393 * call completes.
394 */
395// TODO(#30665): Verify if the max key version needs to be written here too!
396// When loading the UDS the RTL fetches the max key version from the SW
397// register. Verify that the lock is released when the version register is
398// locked.
399status_t keymgr_dpe_testutils_initial_load_uds(
400 const dif_keymgr_dpe_t *keymgr_dpe,
401 const dif_keymgr_dpe_advance_params_t *params) {
402 TRY(dif_keymgr_dpe_initialize(keymgr_dpe, params->slot_dst_sel));
403 return keymgr_dpe_testutils_wait_for_operation_done(keymgr_dpe);
404}
405
406status_t keymgr_dpe_testutils_advance_state(
407 const dif_keymgr_dpe_t *keymgr_dpe,
408 const dif_keymgr_dpe_advance_params_t *params) {
409 TRY(dif_keymgr_dpe_advance_state(keymgr_dpe, params));
410 return keymgr_dpe_testutils_wait_for_operation_done(keymgr_dpe);
411}
412
413status_t keymgr_dpe_testutils_check_state(
414 const dif_keymgr_dpe_t *keymgr_dpe,
415 const dif_keymgr_dpe_state_t exp_state) {
416 dif_keymgr_dpe_state_t act_state;
417 TRY(dif_keymgr_dpe_get_state(keymgr_dpe, &act_state));
418 TRY_CHECK(act_state == exp_state,
419 "Keymgr DPE in unexpected state: %x, expected to be %x", act_state,
420 exp_state);
421 return OK_STATUS();
422}
423
424status_t keymgr_dpe_testutils_generate_key(
425 const dif_keymgr_dpe_t *keymgr_dpe,
426 const dif_keymgr_dpe_generate_params_t *params) {
427 TRY(dif_keymgr_dpe_generate(keymgr_dpe, params));
428 return keymgr_dpe_testutils_wait_for_operation_done(keymgr_dpe);
429}
430
431status_t keymgr_dpe_testutils_disable(const dif_keymgr_dpe_t *keymgr_dpe) {
432 TRY(dif_keymgr_dpe_disable(keymgr_dpe));
433 TRY(keymgr_dpe_testutils_wait_for_operation_done(keymgr_dpe));
434 return keymgr_dpe_testutils_check_state(keymgr_dpe,
435 kDifKeymgrDpeStateDisabled);
436}
437
438status_t keymgr_dpe_testutils_wait_for_operation_done(
439 const dif_keymgr_dpe_t *keymgr_dpe) {
441 do {
442 TRY(dif_keymgr_dpe_get_status_codes(keymgr_dpe, &status));
443 } while (status == 0);
444 // If status code indicate any error (not only idle flag is set) then this
445 // try_check will fail!
446 TRY_CHECK(status == kDifKeymgrDpeStatusCodeIdle, "Unexpected status: %x",
447 status);
448 return OK_STATUS();
449}
450
451status_t keymgr_dpe_testutils_state_string_get(
452 const dif_keymgr_dpe_t *keymgr_dpe, const char **stage_name) {
454 TRY(dif_keymgr_dpe_get_state(keymgr_dpe, &state));
455
456 if (state >= ARRAYSIZE(kKeymgrStageNames)) {
457 *stage_name = NULL;
458 return INTERNAL();
459 }
460
461 *stage_name = kKeymgrStageNames[state];
462 return OK_STATUS();
463}
464
465status_t keymgr_dpe_testutils_clear_sideload_key(
466 const dif_keymgr_dpe_t *keymgr_dpe,
468 TRY(dif_keymgr_dpe_clear_sideload_key(keymgr_dpe, clear_dest));
469 return OK_STATUS();
470}
471#else
472#error "[Keymgr_dpe, testutils] None of the supported tops defined!"
473#endif