Pavona Software APIs
keymgr_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#include "sw/device/lib/testing/keymgr_testutils.h"
6
7#include "hw/top/dt/otp_ctrl.h"
14#include "sw/device/lib/testing/entropy_testutils.h"
15#include "sw/device/lib/testing/flash_ctrl_testutils.h"
16#include "sw/device/lib/testing/kmac_testutils.h"
17#include "sw/device/lib/testing/otp_ctrl_testutils.h"
18#include "sw/device/lib/testing/rstmgr_testutils.h"
19#include "sw/device/lib/testing/test_framework/check.h"
21#include "sw/device/silicon_creator/lib/drivers/retention_sram.h"
22
24
25#define MODULE_ID MAKE_MODULE_ID('k', 'm', 't')
26
27enum {
28 /** Flash Secret partition ID. */
29 kFlashInfoPartitionId = 0,
30
31 /** Secret partition flash bank ID. */
32 kFlashInfoBankId = 0,
33
34 /** Creator Secret flash info page ID. */
35 kFlashInfoPageIdCreatorSecret = 1,
36
37 /** Owner Secret flash info page ID. */
38 kFlashInfoPageIdOwnerSecret = 2,
39};
40
41const static char *kKeymgrStageNames[] = {
42 [kDifKeymgrStateReset] = "Reset",
44 [kDifKeymgrStateCreatorRootKey] = "CreatorRootKey",
46 [kDifKeymgrStateOwnerRootKey] = "OwnerKey",
47 [kDifKeymgrStateDisabled] = "Disabled",
48 [kDifKeymgrStateInvalid] = "Invalid",
49};
50
51static status_t write_info_page(dif_flash_ctrl_state_t *flash, uint32_t page_id,
52 const keymgr_testutils_secret_t *data,
53 bool scramble) {
54 uint32_t address = 0;
55 if (scramble) {
56 TRY(flash_ctrl_testutils_info_region_scrambled_setup(
57 flash, page_id, kFlashInfoBankId, kFlashInfoPartitionId, &address));
58 } else {
59 TRY(flash_ctrl_testutils_info_region_setup(
60 flash, page_id, kFlashInfoBankId, kFlashInfoPartitionId, &address));
61 }
62
63 TRY(flash_ctrl_testutils_erase_and_write_page(
64 flash, address, kFlashInfoPartitionId, data->value,
65 kDifFlashCtrlPartitionTypeInfo, ARRAYSIZE(data->value)));
66
67 keymgr_testutils_secret_t readback_data;
68 TRY(flash_ctrl_testutils_read(
69 flash, address, kFlashInfoPartitionId, readback_data.value,
70 kDifFlashCtrlPartitionTypeInfo, ARRAYSIZE(readback_data.value), 0));
71 TRY_CHECK(memcmp(data->value, readback_data.value, sizeof(data->value)) == 0);
72 return OK_STATUS();
73}
74
75status_t keymgr_testutils_flash_init(
77 const keymgr_testutils_secret_t *creator_secret,
78 const keymgr_testutils_secret_t *owner_secret) {
79 // Initialize flash secrets.
80 if (creator_secret) {
81 write_info_page(flash, kFlashInfoPageIdCreatorSecret, creator_secret,
82 /*scramble=*/true);
83 }
84 write_info_page(flash, kFlashInfoPageIdOwnerSecret, owner_secret,
85 /*scramble=*/true);
86 return OK_STATUS();
87}
88
89static status_t check_lock_otp_partition(void) {
91 TRY(dif_otp_ctrl_init_from_dt(kDtOtpCtrl, &otp));
92
93 bool is_computed;
94 TRY(dif_otp_ctrl_is_digest_computed(&otp, kDifOtpCtrlPartitionSecret2,
95 &is_computed));
96 if (is_computed) {
97 uint64_t digest;
98 TRY(dif_otp_ctrl_get_digest(&otp, kDifOtpCtrlPartitionSecret2, &digest));
99 LOG_INFO("OTP partition locked. Digest: %x-%x", ((uint32_t *)&digest)[0],
100 ((uint32_t *)&digest)[1]);
101 return OK_STATUS();
102 }
103
104 TRY(otp_ctrl_testutils_lock_partition(&otp, kDifOtpCtrlPartitionSecret2, 0));
105 return OK_STATUS();
106}
107
108static status_t dif_init(dif_keymgr_t *keymgr, dif_kmac_t *kmac) {
109 // Initialize KMAC in preparation for keymgr use.
110 TRY(dif_kmac_init(mmio_region_from_addr(TOP_EGRET_KMAC_BASE_ADDR), kmac));
111
112 // We shouldn't use the KMAC block's default entropy setting for keymgr, so
113 // configure it to use software entropy (and a sideloaded key, although it
114 // shouldn't matter here and tests should reconfigure if needed).
115 TRY(kmac_testutils_config(kmac, /*sideload=*/true));
116
117 // Initialize keymgr context.
118 TRY(dif_keymgr_init(mmio_region_from_addr(TOP_EGRET_KEYMGR_BASE_ADDR),
119 keymgr));
120 return OK_STATUS();
121}
122
123status_t keymgr_initialize_sim_dv(dif_keymgr_t *keymgr, dif_kmac_t *kmac) {
124 // Initialize keymgr and advance to CreatorRootKey state.
125 TRY(keymgr_testutils_startup(keymgr, kmac));
126 LOG_INFO("Keymgr entered CreatorRootKey State");
127 // Generate identity at CreatorRootKey (to follow same sequence and reuse
128 // chip_sw_keymgr_key_derivation_vseq.sv).
129 TRY(keymgr_testutils_generate_identity(
130 keymgr,
132 LOG_INFO("Keymgr generated identity at CreatorRootKey State");
133
134 // Advance to OwnerIntermediateKey state and check that the state is correct.
135 // The sim_dv testbench expects this state.
136 TRY(keymgr_testutils_advance_state(keymgr, &kOwnerIntParams));
137 TRY(keymgr_testutils_check_state(keymgr,
139 LOG_INFO("Keymgr entered OwnerIntKey State");
140 return OK_STATUS();
141}
142
143status_t keymgr_initialize_sival(dif_keymgr_t *keymgr, dif_kmac_t *kmac) {
144 dif_keymgr_state_t keymgr_state;
145 TRY(keymgr_testutils_try_startup(keymgr, kmac, &keymgr_state));
146
147 if (keymgr_state == kDifKeymgrStateInitialized) {
148 TRY(keymgr_testutils_advance_state(keymgr, &kOwnerIntParams));
149 TRY(dif_keymgr_get_state(keymgr, &keymgr_state));
150 }
151
152 if (keymgr_state == kDifKeymgrStateOwnerIntermediateKey) {
153 TRY(keymgr_testutils_advance_state(keymgr, &kOwnerRootKeyParams));
154 }
155
156 return keymgr_testutils_check_state(keymgr, kDifKeymgrStateOwnerRootKey);
157}
158
159status_t keymgr_testutils_initialize(dif_keymgr_t *keymgr, dif_kmac_t *kmac) {
161 return keymgr_initialize_sival(keymgr, kmac);
162 }
163 // All other configurations use the sim_dv initialization.
164 return keymgr_initialize_sim_dv(keymgr, kmac);
165}
166
167status_t keymgr_testutils_try_startup(dif_keymgr_t *keymgr, dif_kmac_t *kmac,
168 dif_keymgr_state_t *keymgr_state) {
169 TRY(dif_init(keymgr, kmac));
170
171 // Check keymgr state. If initialized, there is no need to proceed with
172 // the initialization process.
173 TRY(dif_keymgr_get_state(keymgr, keymgr_state));
174
175 if (*keymgr_state == kDifKeymgrStateInvalid ||
176 *keymgr_state == kDifKeymgrStateDisabled) {
177 LOG_INFO("Unexpected keymgr state: 0x%x", keymgr_state);
178 return INTERNAL();
179 }
180
181 if (*keymgr_state == kDifKeymgrStateReset) {
182 TRY(keymgr_testutils_startup(keymgr, kmac));
183 TRY(dif_keymgr_get_state(keymgr, keymgr_state));
184 }
185
186 return OK_STATUS();
187}
188
189status_t keymgr_testutils_init_nvm_then_reset(void) {
191 dif_rstmgr_t rstmgr;
192 dif_otp_ctrl_t otp_ctrl;
193
194 TRY(dif_rstmgr_init(mmio_region_from_addr(TOP_EGRET_RSTMGR_AON_BASE_ADDR),
195 &rstmgr));
196 const dif_rstmgr_reset_info_bitfield_t reset_info =
197 rstmgr_testutils_reason_get();
198
199 // POR reset.
200 if (reset_info == kDifRstmgrResetInfoPor) {
201 LOG_INFO("Powered up for the first time, program flash");
202
203 TRY(dif_flash_ctrl_init_state(
204 &flash, mmio_region_from_addr(TOP_EGRET_FLASH_CTRL_CORE_BASE_ADDR)));
205 TRY(dif_otp_ctrl_init(
206 mmio_region_from_addr(TOP_EGRET_OTP_CTRL_CORE_BASE_ADDR), &otp_ctrl));
207
208 bool secret2_computed = false;
209 TRY(dif_otp_ctrl_is_digest_computed(&otp_ctrl, kDifOtpCtrlPartitionSecret2,
210 &secret2_computed));
211
212 // Only initialise the creator secret if `SECRET2` digest has not been
213 // computed. `flash_ctrl` will throw a recoverable error if we try to write
214 // this afterwards.
215 const keymgr_testutils_secret_t *creator_secret = NULL;
216 if (!secret2_computed) {
217 creator_secret = &kCreatorSecret;
218 }
219 TRY(keymgr_testutils_flash_init(&flash, creator_secret, &kOwnerSecret));
220
221 TRY(check_lock_otp_partition());
222
223 // Reboot device.
224 LOG_INFO("Requesting a reset to make OTP partitions accessible to keymgr");
225 rstmgr_testutils_reason_clear();
226 TRY(dif_rstmgr_software_device_reset(&rstmgr));
227
228 // Wait here until device reset.
229 wait_for_interrupt();
230
231 // Should never reach this.
232 return INTERNAL();
233
234 } else {
235 // Not POR reset: this function has done its job (or can't run because it's
236 // supposed to run after POR).
237 return OK_STATUS();
238 }
239}
240
241status_t keymgr_testutils_startup(dif_keymgr_t *keymgr, dif_kmac_t *kmac) {
242 dif_rstmgr_t rstmgr;
243
244 // Check the last word of the retention SRAM creator area to determine the
245 // type of the ROM.
246 bool is_using_test_rom =
247 retention_sram_get()
248 ->creator
249 .reserved[ARRAYSIZE((retention_sram_t){0}.creator.reserved) - 1] ==
251
252 TRY(keymgr_testutils_init_nvm_then_reset());
253
254 TRY(dif_rstmgr_init(mmio_region_from_addr(TOP_EGRET_RSTMGR_AON_BASE_ADDR),
255 &rstmgr));
256 const dif_rstmgr_reset_info_bitfield_t info = rstmgr_testutils_reason_get();
257
258 TRY_CHECK(info == kDifRstmgrResetInfoSw, "Unexpected reset reason: %08x",
259 info);
260
261 LOG_INFO("Initializing entropy complex in Auto mode");
262
263 TRY(entropy_testutils_auto_mode_init());
264
265 LOG_INFO("Powered up for the second time, actuate keymgr and perform test.");
266
267 TRY(dif_init(keymgr, kmac));
268
269 // Advance to Initialized state.
270 TRY(keymgr_testutils_check_state(keymgr, kDifKeymgrStateReset));
271 TRY(keymgr_testutils_advance_state(keymgr, NULL));
272 TRY(keymgr_testutils_check_state(keymgr, kDifKeymgrStateInitialized));
273 LOG_INFO("Keymgr entered Init State");
274
275 // Advance to CreatorRootKey state.
276 if (is_using_test_rom) {
277 LOG_INFO("Using test_rom, setting inputs and advancing state...");
278 TRY(keymgr_testutils_advance_state(keymgr, &kCreatorParams));
279 } else {
280 LOG_INFO("Using rom, only advancing state...");
281 TRY(dif_keymgr_advance_state_raw(keymgr));
282 TRY(keymgr_testutils_wait_for_operation_done(keymgr));
283 }
284 TRY(keymgr_testutils_check_state(keymgr, kDifKeymgrStateCreatorRootKey));
285 LOG_INFO("Keymgr entered CreatorRootKey State");
286
287 // Identity generation is not really necessary for all tests, but it is
288 // added to make sure each test using this function is also compatible with
289 // the DV_WAIT sequences from keymgr_key_derivation vseq
290 TRY(keymgr_testutils_generate_identity(
291 keymgr,
293 LOG_INFO("Keymgr generated identity at CreatorRootKey State");
294
295 return OK_STATUS();
296}
297
298status_t keymgr_testutils_advance_state(
299 const dif_keymgr_t *keymgr, const dif_keymgr_state_params_t *params) {
300 TRY(dif_keymgr_advance_state(keymgr, params));
301 return keymgr_testutils_wait_for_operation_done(keymgr);
302}
303
304status_t keymgr_testutils_check_state(const dif_keymgr_t *keymgr,
305 const dif_keymgr_state_t exp_state) {
306 dif_keymgr_state_t act_state;
307 TRY(dif_keymgr_get_state(keymgr, &act_state));
308 TRY_CHECK(act_state == exp_state,
309 "Keymgr in unexpected state: %x, expected to be %x", act_state,
310 exp_state);
311 return OK_STATUS();
312}
313
314status_t keymgr_testutils_generate_identity(
315 const dif_keymgr_t *keymgr,
317 TRY(dif_keymgr_generate_identity_seed(keymgr, params));
318 return keymgr_testutils_wait_for_operation_done(keymgr);
319}
320
321status_t keymgr_testutils_generate_versioned_key(
322 const dif_keymgr_t *keymgr,
324 TRY(dif_keymgr_generate_versioned_key(keymgr, params));
325 return keymgr_testutils_wait_for_operation_done(keymgr);
326}
327
328status_t keymgr_testutils_disable(const dif_keymgr_t *keymgr) {
329 TRY(dif_keymgr_disable(keymgr));
330 return keymgr_testutils_wait_for_operation_done(keymgr);
331}
332
333status_t keymgr_testutils_wait_for_operation_done(const dif_keymgr_t *keymgr) {
335 do {
336 TRY(dif_keymgr_get_status_codes(keymgr, &status));
337 } while (status == 0);
338 TRY_CHECK(status == kDifKeymgrStatusCodeIdle, "Unexpected status: %x",
339 status);
340 return OK_STATUS();
341}
342
343status_t keymgr_testutils_max_key_version_get(const dif_keymgr_t *keymgr,
344 uint32_t *max_key_version) {
345 dif_keymgr_state_t keymgr_state;
346 TRY(dif_keymgr_get_state(keymgr, &keymgr_state));
347
348 if (keymgr_state == kDifKeymgrStateInvalid ||
349 keymgr_state == kDifKeymgrStateDisabled ||
350 keymgr_state == kDifKeymgrStateReset) {
351 LOG_INFO("Unexpected keymgr state: 0x%x", keymgr_state);
352 return INTERNAL();
353 }
354
355 dif_keymgr_max_key_version_t versions;
356 TRY(dif_keymgr_read_max_key_version(keymgr, &versions));
357
358 switch (keymgr_state) {
360 *max_key_version = versions.creator_max_key_version;
361 break;
363 *max_key_version = versions.owner_int_max_key_version;
364 break;
366 *max_key_version = versions.owner_max_key_version;
367 break;
368 default:
369 return INTERNAL();
370 }
371
372 return OK_STATUS();
373}
374
375status_t keymgr_testutils_state_string_get(const dif_keymgr_t *keymgr,
376 const char **stage_name) {
377 dif_keymgr_state_t state;
378 CHECK_DIF_OK(dif_keymgr_get_state(keymgr, &state));
379
380 if (state >= ARRAYSIZE(kKeymgrStageNames)) {
381 *stage_name = NULL;
382 return INTERNAL();
383 }
384
385 *stage_name = kKeymgrStageNames[state];
386 return OK_STATUS();
387}