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_EARLGREY_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_EARLGREY_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_EARLGREY_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_EARLGREY_FLASH_CTRL_CORE_BASE_ADDR)));
205 TRY(dif_otp_ctrl_init(
206 mmio_region_from_addr(TOP_EARLGREY_OTP_CTRL_CORE_BASE_ADDR),
207 &otp_ctrl));
208
209 bool secret2_computed = false;
210 TRY(dif_otp_ctrl_is_digest_computed(&otp_ctrl, kDifOtpCtrlPartitionSecret2,
211 &secret2_computed));
212
213 // Only initialise the creator secret if `SECRET2` digest has not been
214 // computed. `flash_ctrl` will throw a recoverable error if we try to write
215 // this afterwards.
216 const keymgr_testutils_secret_t *creator_secret = NULL;
217 if (!secret2_computed) {
218 creator_secret = &kCreatorSecret;
219 }
220 TRY(keymgr_testutils_flash_init(&flash, creator_secret, &kOwnerSecret));
221
222 TRY(check_lock_otp_partition());
223
224 // Reboot device.
225 LOG_INFO("Requesting a reset to make OTP partitions accessible to keymgr");
226 rstmgr_testutils_reason_clear();
227 TRY(dif_rstmgr_software_device_reset(&rstmgr));
228
229 // Wait here until device reset.
230 wait_for_interrupt();
231
232 // Should never reach this.
233 return INTERNAL();
234
235 } else {
236 // Not POR reset: this function has done its job (or can't run because it's
237 // supposed to run after POR).
238 return OK_STATUS();
239 }
240}
241
242status_t keymgr_testutils_startup(dif_keymgr_t *keymgr, dif_kmac_t *kmac) {
243 dif_rstmgr_t rstmgr;
244
245 // Check the last word of the retention SRAM creator area to determine the
246 // type of the ROM.
247 bool is_using_test_rom =
248 retention_sram_get()
249 ->creator
250 .reserved[ARRAYSIZE((retention_sram_t){0}.creator.reserved) - 1] ==
252
253 TRY(keymgr_testutils_init_nvm_then_reset());
254
255 TRY(dif_rstmgr_init(mmio_region_from_addr(TOP_EARLGREY_RSTMGR_AON_BASE_ADDR),
256 &rstmgr));
257 const dif_rstmgr_reset_info_bitfield_t info = rstmgr_testutils_reason_get();
258
259 TRY_CHECK(info == kDifRstmgrResetInfoSw, "Unexpected reset reason: %08x",
260 info);
261
262 LOG_INFO("Initializing entropy complex in Auto mode");
263
264 TRY(entropy_testutils_auto_mode_init());
265
266 LOG_INFO("Powered up for the second time, actuate keymgr and perform test.");
267
268 TRY(dif_init(keymgr, kmac));
269
270 // Advance to Initialized state.
271 TRY(keymgr_testutils_check_state(keymgr, kDifKeymgrStateReset));
272 TRY(keymgr_testutils_advance_state(keymgr, NULL));
273 TRY(keymgr_testutils_check_state(keymgr, kDifKeymgrStateInitialized));
274 LOG_INFO("Keymgr entered Init State");
275
276 // Advance to CreatorRootKey state.
277 if (is_using_test_rom) {
278 LOG_INFO("Using test_rom, setting inputs and advancing state...");
279 TRY(keymgr_testutils_advance_state(keymgr, &kCreatorParams));
280 } else {
281 LOG_INFO("Using rom, only advancing state...");
282 TRY(dif_keymgr_advance_state_raw(keymgr));
283 TRY(keymgr_testutils_wait_for_operation_done(keymgr));
284 }
285 TRY(keymgr_testutils_check_state(keymgr, kDifKeymgrStateCreatorRootKey));
286 LOG_INFO("Keymgr entered CreatorRootKey State");
287
288 // Identity generation is not really necessary for all tests, but it is
289 // added to make sure each test using this function is also compatible with
290 // the DV_WAIT sequences from keymgr_key_derivation vseq
291 TRY(keymgr_testutils_generate_identity(
292 keymgr,
294 LOG_INFO("Keymgr generated identity at CreatorRootKey State");
295
296 return OK_STATUS();
297}
298
299status_t keymgr_testutils_advance_state(
300 const dif_keymgr_t *keymgr, const dif_keymgr_state_params_t *params) {
301 TRY(dif_keymgr_advance_state(keymgr, params));
302 return keymgr_testutils_wait_for_operation_done(keymgr);
303}
304
305status_t keymgr_testutils_check_state(const dif_keymgr_t *keymgr,
306 const dif_keymgr_state_t exp_state) {
307 dif_keymgr_state_t act_state;
308 TRY(dif_keymgr_get_state(keymgr, &act_state));
309 TRY_CHECK(act_state == exp_state,
310 "Keymgr in unexpected state: %x, expected to be %x", act_state,
311 exp_state);
312 return OK_STATUS();
313}
314
315status_t keymgr_testutils_generate_identity(
316 const dif_keymgr_t *keymgr,
318 TRY(dif_keymgr_generate_identity_seed(keymgr, params));
319 return keymgr_testutils_wait_for_operation_done(keymgr);
320}
321
322status_t keymgr_testutils_generate_versioned_key(
323 const dif_keymgr_t *keymgr,
325 TRY(dif_keymgr_generate_versioned_key(keymgr, params));
326 return keymgr_testutils_wait_for_operation_done(keymgr);
327}
328
329status_t keymgr_testutils_disable(const dif_keymgr_t *keymgr) {
330 TRY(dif_keymgr_disable(keymgr));
331 return keymgr_testutils_wait_for_operation_done(keymgr);
332}
333
334status_t keymgr_testutils_wait_for_operation_done(const dif_keymgr_t *keymgr) {
336 do {
337 TRY(dif_keymgr_get_status_codes(keymgr, &status));
338 } while (status == 0);
339 TRY_CHECK(status == kDifKeymgrStatusCodeIdle, "Unexpected status: %x",
340 status);
341 return OK_STATUS();
342}
343
344status_t keymgr_testutils_max_key_version_get(const dif_keymgr_t *keymgr,
345 uint32_t *max_key_version) {
346 dif_keymgr_state_t keymgr_state;
347 TRY(dif_keymgr_get_state(keymgr, &keymgr_state));
348
349 if (keymgr_state == kDifKeymgrStateInvalid ||
350 keymgr_state == kDifKeymgrStateDisabled ||
351 keymgr_state == kDifKeymgrStateReset) {
352 LOG_INFO("Unexpected keymgr state: 0x%x", keymgr_state);
353 return INTERNAL();
354 }
355
356 dif_keymgr_max_key_version_t versions;
357 TRY(dif_keymgr_read_max_key_version(keymgr, &versions));
358
359 switch (keymgr_state) {
361 *max_key_version = versions.creator_max_key_version;
362 break;
364 *max_key_version = versions.owner_int_max_key_version;
365 break;
367 *max_key_version = versions.owner_max_key_version;
368 break;
369 default:
370 return INTERNAL();
371 }
372
373 return OK_STATUS();
374}
375
376status_t keymgr_testutils_state_string_get(const dif_keymgr_t *keymgr,
377 const char **stage_name) {
378 dif_keymgr_state_t state;
379 CHECK_DIF_OK(dif_keymgr_get_state(keymgr, &state));
380
381 if (state >= ARRAYSIZE(kKeymgrStageNames)) {
382 *stage_name = NULL;
383 return INTERNAL();
384 }
385
386 *stage_name = kKeymgrStageNames[state];
387 return OK_STATUS();
388}