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