Software APIs
keymgr_sideload_otbn_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/entropy_testutils.h"
16 #include "sw/device/lib/testing/keymgr_testutils.h"
18 #include "sw/device/lib/testing/test_framework/check.h"
20 
22 #include "otbn_regs.h" // Generated.
23 
24 static dif_keymgr_t keymgr;
25 static dif_kmac_t kmac;
26 static dif_otbn_t otbn;
27 
28 /* Set up pointers to symbols in the OTBN application. */
29 OTBN_DECLARE_APP_SYMBOLS(x25519_sideload);
30 OTBN_DECLARE_SYMBOL_ADDR(x25519_sideload, enc_u);
31 OTBN_DECLARE_SYMBOL_ADDR(x25519_sideload, enc_result);
32 static const otbn_app_t kOtbnAppX25519 = OTBN_APP_T_INIT(x25519_sideload);
33 static const otbn_addr_t kOtbnVarEncU =
34  OTBN_ADDR_T_INIT(x25519_sideload, enc_u);
35 static const otbn_addr_t kOtbnVarEncResult =
36  OTBN_ADDR_T_INIT(x25519_sideload, enc_result);
37 
38 OTTF_DEFINE_TEST_CONFIG();
39 
40 /**
41  * Initializes all DIF handles for each peripheral used in this test.
42  */
43 static void init_peripheral_handles(void) {
44  CHECK_DIF_OK(
45  dif_kmac_init(mmio_region_from_addr(TOP_EARLGREY_KMAC_BASE_ADDR), &kmac));
46  CHECK_DIF_OK(dif_keymgr_init(
48  CHECK_DIF_OK(
49  dif_otbn_init(mmio_region_from_addr(TOP_EARLGREY_OTBN_BASE_ADDR), &otbn));
50 }
51 
52 /**
53  * Encoded Montgomery u-coordinate for testing.
54  *
55  * This value (9) is actually the u-coordinate of the Curve25519 base point, so
56  * the X25519 function will effectively compute the public key. This is the
57  * first step in key exchange (see RFC 7748, section 6.1).
58  */
59 static const uint32_t kEncodedU[8] = {
60  0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
61 };
62 static const dif_otbn_err_bits_t kOtbnInvalidKeyErr =
63  0x1 << OTBN_ERR_BITS_KEY_INVALID_BIT;
64 static const dif_otbn_err_bits_t kErrBitsOk = 0x0;
65 
66 /**
67  * Runs the OTBN X25519 application.
68  *
69  * The X25519 app and sideloaded key should already be loaded into OTBN before
70  * this routine is called. Causes CHECK-fail if the OTBN error code is not as
71  * expected.
72  *
73  * @param otbn OTBN context object
74  * @param[out] result Resulting Montgomery u-coordinate.
75  * @param expect_err_bits Error code expected from OTBN ERR register.
76  * an unexpected error.
77  */
78 static void run_x25519_app(dif_otbn_t *otbn, uint32_t *result,
79  dif_otbn_err_bits_t expect_err_bits) {
80  CHECK_DIF_OK(dif_otbn_set_ctrl_software_errs_fatal(otbn, /*enable=*/false));
81 
82  // Copy the input argument (Montgomery u-coordinate).
83  CHECK_STATUS_OK(otbn_testutils_write_data(otbn, sizeof(kEncodedU), &kEncodedU,
84  kOtbnVarEncU));
85 
86  // Run the OTBN program and wait for it to complete. Clear software
87  // error fatal flag as the test expects an intermediate error state.
88  LOG_INFO("Starting OTBN program...");
89  CHECK_DIF_OK(dif_otbn_set_ctrl_software_errs_fatal(otbn, false));
90  CHECK_STATUS_OK(otbn_testutils_execute(otbn));
91  CHECK_STATUS_OK(otbn_testutils_wait_for_done(otbn, expect_err_bits));
92 
93  // Copy the result (also a 256-bit Montgomery u-coordinate).
94  CHECK_STATUS_OK(
95  otbn_testutils_read_data(otbn, 32, kOtbnVarEncResult, result));
96 }
97 
98 /**
99  * Run an OTBN program using a sideloaded key.
100  * This routine does not check the correctness of results, merely sideloads the
101  * key from keymgr to OTBN and then runs the X25519 program.
102  */
103 static void test_otbn_with_sideloaded_key(dif_keymgr_t *keymgr,
104  dif_otbn_t *otbn) {
105  // Generate the sideloaded key.
106  // TODO(weicai): also check in SV sequence that the key is correct.
107  dif_keymgr_versioned_key_params_t sideload_params = kKeyVersionedParams;
108  sideload_params.dest = kDifKeymgrVersionedKeyDestOtbn;
109 
110  // Get the maximum key version supported by the keymgr in its current state.
111  uint32_t max_key_version;
112  CHECK_STATUS_OK(
113  keymgr_testutils_max_key_version_get(keymgr, &max_key_version));
114 
115  if (sideload_params.version > max_key_version) {
116  LOG_INFO("Key version %d is greater than the maximum key version %d",
117  sideload_params.version, max_key_version);
118  LOG_INFO("Setting key version to the maximum key version %d",
119  max_key_version);
120  sideload_params.version = max_key_version;
121  }
122 
123  CHECK_STATUS_OK(
124  keymgr_testutils_generate_versioned_key(keymgr, sideload_params));
125  LOG_INFO("Keymgr generated HW output for OTBN.");
126 
127  // Load the X25519 application.
128  CHECK_STATUS_OK(otbn_testutils_load_app(otbn, kOtbnAppX25519));
129  // Run the OTBN app and retrieve the result.
130  uint32_t result[8];
131  run_x25519_app(otbn, result, kErrBitsOk);
132 
133 #ifdef TEST_SIMPLE_CASE_ONLY
134  return;
135 #endif
136 
137  // Clear the sideload key and check that OTBN errors with the correct error
138  // code (`KEY_INVALID` bit 5 = 1).
139  CHECK_DIF_OK(
141  LOG_INFO("Clearing the Keymgr generated sideload keys.");
142  uint32_t at_clear_salt_result[8];
143  run_x25519_app(otbn, at_clear_salt_result, kOtbnInvalidKeyErr);
144 
145  // Disable sideload key clearing.
146  CHECK_DIF_OK(
148  LOG_INFO("Disable clearing the Keymgr generated sideload keys.");
149 
150  // Clear the ERR bits register
151  mmio_region_write32(otbn->base_addr, OTBN_ERR_BITS_REG_OFFSET, 0x0);
152 
153  CHECK_STATUS_OK(keymgr_testutils_generate_versioned_key(
154  keymgr, sideload_params)); // Regenerate the sideload key.
155  LOG_INFO("Keymgr generated HW output for OTBN.");
156  uint32_t post_clear_salt_result[8];
157  run_x25519_app(otbn, post_clear_salt_result, kErrBitsOk);
158  CHECK_ARRAYS_EQ(result, post_clear_salt_result, ARRAYSIZE(result));
159 
160  // Change the salt to generate a different key.
161  sideload_params.salt[0] = ~sideload_params.salt[0];
162  CHECK_STATUS_OK(
163  keymgr_testutils_generate_versioned_key(keymgr, sideload_params));
164  LOG_INFO("Keymgr generated HW output for OTBN.");
165 
166  uint32_t modified_salt_result[8];
167  run_x25519_app(otbn, modified_salt_result, kErrBitsOk);
168 
169  // Check that the result with the new key is different from the first
170  // result.
171  CHECK_ARRAYS_NE(result, modified_salt_result, ARRAYSIZE(result));
172 
173  // Change the salt back to generate the first key again.
174  sideload_params.salt[0] = ~sideload_params.salt[0];
175  CHECK_STATUS_OK(
176  keymgr_testutils_generate_versioned_key(keymgr, sideload_params));
177  LOG_INFO("Keymgr generated HW output for OTBN.");
178 
179  uint32_t same_key_result[8];
180  run_x25519_app(otbn, same_key_result, kErrBitsOk);
181 
182  // Check that the result generated using the same key matches the first
183  // result.
184  CHECK_ARRAYS_EQ(result, same_key_result, ARRAYSIZE(result));
185 }
186 
187 bool test_main(void) {
188  init_peripheral_handles();
189  CHECK_STATUS_OK(keymgr_testutils_initialize(&keymgr, &kmac));
190 
191  // Test OTBN sideloading.
192  test_otbn_with_sideloaded_key(&keymgr, &otbn);
193 
194  return true;
195 }