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
15#include "sw/device/lib/testing/entropy_testutils.h"
16#include "sw/device/lib/testing/flash_ctrl_testutils.h"
17#include "sw/device/lib/testing/kmac_testutils.h"
18#include "sw/device/lib/testing/otp_ctrl_testutils.h"
19#include "sw/device/lib/testing/rstmgr_testutils.h"
20#include "sw/device/lib/testing/test_framework/check.h"
22#include "sw/device/silicon_creator/lib/drivers/retention_sram.h"
23
25
26#define MODULE_ID MAKE_MODULE_ID('k', 'm', 't')
27
28enum {
29 /** Flash Secret partition ID. */
30 kFlashInfoPartitionId = 0,
31
32 /** Secret partition flash bank ID. */
33 kFlashInfoBankId = 0,
34
35 /** Creator Secret flash info page ID. */
36 kFlashInfoPageIdCreatorSecret = 1,
37
38 /** Owner Secret flash info page ID. */
39 kFlashInfoPageIdOwnerSecret = 2,
40};
41
42const static char *kKeymgrStageNames[] = {
43 [kDifKeymgrStateReset] = "Reset",
45 [kDifKeymgrStateCreatorRootKey] = "CreatorRootKey",
47 [kDifKeymgrStateOwnerRootKey] = "OwnerKey",
48 [kDifKeymgrStateDisabled] = "Disabled",
49 [kDifKeymgrStateInvalid] = "Invalid",
50};
51
52static status_t write_info_page(dif_flash_ctrl_state_t *flash, uint32_t page_id,
53 const keymgr_testutils_secret_t *data,
54 bool scramble) {
55 uint32_t address = 0;
56 if (scramble) {
57 TRY(flash_ctrl_testutils_info_region_scrambled_setup(
58 flash, page_id, kFlashInfoBankId, kFlashInfoPartitionId, &address));
59 } else {
60 TRY(flash_ctrl_testutils_info_region_setup(
61 flash, page_id, kFlashInfoBankId, kFlashInfoPartitionId, &address));
62 }
63
64 TRY(flash_ctrl_testutils_erase_and_write_page(
65 flash, address, kFlashInfoPartitionId, data->value,
66 kDifFlashCtrlPartitionTypeInfo, ARRAYSIZE(data->value)));
67
68 keymgr_testutils_secret_t readback_data;
69 TRY(flash_ctrl_testutils_read(
70 flash, address, kFlashInfoPartitionId, readback_data.value,
71 kDifFlashCtrlPartitionTypeInfo, ARRAYSIZE(readback_data.value), 0));
72 TRY_CHECK(memcmp(data->value, readback_data.value, sizeof(data->value)) == 0);
73 return OK_STATUS();
74}
75
76status_t keymgr_testutils_flash_init(
78 const keymgr_testutils_secret_t *creator_secret,
79 const keymgr_testutils_secret_t *owner_secret) {
80 // Initialize flash secrets.
81 write_info_page(flash, kFlashInfoPageIdCreatorSecret, creator_secret,
82 /*scramble=*/true);
83 write_info_page(flash, kFlashInfoPageIdOwnerSecret, owner_secret,
84 /*scramble=*/true);
85 return OK_STATUS();
86}
87
88static status_t check_lock_otp_partition(void) {
90 TRY(dif_otp_ctrl_init(
91 mmio_region_from_addr(TOP_EARLGREY_OTP_CTRL_CORE_BASE_ADDR), &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
193 TRY(dif_rstmgr_init(mmio_region_from_addr(TOP_EARLGREY_RSTMGR_AON_BASE_ADDR),
194 &rstmgr));
195 const dif_rstmgr_reset_info_bitfield_t reset_info =
196 rstmgr_testutils_reason_get();
197
198 // POR reset.
199 if (reset_info == kDifRstmgrResetInfoPor) {
200 LOG_INFO("Powered up for the first time, program flash");
201
202 TRY(dif_flash_ctrl_init_state(
203 &flash, mmio_region_from_addr(TOP_EARLGREY_FLASH_CTRL_CORE_BASE_ADDR)));
204
205 TRY(keymgr_testutils_flash_init(&flash, &kCreatorSecret, &kOwnerSecret));
206
207 TRY(check_lock_otp_partition());
208
209 // Reboot device.
210 LOG_INFO("Requesting a reset to make OTP partitions accessible to keymgr");
211 rstmgr_testutils_reason_clear();
212 TRY(dif_rstmgr_software_device_reset(&rstmgr));
213
214 // Wait here until device reset.
215 wait_for_interrupt();
216
217 // Should never reach this.
218 return INTERNAL();
219
220 } else {
221 // Not POR reset: this function has done its job (or can't run because it's
222 // supposed to run after POR).
223 return OK_STATUS();
224 }
225}
226
227status_t keymgr_testutils_startup(dif_keymgr_t *keymgr, dif_kmac_t *kmac) {
228 dif_rstmgr_t rstmgr;
229
230 // Check the last word of the retention SRAM creator area to determine the
231 // type of the ROM.
232 bool is_using_test_rom =
233 retention_sram_get()
234 ->creator
235 .reserved[ARRAYSIZE((retention_sram_t){0}.creator.reserved) - 1] ==
237
238 TRY(keymgr_testutils_init_nvm_then_reset());
239
240 TRY(dif_rstmgr_init(mmio_region_from_addr(TOP_EARLGREY_RSTMGR_AON_BASE_ADDR),
241 &rstmgr));
242 const dif_rstmgr_reset_info_bitfield_t info = rstmgr_testutils_reason_get();
243
244 TRY_CHECK(info == kDifRstmgrResetInfoSw, "Unexpected reset reason: %08x",
245 info);
246
247 LOG_INFO("Initializing entropy complex in Auto mode");
248
249 TRY(entropy_testutils_auto_mode_init());
250
251 LOG_INFO("Powered up for the second time, actuate keymgr and perform test.");
252
253 TRY(dif_init(keymgr, kmac));
254
255 // Advance to Initialized state.
256 TRY(keymgr_testutils_check_state(keymgr, kDifKeymgrStateReset));
257 TRY(keymgr_testutils_advance_state(keymgr, NULL));
258 TRY(keymgr_testutils_check_state(keymgr, kDifKeymgrStateInitialized));
259 LOG_INFO("Keymgr entered Init State");
260
261 // Advance to CreatorRootKey state.
262 if (is_using_test_rom) {
263 LOG_INFO("Using test_rom, setting inputs and advancing state...");
264 TRY(keymgr_testutils_advance_state(keymgr, &kCreatorParams));
265 } else {
266 LOG_INFO("Using rom, only advancing state...");
267 TRY(dif_keymgr_advance_state_raw(keymgr));
268 TRY(keymgr_testutils_wait_for_operation_done(keymgr));
269 }
270 TRY(keymgr_testutils_check_state(keymgr, kDifKeymgrStateCreatorRootKey));
271 LOG_INFO("Keymgr entered CreatorRootKey State");
272
273 // Identity generation is not really necessary for all tests, but it is
274 // added to make sure each test using this function is also compatible with
275 // the DV_WAIT sequences from keymgr_key_derivation vseq
276 TRY(keymgr_testutils_generate_identity(
277 keymgr,
279 LOG_INFO("Keymgr generated identity at CreatorRootKey State");
280
281 return OK_STATUS();
282}
283
284status_t keymgr_testutils_advance_state(
285 const dif_keymgr_t *keymgr, const dif_keymgr_state_params_t *params) {
286 TRY(dif_keymgr_advance_state(keymgr, params));
287 return keymgr_testutils_wait_for_operation_done(keymgr);
288}
289
290status_t keymgr_testutils_check_state(const dif_keymgr_t *keymgr,
291 const dif_keymgr_state_t exp_state) {
292 dif_keymgr_state_t act_state;
293 TRY(dif_keymgr_get_state(keymgr, &act_state));
294 TRY_CHECK(act_state == exp_state,
295 "Keymgr in unexpected state: %x, expected to be %x", act_state,
296 exp_state);
297 return OK_STATUS();
298}
299
300status_t keymgr_testutils_generate_identity(
301 const dif_keymgr_t *keymgr,
303 TRY(dif_keymgr_generate_identity_seed(keymgr, params));
304 return keymgr_testutils_wait_for_operation_done(keymgr);
305}
306
307status_t keymgr_testutils_generate_versioned_key(
308 const dif_keymgr_t *keymgr,
310 TRY(dif_keymgr_generate_versioned_key(keymgr, params));
311 return keymgr_testutils_wait_for_operation_done(keymgr);
312}
313
314status_t keymgr_testutils_disable(const dif_keymgr_t *keymgr) {
315 TRY(dif_keymgr_disable(keymgr));
316 return keymgr_testutils_wait_for_operation_done(keymgr);
317}
318
319status_t keymgr_testutils_wait_for_operation_done(const dif_keymgr_t *keymgr) {
321 do {
322 TRY(dif_keymgr_get_status_codes(keymgr, &status));
323 } while (status == 0);
324 TRY_CHECK(status == kDifKeymgrStatusCodeIdle, "Unexpected status: %x",
325 status);
326 return OK_STATUS();
327}
328
329status_t keymgr_testutils_max_key_version_get(const dif_keymgr_t *keymgr,
330 uint32_t *max_key_version) {
331 dif_keymgr_state_t keymgr_state;
332 TRY(dif_keymgr_get_state(keymgr, &keymgr_state));
333
334 if (keymgr_state == kDifKeymgrStateInvalid ||
335 keymgr_state == kDifKeymgrStateDisabled ||
336 keymgr_state == kDifKeymgrStateReset) {
337 LOG_INFO("Unexpected keymgr state: 0x%x", keymgr_state);
338 return INTERNAL();
339 }
340
341 dif_keymgr_max_key_version_t versions;
342 TRY(dif_keymgr_read_max_key_version(keymgr, &versions));
343
344 switch (keymgr_state) {
346 *max_key_version = versions.creator_max_key_version;
347 break;
349 *max_key_version = versions.owner_int_max_key_version;
350 break;
352 *max_key_version = versions.owner_max_key_version;
353 break;
354 default:
355 return INTERNAL();
356 }
357
358 return OK_STATUS();
359}
360
361status_t keymgr_testutils_state_string_get(const dif_keymgr_t *keymgr,
362 const char **stage_name) {
363 dif_keymgr_state_t state;
364 CHECK_DIF_OK(dif_keymgr_get_state(keymgr, &state));
365
366 if (state >= ARRAYSIZE(kKeymgrStageNames)) {
367 *stage_name = NULL;
368 return INTERNAL();
369 }
370
371 *stage_name = kKeymgrStageNames[state];
372 return OK_STATUS();
373}