Software APIs
ecc256_sign_serial.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 
7 #include "sw/device/lib/crypto/drivers/otbn.h"
10 #include "sw/device/lib/testing/entropy_testutils.h"
12 #include "sw/device/lib/testing/test_framework/ottf_test_config.h"
14 #include "sw/device/tests/penetrationtests/firmware/lib/pentest_lib.h"
15 
17 #include "otbn_regs.h"
18 
19 /**
20  * OpenTitan program for OTBN ECDSA-P256 side-channel analysis.
21  *
22  * This program implements the following simple serial commands:
23  * - Set ephemeral secret key ('k')*,
24  * - Set private key ('d')*,
25  * - Set message ('n')*,
26  * - Start signing ('p')*
27  * - Version ('v')+,
28  * - Seed PRNG ('s')+,
29  * Commands marked with * are implemented in this file. Those marked with + are
30  * implemented in the simple serial library.
31  * See https://wiki.newae.com/SimpleSerial for details on the protocol.
32  *
33  * The OTBN-related code was developed based on
34  * https://github.com/lowRISC/opentitan/tree/master/sw/device/lib/crypto/ecc/ecdsa_p256.c
35  * and
36  * https://github.com/lowRISC/opentitan/blob/master/sw/device/tests/crypto/ecdsa_p256_functest.c
37  *
38  */
39 
40 OTTF_DEFINE_TEST_CONFIG();
41 
42 enum {
43  /**
44  * Number of bytes for ECDSA P-256 private keys, message digests, and point
45  * coordinates.
46  */
47  kEcc256NumBytes = 256 / 8,
48  /**
49  * Number of 32b words for ECDSA P-256 private keys, message digests, and
50  * point coordinates.
51  */
52  kEcc256NumWords = kEcc256NumBytes / sizeof(uint32_t),
53 };
54 
55 /**
56  * Two shares of the ephemeral secret key k
57  * k = k0 + k1
58  * k0 = ecc256_secret_k[0:7] (0x00000000...ffffffff)
59  * k1 = ecc256_secret_k[8:15] (0x00000000...00000000)
60  *
61  * The default values can be overwritten via
62  * the simpleserial command `k` (see ecc256_set_private_key_d)
63  */
64 uint32_t ecc256_secret_k[2 * kEcc256NumWords] = {
65  0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
66  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
67  0x00000000, 0x00000000, 0x00000000, 0x00000000,
68 };
69 
70 /**
71  * Private key d
72  * This is the default value used by NewAE in their experiments
73  * https://github.com/newaetech/ot-sca/blob/ecc-analysis/reports/ecc/REPORT.md
74  * https://github.com/newaetech/opentitan/tree/sca_otbninst
75  *
76  *
77  * The value of this variable can be overwritten via
78  * the simpleserial command `d` (see ecc256_set_private_key_d)
79  */
80 uint32_t ecc256_private_key_d[2 * kEcc256NumWords] = {
81  0xaf57b4cd, 0x744c9f1c, 0x8b7e0c02, 0x283e93e9, 0x0d18f00c, 0xda0b6cf4,
82  0x8fe6bb7a, 0x5545a0b7, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
83  0x00000000, 0x00000000, 0x00000000, 0x00000000,
84 };
85 
86 /**
87  * Message to sign.
88  *
89  * The value of this variable can be overwritten via the simpleserial command
90  * `n` (see ecc256_set_msg).
91  */
92 uint32_t ecc256_msg[kEcc256NumWords] = {
93  0x48656c6c, // 'Hell'
94  0x6f204f54, // 'o OT'
95  0x424e0000, // 'BN'
96 };
97 
98 // p256_ecdsa_sca has randomnization removed.
99 OTBN_DECLARE_APP_SYMBOLS(p256_ecdsa_sca);
100 
101 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, mode);
102 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, msg);
103 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, r);
104 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, s);
105 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, x);
106 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, y);
107 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, d0);
108 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, d1);
109 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, k0);
110 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, k1);
111 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, x_r);
112 
113 static const otbn_app_t kOtbnAppP256Ecdsa = OTBN_APP_T_INIT(p256_ecdsa_sca);
114 
115 static const otbn_addr_t kOtbnVarMode = OTBN_ADDR_T_INIT(p256_ecdsa_sca, mode);
116 static const otbn_addr_t kOtbnVarMsg = OTBN_ADDR_T_INIT(p256_ecdsa_sca, msg);
117 static const otbn_addr_t kOtbnVarR = OTBN_ADDR_T_INIT(p256_ecdsa_sca, r);
118 static const otbn_addr_t kOtbnVarS = OTBN_ADDR_T_INIT(p256_ecdsa_sca, s);
119 static const otbn_addr_t kOtbnVarX = OTBN_ADDR_T_INIT(p256_ecdsa_sca, x);
120 static const otbn_addr_t kOtbnVarY = OTBN_ADDR_T_INIT(p256_ecdsa_sca, y);
121 static const otbn_addr_t kOtbnVarD0 = OTBN_ADDR_T_INIT(p256_ecdsa_sca, d0);
122 static const otbn_addr_t kOtbnVarD1 = OTBN_ADDR_T_INIT(p256_ecdsa_sca, d1);
123 static const otbn_addr_t kOtbnVarXR = OTBN_ADDR_T_INIT(p256_ecdsa_sca, x_r);
124 static const otbn_addr_t kOtbnVarK0 = OTBN_ADDR_T_INIT(p256_ecdsa_sca, k0);
125 static const otbn_addr_t kOtbnVarK1 = OTBN_ADDR_T_INIT(p256_ecdsa_sca, k1);
126 
127 /**
128  * Simple serial 'k' (set ephemeral key) command handler.
129  *
130  * This function sets both shares of the secret scalar k.
131  * The first 32 bytes (i.e, kEcc256NumBytes) are used as k0, and
132  * The last 32 bytes (i.e, kEcc256NumBytes) are used as k1.
133  *
134  * Any of the shares can be set to all zeros to simplify the SCA.
135  *
136  * As this function sets both shares,
137  * the data length must be `2*kEcc256NumBytes`.
138  *
139  * @param secret_k Key.
140  * @param secret_k_len Key length.
141  */
142 static void ecc256_set_secret_key_k(const uint8_t *secret_k,
143  size_t secret_k_len) {
144  SS_CHECK(secret_k_len == 2 * kEcc256NumBytes);
145  memcpy(ecc256_secret_k, secret_k, secret_k_len);
146 }
147 
148 /**
149  * Simple serial 'd' (set private key) command handler.
150  *
151  * This function sets both shares of the private key d.
152  * The first 32 bytes (i.e, kEcc256NumBytes) are used as d0, and
153  * The last 32 bytes (i.e, kEcc256NumBytes) are used as d1.
154  *
155  * Any of the shares can be set to all zeros to simplify the SCA.
156  *
157  * As this function sets both shares,
158  * the data length must be `2*kEcc256NumBytes`.
159  *
160  * @param key_d Key.
161  * @param key_d_len Key length.
162  */
163 static void ecc256_set_private_key_d(const uint8_t *key_d, size_t key_d_len) {
164  SS_CHECK(key_d_len == 2 * kEcc256NumBytes);
165  memcpy(ecc256_private_key_d, key_d, key_d_len);
166 }
167 
168 /**
169  * Simple serial 'n' (set message) command handler.
170  *
171  * This implementation skips hashing the message to simplify side-channel
172  * analysis, so the message must not be longer than `kEcc256NumBytes` bytes
173  * long.
174  *
175  * @param msg Message to sign.
176  * @param msg_len Message length.
177  */
178 static void ecc256_set_msg(const uint8_t *msg, size_t msg_len) {
179  SS_CHECK(msg_len <= kEcc256NumBytes);
180  // Reset to zero before copying.
181  memset(ecc256_msg, 0, kEcc256NumBytes);
182  memcpy(ecc256_msg, msg, msg_len);
183 }
184 
185 /**
186  * Signs a message with ECDSA using the P-256 curve.
187  *
188  * R = k*G
189  * r = x-coordinate of R
190  * s = k^(-1)(msg + r*d) mod n
191  *
192  * @param otbn_ctx The OTBN context object.
193  * @param msg The message to sign, msg (32B).
194  * @param private_key_d The private key, d (32B).
195  * @param k The ephemeral key, k (random scalar) (32B).
196  * @param[out] signature_r Signature component r (the x-coordinate of R).
197  * Provide a pre-allocated 32B buffer.
198  * @param[out] signature_s Signature component s (the proof).
199  * Provide a pre-allocated 32B buffer.
200  */
201 static void p256_ecdsa_sign(const uint32_t *msg, const uint32_t *private_key_d,
202  uint32_t *signature_r, uint32_t *signature_s,
203  const uint32_t *k) {
204  uint32_t mode = 1; // mode 1 => sign
205  // Send operation mode to OTBN
206  SS_CHECK_STATUS_OK(otbn_dmem_write(/*num_words=*/1, &mode, kOtbnVarMode));
207  // Send Msg to OTBN
208  SS_CHECK_STATUS_OK(otbn_dmem_write(kEcc256NumWords, msg, kOtbnVarMsg));
209  // Send two shares of private_key_d to OTBN
211  otbn_dmem_write(kEcc256NumWords, private_key_d, kOtbnVarD0));
212  SS_CHECK_STATUS_OK(otbn_dmem_write(
213  kEcc256NumWords, private_key_d + kEcc256NumWords, kOtbnVarD1));
214  // Send two shares of secret_k to OTBN
215  SS_CHECK_STATUS_OK(otbn_dmem_write(kEcc256NumWords, k, kOtbnVarK0));
217  otbn_dmem_write(kEcc256NumWords, k + kEcc256NumWords, kOtbnVarK1));
218 
219  // Start OTBN execution
220  SS_CHECK_STATUS_OK(otbn_execute());
221  SS_CHECK_STATUS_OK(otbn_busy_wait_for_done());
222 
223  // Read the results back (sig_r, sig_s)
224  SS_CHECK_STATUS_OK(otbn_dmem_read(kEcc256NumWords, kOtbnVarR, signature_r));
225  SS_CHECK_STATUS_OK(otbn_dmem_read(kEcc256NumWords, kOtbnVarS, signature_s));
226 }
227 
228 /**
229  * Simple serial 'p' (sign) command handler.
230  *
231  * Triggers OTBN_P256_sign operation.
232  *
233  */
234 static void ecc256_ecdsa(const uint8_t *arg, size_t len) {
235  LOG_INFO("SSECDSA starting...");
236  SS_CHECK_STATUS_OK(otbn_load_app(kOtbnAppP256Ecdsa));
237  LOG_INFO("otbn_status: 0x%08x", abs_mmio_read32(TOP_EARLGREY_OTBN_BASE_ADDR +
238  OTBN_STATUS_REG_OFFSET));
239 
240  uint32_t ecc256_signature_r[kEcc256NumWords];
241  uint32_t ecc256_signature_s[kEcc256NumWords];
242 
243  LOG_INFO("Signing");
244  pentest_set_trigger_high();
245  p256_ecdsa_sign(ecc256_msg, ecc256_private_key_d, ecc256_signature_r,
246  ecc256_signature_s, ecc256_secret_k);
247  pentest_set_trigger_low();
248 
249  // Copy r and s into byte buffers to avoid strict-aliasing violations.
250  uint8_t ecc256_signature_r_bytes[kEcc256NumBytes];
251  memcpy(ecc256_signature_r_bytes, ecc256_signature_r,
252  sizeof(ecc256_signature_r));
253  uint8_t ecc256_signature_s_bytes[kEcc256NumBytes];
254  memcpy(ecc256_signature_s_bytes, ecc256_signature_s,
255  sizeof(ecc256_signature_s));
256 
257  // Send the outputs to the Host (Python) through simpleserial protocol.
258  simple_serial_send_packet('r', ecc256_signature_r_bytes, kEcc256NumBytes);
259  simple_serial_send_packet('r', ecc256_signature_s_bytes, kEcc256NumBytes);
260 
261  // Clear OTBN memory
262  SS_CHECK_STATUS_OK(otbn_dmem_sec_wipe());
263  SS_CHECK_STATUS_OK(otbn_imem_sec_wipe());
264 }
265 
266 /**
267  * Initializes peripherals and processes simple serial packets received over
268  * UART.
269  */
270 static void simple_serial_main(void) {
271  SS_CHECK_STATUS_OK(entropy_testutils_auto_mode_init());
272 
273  pentest_init(kPentestTriggerSourceOtbn,
274  kPentestPeripheralEntropy | kPentestPeripheralIoDiv4 |
275  kPentestPeripheralOtbn | kPentestPeripheralCsrng |
276  kPentestPeripheralEdn | kPentestPeripheralHmac);
277 
278  LOG_INFO("Running ECC serial");
279  LOG_INFO("Initializing simple serial interface to capture board.");
280 
281  simple_serial_init(pentest_get_uart());
282  SS_CHECK(simple_serial_register_handler('p', ecc256_ecdsa) ==
283  kSimpleSerialOk);
284  SS_CHECK(simple_serial_register_handler('k', ecc256_set_secret_key_k) ==
285  kSimpleSerialOk);
286  SS_CHECK(simple_serial_register_handler('d', ecc256_set_private_key_d) ==
287  kSimpleSerialOk);
288  SS_CHECK(simple_serial_register_handler('n', ecc256_set_msg) ==
289  kSimpleSerialOk);
290 
291  LOG_INFO("Starting simple serial packet handling.");
292  while (true) {
294  }
295 }
296 
297 bool test_main(void) {
298  (void)kOtbnVarX;
299  (void)kOtbnVarY;
300  (void)kOtbnVarXR;
301 
302  simple_serial_main();
303  return true;
304 }