Software APIs
kmac_kmac_key_sideload_test.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 
11 #include "sw/device/lib/testing/keymgr_testutils.h"
12 #include "sw/device/lib/testing/kmac_testutils.h"
13 #include "sw/device/lib/testing/ret_sram_testutils.h"
14 #include "sw/device/lib/testing/rstmgr_testutils.h"
15 #include "sw/device/lib/testing/sram_ctrl_testutils.h"
16 #include "sw/device/lib/testing/test_framework/check.h"
18 #include "sw/device/silicon_creator/lib/drivers/retention_sram.h"
19 
21 
22 // The KMAC dif expects a secret key, even though if the configuration is set
23 // to use the sideloaded key then it will be ignored. We will write a software
24 // key and then ensure that the output does NOT match the expected value for
25 // this key when sideloading is used.
26 //
27 // Test taken from sample #1 here:
28 // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMAC_samples.pdf
29 static const dif_kmac_key_t kSoftwareKey = {
30  .share0 = {0x43424140, 0x47464544, 0x4B4A4948, 0x4F4E4D4C, 0x53525150,
31  0x57565554, 0x5B5A5958, 0x5F5E5D5C},
32  .share1 = {0},
33  .length = kDifKmacKeyLen256,
34 };
35 static const dif_kmac_mode_kmac_t kKmacModes[2] = {kDifKmacModeKmacLen128,
37 static const size_t kKmacOutputLen = 8;
38 static const char *kCustomString = NULL;
39 static const size_t kCustomStringLen = 0;
40 static const char kKmacMessage[] = "\x00\x01\x02\x03";
41 static const size_t kKmacMessageLen = 4;
42 
43 enum {
44  /**
45  * Retention SRAM start address (inclusive).
46  */
48 
49  kRetSramOwnerAddr = kRetSramBaseAddr + offsetof(retention_sram_t, owner),
50  kRetRamLastAddr =
51  kRetSramBaseAddr + TOP_EARLGREY_SRAM_CTRL_RET_AON_RAM_SIZE_BYTES - 1,
52 };
53 
54 static dif_keymgr_t keymgr;
55 static dif_kmac_t kmac;
56 static dif_sram_ctrl_t ret_sram;
57 static dif_rstmgr_t rstmgr;
58 
59 OTTF_DEFINE_TEST_CONFIG();
60 
61 /**
62  * Initializes all DIF handles for each peripheral used in this test.
63  */
64 static void init_peripheral_handles(void) {
65  CHECK_DIF_OK(
66  dif_kmac_init(mmio_region_from_addr(TOP_EARLGREY_KMAC_BASE_ADDR), &kmac));
67  CHECK_DIF_OK(dif_keymgr_init(
69  CHECK_DIF_OK(dif_rstmgr_init(
71  CHECK_DIF_OK(dif_sram_ctrl_init(
73  &ret_sram));
74 }
75 
76 /**
77  * KMAC key sideload test.
78  *
79  * This function is executed twice.
80  *
81  * In phase 0, KMAC outputs for kDifKmacModeKmacLen128 and
82  * kDifKmacModeKmacLen256 with a sideloaded key are computed. The outputs are
83  * stored in the retention SRAM to preserve the results. Then, the sideload key
84  * is invalidated, a new sideload key with a different salt is generated and the
85  * test checks whether KMAC can no longer reproduce the same KMAC output.
86  *
87  * Then, test_main performs a software reset.
88  *
89  * In phase 1, KMAC outputs for kDifKmacModeKmacLen128 and
90  * kDifKmacModeKmacLen256 with a sideloaded key are computed. The outputs are
91  * compared to the previous value stored in the retention SRAM.
92  *
93  * @param keymgr the key manager handle.
94  * @param kmac the kmac handle.
95  * @param test_phase the current test phase.
96  */
97 static void test_kmac_key_sideload(dif_keymgr_t *keymgr, dif_kmac_t *kmac,
98  size_t test_phase) {
99  // Configure KMAC to use the sideloaded key.
100  CHECK_STATUS_OK(kmac_testutils_config(kmac, true));
101 
102  // Generate the sideloaded key.
103  dif_keymgr_versioned_key_params_t sideload_params = kKeyVersionedParams;
104  sideload_params.dest = kDifKeymgrVersionedKeyDestKmac;
105 
106  // Get the maximum key version supported by the keymgr in its current state.
107  uint32_t max_key_version;
108  CHECK_STATUS_OK(
109  keymgr_testutils_max_key_version_get(keymgr, &max_key_version));
110 
111  if (sideload_params.version > max_key_version) {
112  LOG_INFO("Key version %d is greater than the maximum key version %d",
113  sideload_params.version, max_key_version);
114  LOG_INFO("Setting key version to the maximum key version %d",
115  max_key_version);
116  sideload_params.version = max_key_version;
117  }
118 
119  CHECK_STATUS_OK(
120  keymgr_testutils_generate_versioned_key(keymgr, sideload_params));
121  LOG_INFO("Keymgr generated HW output for Kmac");
122  uint32_t output_sideload[ARRAYSIZE(kKmacModes)][kKmacOutputLen];
123 
124  for (size_t it = 0; it < ARRAYSIZE(kKmacModes); it++) {
125  CHECK_STATUS_OK(kmac_testutils_kmac(
126  kmac, kKmacModes[it], &kSoftwareKey, kCustomString, kCustomStringLen,
127  kKmacMessage, kKmacMessageLen, kKmacOutputLen, output_sideload[it],
128  /*capacity=*/NULL));
129  }
130  LOG_INFO("Computed KMAC output for sideloaded key.");
131 
132  if (!test_phase) {
133  // In test phase 0, store the KMAC digest into the retention SRAM.
134  for (size_t it = 0; it < ARRAYSIZE(kKmacModes); it++) {
135  // Use kRetSramOwnerAddr + 4 to avoid overwriting test_phase_cnt.
136  sram_ctrl_testutils_write(
137  kRetSramOwnerAddr + 4 + 4 * it * kKmacOutputLen,
138  (sram_ctrl_testutils_data_t){.words = output_sideload[it],
139  .len = kKmacOutputLen});
140  }
141 
142  LOG_INFO("Clearing the sideloaded key.");
143 
144  // Enable "clear the key" toggle, so that previous sideload key port is
145  // cleared.
146  CHECK_DIF_OK(
148 
149  // Disable "clear the key" toggle, so that the sideload key port is stable.
150  // Otherwise, the sideload port is continuously overwritten by fresh
151  // randomness every clock cycle.
152  CHECK_DIF_OK(
154 
155  // Let the keymanager generate a new key with a different salt.
156  sideload_params.salt[0] = ~sideload_params.salt[0];
157  CHECK_STATUS_OK(
158  keymgr_testutils_generate_versioned_key(keymgr, sideload_params));
159  LOG_INFO("Keymgr generated new HW output for Kmac.");
160 
161  uint32_t output_sideload_after_clear[kKmacOutputLen];
162  CHECK_STATUS_OK(
163  kmac_testutils_kmac(kmac, kKmacModes[0], &kSoftwareKey, kCustomString,
164  kCustomStringLen, kKmacMessage, kKmacMessageLen,
165  kKmacOutputLen, output_sideload_after_clear,
166  /*capacity=*/NULL));
167  LOG_INFO(
168  "Ran KMAC with an another sideload key and checked that the output is "
169  "not identical to before.");
170 
171  CHECK_ARRAYS_NE(output_sideload_after_clear, output_sideload[0],
172  kKmacOutputLen);
173 
174  } else {
175  // In test phase 1, read the previous KMAC digests from the retention SRAM
176  // and compare them with the calculated ones.
177  for (size_t it = 0; it < ARRAYSIZE(kKmacModes); it++) {
178  uint32_t prev_digest[kKmacOutputLen];
179  memcpy(prev_digest,
180  (uint8_t *)(kRetSramOwnerAddr + 4 + 4 * it * kKmacOutputLen),
181  sizeof(prev_digest));
182  CHECK_ARRAYS_EQ(output_sideload[it], prev_digest, kKmacOutputLen);
183  }
184  LOG_INFO("Checked current and previous KMAC digest.");
185  }
186 }
187 
188 bool test_main(void) {
189  // Use the retention SRAM to store a test phase counter.
190  const dif_rstmgr_reset_info_bitfield_t reset_info =
191  rstmgr_testutils_reason_get();
192  size_t test_phase_cnt;
193 
194  ret_sram_testutils_init();
195 
196  if (reset_info == kDifRstmgrResetInfoPor) {
197  // Init counter to 0 after first power up.
198  CHECK_STATUS_OK(ret_sram_testutils_counter_clear(0));
199  }
200  CHECK_STATUS_OK(ret_sram_testutils_counter_get(0, &test_phase_cnt));
201 
202  // Initialize peripherals and the keymanager.
203  init_peripheral_handles();
204  CHECK_STATUS_OK(keymgr_testutils_initialize(&keymgr, &kmac));
205 
206  LOG_INFO("Starting test phase %d", test_phase_cnt);
207  test_kmac_key_sideload(&keymgr, &kmac, test_phase_cnt);
208  LOG_INFO("Finished test phase %x", test_phase_cnt);
209 
210  // After phase 0, trigger a software reset.
211  if (test_phase_cnt == 0) {
212  CHECK_STATUS_OK(ret_sram_testutils_counter_increment(0));
213  CHECK_DIF_OK(dif_rstmgr_software_device_reset(&rstmgr));
215  }
216 
217  return true;
218 }