Software APIs
keymgr_sideload_kmac_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 
5 #include <stdbool.h>
6 #include <stdint.h>
7 
15 #include "sw/device/lib/testing/keymgr_testutils.h"
16 #include "sw/device/lib/testing/kmac_testutils.h"
17 #include "sw/device/lib/testing/test_framework/check.h"
19 
21 #include "keymgr_regs.h" // Generated.
22 #include "kmac_regs.h" // Generated.
23 
24 // The KMAC dif expects a secret key, even though if the configuration is set
25 // to use the sideloaded key then it will be ignored. We will write a software
26 // key and then ensure that the output does NOT match the expected value for
27 // this key when sideloading is used.
28 //
29 // Test taken from sample #1 here:
30 // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMAC_samples.pdf
31 static const dif_kmac_key_t kSoftwareKey = {
32  .share0 = {0x43424140, 0x47464544, 0x4B4A4948, 0x4F4E4D4C, 0x53525150,
33  0x57565554, 0x5B5A5958, 0x5F5E5D5C},
34  .share1 = {0},
35  .length = kDifKmacKeyLen256,
36 };
37 static const dif_kmac_mode_kmac_t kKmacMode = kDifKmacModeKmacLen128;
38 static const size_t kKmacOutputLen = 8;
39 static const uint32_t kSoftwareKeyExpectedOutput[8] = {
40  0x0D0B78E5, 0xD3F7A63E, 0x70C529A4, 0x003AA46A,
41  0xD4D7DBFA, 0x9E832896, 0x3F248731, 0x4EE16E45};
42 static const char *kCustomString = NULL;
43 static const size_t kCustomStringLen = 0;
44 static const char kKmacMessage[] = "\x00\x01\x02\x03";
45 static const size_t kKmacMessageLen = 4;
46 
47 static dif_keymgr_t keymgr;
48 static dif_kmac_t kmac;
49 
50 // This is computed and filled by dv side
51 static volatile const uint8_t sideload_digest_result[32] = {0};
52 
53 OTTF_DEFINE_TEST_CONFIG();
54 
55 /**
56  * Initializes all DIF handles for each peripheral used in this test.
57  */
58 static void init_peripheral_handles(void) {
59  CHECK_DIF_OK(
60  dif_kmac_init(mmio_region_from_addr(TOP_EARLGREY_KMAC_BASE_ADDR), &kmac));
61  CHECK_DIF_OK(dif_keymgr_init(
63 }
64 
65 /**
66  * Compute the total length of capacity.
67  *
68  * The length of the capacity is either 256 or 512 depending on the security
69  * strength implied by `kmac_mode`. The total length of capacity refers to
70  * the length of concatenated capacity parts across multiple output Keccak
71  * rounds. For instance, if `kmac_mode` implies 128-bit security and if
72  * `digest_len` implies 336 bytes of digest, then the total capacity is 512
73  * bits.
74  *
75  * @param kmac_mode KMAC mode that implies security strength.
76  * @param digest_len The length of the requested digest from KMAC operation in
77  * words.
78  * @param[out] capacity_total_len The total length of multiple capacity blocks
79  * in words.
80  * @return The result of the operation.
81  */
83 static status_t get_total_capacity_len(dif_kmac_mode_kmac_t kmac_mode,
84  size_t digest_len,
85  size_t *capacity_total_len) {
86  size_t capacity_len;
87  size_t rate_len;
88  if (kmac_mode == kDifKmacModeKmacLen128) {
89  capacity_len = 256 / 8 / sizeof(uint32_t);
90  } else if (kmac_mode == kDifKmacModeKmacLen256) {
91  capacity_len = 512 / 8 / sizeof(uint32_t);
92  } else {
93  return INVALID_ARGUMENT();
94  }
95  rate_len = kDifKmacStateWords - capacity_len;
96  *capacity_total_len = ceil_div(digest_len, rate_len) * capacity_len;
97  return OK_STATUS();
98 }
99 
100 /**
101  * Initialize and run KMAC using a sideloaded key.
102  *
103  * First, checks that KMAC works with the software key. Next, checks that when
104  * sideload=true, KMAC produces a different result.
105  */
106 static void test_kmac_with_sideloaded_key(dif_keymgr_t *keymgr,
107  dif_kmac_t *kmac) {
108  // Configure KMAC hardware (using software key and software entropy).
109  CHECK_STATUS_OK(kmac_testutils_config(kmac, false));
110 
111  // Allocate buffers to read capacity into so that we can test if it is
112  // zeroized for sideloaded KMAC operations (see #17759).
113  size_t capacity_total_len;
114  CHECK_STATUS_OK(
115  get_total_capacity_len(kKmacMode, kKmacOutputLen, &capacity_total_len));
116  uint32_t capacity[capacity_total_len];
117  uint32_t zero_array[capacity_total_len];
118  memset(zero_array, 0, sizeof(zero_array));
119  // The expected capacity after SW-keyed KMAC is non-zero, so initialize the
120  // array to 0.
121  memset(capacity, 0, sizeof(capacity));
122 
123  uint32_t output[kKmacOutputLen];
124  CHECK_STATUS_OK(kmac_testutils_kmac(
125  kmac, kKmacMode, &kSoftwareKey, kCustomString, kCustomStringLen,
126  kKmacMessage, kKmacMessageLen, kKmacOutputLen, output, capacity));
127  LOG_INFO("Computed KMAC output for software key.");
128 
129  // Check that the output matches the expected output.
130  CHECK_ARRAYS_EQ(output, kSoftwareKeyExpectedOutput, kKmacOutputLen);
131 
132  // Check that the capacity part is non-zero
133  CHECK_ARRAYS_NE(capacity, zero_array, ARRAYSIZE(capacity));
134 
135  // Reconfigure KMAC to use the sideloaded key.
136  CHECK_STATUS_OK(kmac_testutils_config(kmac, true));
137 
138  // Generate the sideloaded key.
139  dif_keymgr_versioned_key_params_t sideload_params = kKeyVersionedParams;
140  sideload_params.dest = kDifKeymgrVersionedKeyDestKmac;
141 
142  // Get the maximum key version supported by the keymgr in its current state.
143  uint32_t max_key_version;
144  CHECK_STATUS_OK(
145  keymgr_testutils_max_key_version_get(keymgr, &max_key_version));
146 
147  if (sideload_params.version > max_key_version) {
148  LOG_INFO("Key version %d is greater than the maximum key version %d",
149  sideload_params.version, max_key_version);
150  LOG_INFO("Setting key version to the maximum key version %d",
151  max_key_version);
152  sideload_params.version = max_key_version;
153  }
154 
155  CHECK_STATUS_OK(
156  keymgr_testutils_generate_versioned_key(keymgr, sideload_params));
157  LOG_INFO("Keymgr generated HW output for Kmac at OwnerIntKey State");
158 
159  uint32_t output_sideload_good0[kKmacOutputLen];
160  CHECK_STATUS_OK(
161  kmac_testutils_kmac(kmac, kKmacMode, &kSoftwareKey, kCustomString,
162  kCustomStringLen, kKmacMessage, kKmacMessageLen,
163  kKmacOutputLen, output_sideload_good0, capacity));
164  LOG_INFO("Computed KMAC output for sideloaded key.");
165 
166  // Check that capacity is read as 0.
167  CHECK_ARRAYS_EQ(capacity, zero_array, ARRAYSIZE(capacity));
168 
169  if (kDeviceType == kDeviceSimDV) {
170  // From the DV environment we get the expected digest, so check that the
171  // output using the sideloaded key matches the expectation. We cannot do
172  // this check outside the DV environment because we cannot observe the
173  // sideloaded key, thus cannot compute the expected digest.
174  CHECK_ARRAYS_EQ(output_sideload_good0, (uint32_t *)sideload_digest_result,
175  kKmacOutputLen);
176  }
177 
178  LOG_INFO("Clearing the sideloaded key.");
179 
180  // Enable "clear the key" toggle, so that previous sideload key port is
181  // cleared.
182  CHECK_DIF_OK(
184 
185  // Disable "clear the key" toggle, so that the sideload key port is stable.
186  // Otherwise, the sideload port is continuously overwritten by fresh
187  // randomness every clock cycle.
188  CHECK_DIF_OK(
190 
191  uint32_t output_sideload_bad[kKmacOutputLen];
192  // Initialize this output array because the following `kmac_testutils_kmac`
193  // function call fails early and is expected to *not* overwrite this array.
194  for (size_t i = 0; i < kKmacOutputLen; i++) {
195  output_sideload_bad[i] = i;
196  }
197  CHECK(kFailedPrecondition ==
198  status_err(kmac_testutils_kmac(
199  kmac, kKmacMode, &kSoftwareKey, kCustomString, kCustomStringLen,
200  kKmacMessage, kKmacMessageLen, kKmacOutputLen, output_sideload_bad,
201  /*capacity=*/NULL)));
202  LOG_INFO("Ran KMAC with an invalid sideload key and checked that it fails.");
203 
204  // Verify that the output array did not get overwritten.
205  for (size_t i = 0; i < kKmacOutputLen; i++) {
206  CHECK(output_sideload_bad[i] == i);
207  }
208 
209  // Sideload the same KMAC key again and check if we can compute the same
210  // result as before.
211  CHECK_STATUS_OK(
212  keymgr_testutils_generate_versioned_key(keymgr, sideload_params));
213  LOG_INFO("Keymgr regenerated HW output for Kmac at OwnerIntKey State");
214 
215  uint32_t output_sideload_good1[kKmacOutputLen];
216  CHECK_STATUS_OK(kmac_testutils_kmac(
217  kmac, kKmacMode, &kSoftwareKey, kCustomString, kCustomStringLen,
218  kKmacMessage, kKmacMessageLen, kKmacOutputLen, output_sideload_good1,
219  /*capacity=*/NULL));
220  LOG_INFO("Re-computed KMAC output for sideloaded key.");
221 
222  CHECK_ARRAYS_EQ(output_sideload_good1, output_sideload_good0, kKmacOutputLen);
223 }
224 
225 bool test_main(void) {
226  init_peripheral_handles();
227 
228  CHECK_STATUS_OK(keymgr_testutils_initialize(&keymgr, &kmac));
229 
230  // Test KMAC sideloading.
231  test_kmac_with_sideloaded_key(&keymgr, &kmac);
232  return true;
233 }