Software APIs
p384.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/crypto/impl/ecc/p384.h"
6 
9 #include "sw/device/lib/crypto/drivers/otbn.h"
10 
12 
13 // Module ID for status codes.
14 #define MODULE_ID MAKE_MODULE_ID('p', '3', 'r')
15 
16 // Declare the OTBN app.
17 OTBN_DECLARE_APP_SYMBOLS(run_p384);
18 static const otbn_app_t kOtbnAppP384 = OTBN_APP_T_INIT(run_p384);
19 
20 // Declare offsets for input and output buffers.
21 OTBN_DECLARE_SYMBOL_ADDR(run_p384, mode); // Mode of operation.
22 OTBN_DECLARE_SYMBOL_ADDR(run_p384, msg); // ECDSA message digest.
23 OTBN_DECLARE_SYMBOL_ADDR(run_p384, r); // ECDSA signature scalar R.
24 OTBN_DECLARE_SYMBOL_ADDR(run_p384, s); // ECDSA signature scalar S.
25 OTBN_DECLARE_SYMBOL_ADDR(run_p384, x); // Public key x-coordinate.
26 OTBN_DECLARE_SYMBOL_ADDR(run_p384, y); // Public key y-coordinate.
27 OTBN_DECLARE_SYMBOL_ADDR(run_p384, d0); // Private key scalar d (share 0).
28 OTBN_DECLARE_SYMBOL_ADDR(run_p384, d1); // Private key scalar d (share 1).
29 OTBN_DECLARE_SYMBOL_ADDR(run_p384, x_r); // ECDSA verification result.
30 OTBN_DECLARE_SYMBOL_ADDR(run_p384, ok); // Status code.
31 
32 static const otbn_addr_t kOtbnVarMode = OTBN_ADDR_T_INIT(run_p384, mode);
33 static const otbn_addr_t kOtbnVarMsg = OTBN_ADDR_T_INIT(run_p384, msg);
34 static const otbn_addr_t kOtbnVarR = OTBN_ADDR_T_INIT(run_p384, r);
35 static const otbn_addr_t kOtbnVarS = OTBN_ADDR_T_INIT(run_p384, s);
36 static const otbn_addr_t kOtbnVarX = OTBN_ADDR_T_INIT(run_p384, x);
37 static const otbn_addr_t kOtbnVarY = OTBN_ADDR_T_INIT(run_p384, y);
38 static const otbn_addr_t kOtbnVarD0 = OTBN_ADDR_T_INIT(run_p384, d0);
39 static const otbn_addr_t kOtbnVarD1 = OTBN_ADDR_T_INIT(run_p384, d1);
40 static const otbn_addr_t kOtbnVarXr = OTBN_ADDR_T_INIT(run_p384, x_r);
41 static const otbn_addr_t kOtbnVarOk = OTBN_ADDR_T_INIT(run_p384, ok);
42 
43 // Declare mode constants.
44 OTBN_DECLARE_SYMBOL_ADDR(run_p384, MODE_KEYGEN);
45 OTBN_DECLARE_SYMBOL_ADDR(run_p384, MODE_SIGN);
46 OTBN_DECLARE_SYMBOL_ADDR(run_p384, MODE_VERIFY);
47 OTBN_DECLARE_SYMBOL_ADDR(run_p384, MODE_ECDH);
48 OTBN_DECLARE_SYMBOL_ADDR(run_p384, MODE_SIDELOAD_KEYGEN);
49 OTBN_DECLARE_SYMBOL_ADDR(run_p384, MODE_SIDELOAD_SIGN);
50 OTBN_DECLARE_SYMBOL_ADDR(run_p384, MODE_SIDELOAD_ECDH);
51 static const uint32_t kP384ModeKeygen = OTBN_ADDR_T_INIT(run_p384, MODE_KEYGEN);
52 static const uint32_t kP384ModeSign = OTBN_ADDR_T_INIT(run_p384, MODE_SIGN);
53 static const uint32_t kP384ModeVerify = OTBN_ADDR_T_INIT(run_p384, MODE_VERIFY);
54 static const uint32_t kP384ModeEcdh = OTBN_ADDR_T_INIT(run_p384, MODE_ECDH);
55 static const uint32_t kP384ModeSideloadKeygen =
56  OTBN_ADDR_T_INIT(run_p384, MODE_SIDELOAD_KEYGEN);
57 static const uint32_t kP384ModeSideloadSign =
58  OTBN_ADDR_T_INIT(run_p384, MODE_SIDELOAD_SIGN);
59 static const uint32_t kP384ModeSideloadEcdh =
60  OTBN_ADDR_T_INIT(run_p384, MODE_SIDELOAD_ECDH);
61 
62 enum {
63  /*
64  * Mode is represented by a single word.
65  */
66  kP384ModeWords = 1,
67  /**
68  * Number of extra padding words needed for masked scalar shares.
69  *
70  * Where W is the word size and S is the share size, the padding needed is:
71  * (W - (S % W)) % W
72  *
73  * The extra outer "% W" ensures that the padding is 0 if (S % W) is 0.
74  */
75  kMaskedScalarPaddingWords =
76  (kOtbnWideWordNumWords -
77  (kP384MaskedScalarShareWords % kOtbnWideWordNumWords)) %
78  kOtbnWideWordNumWords,
79 };
80 
81 static status_t p384_masked_scalar_write(const p384_masked_scalar_t *src,
82  const otbn_addr_t share0_addr,
83  const otbn_addr_t share1_addr) {
84  HARDENED_TRY(
85  otbn_dmem_write(kP384MaskedScalarShareWords, src->share0, share0_addr));
86  HARDENED_TRY(
87  otbn_dmem_write(kP384MaskedScalarShareWords, src->share1, share1_addr));
88 
89  // Write trailing 0s so that OTBN's 384-bit read of the second share does not
90  // cause an error.
91  HARDENED_TRY(otbn_dmem_set(kMaskedScalarPaddingWords, 0,
92  share0_addr + kP384MaskedScalarShareBytes));
93  HARDENED_TRY(otbn_dmem_set(kMaskedScalarPaddingWords, 0,
94  share1_addr + kP384MaskedScalarShareBytes));
95 
96  return OTCRYPTO_OK;
97 }
98 
99 static status_t set_message_digest(const uint32_t digest[kP384ScalarWords],
100  const otbn_addr_t dst) {
101  // Set the message digest. We swap all the bytes so that OTBN can interpret
102  // the digest as a little-endian integer, which is a more natural fit for the
103  // architecture than the big-endian form requested by the specification (FIPS
104  // 186-5, section B.2.1).
105  uint32_t digest_little_endian[kP384ScalarWords];
106  size_t i = 0;
107  for (; launder32(i) < kP384ScalarWords; i++) {
108  digest_little_endian[i] =
109  __builtin_bswap32(digest[kP384ScalarWords - 1 - i]);
110  }
111  HARDENED_CHECK_EQ(i, kP384ScalarWords);
112  return otbn_dmem_write(kP384ScalarWords, digest_little_endian, dst);
113 }
114 
115 status_t p384_keygen_start(void) {
116  // Load the ECDH/P-384 app. Fails if OTBN is non-idle.
117  HARDENED_TRY(otbn_load_app(kOtbnAppP384));
118 
119  // Set mode so start() will jump into keygen.
120  uint32_t mode = kP384ModeKeygen;
121  HARDENED_TRY(otbn_dmem_write(kP384ModeWords, &mode, kOtbnVarMode));
122 
123  // Start the OTBN routine.
124  return otbn_execute();
125 }
126 
127 status_t p384_keygen_finalize(p384_masked_scalar_t *private_key,
128  p384_point_t *public_key) {
129  // Spin here waiting for OTBN to complete.
130  HARDENED_TRY(otbn_busy_wait_for_done());
131 
132  // Read the masked private key from OTBN dmem.
133  HARDENED_TRY(otbn_dmem_read(kP384MaskedScalarShareWords, kOtbnVarD0,
134  private_key->share0));
135  HARDENED_TRY(otbn_dmem_read(kP384MaskedScalarShareWords, kOtbnVarD1,
136  private_key->share1));
137 
138  // Read the public key from OTBN dmem.
139  HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarX, public_key->x));
140  HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarY, public_key->y));
141 
142  // Wipe DMEM.
143  HARDENED_TRY(otbn_dmem_sec_wipe());
144 
145  return OTCRYPTO_OK;
146 }
147 
148 status_t p384_sideload_keygen_start(void) {
149  // Load the ECDH/P-384 app. Fails if OTBN is non-idle.
150  HARDENED_TRY(otbn_load_app(kOtbnAppP384));
151 
152  // Set mode so start() will jump into keygen.
153  uint32_t mode = kP384ModeSideloadKeygen;
154  HARDENED_TRY(otbn_dmem_write(kP384ModeWords, &mode, kOtbnVarMode));
155 
156  // Start the OTBN routine.
157  return otbn_execute();
158 }
159 
160 status_t p384_sideload_keygen_finalize(p384_point_t *public_key) {
161  // Spin here waiting for OTBN to complete.
162  HARDENED_TRY(otbn_busy_wait_for_done());
163 
164  // Read the public key from OTBN dmem.
165  HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarX, public_key->x));
166  HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarY, public_key->y));
167 
168  // Wipe DMEM.
169  HARDENED_TRY(otbn_dmem_sec_wipe());
170 
171  return OTCRYPTO_OK;
172 }
173 
174 status_t p384_ecdsa_sign_start(const uint32_t digest[kP384ScalarWords],
175  const p384_masked_scalar_t *private_key) {
176  // Load the ECDSA/P-384 app. Fails if OTBN is non-idle.
177  HARDENED_TRY(otbn_load_app(kOtbnAppP384));
178 
179  // Set mode so start() will jump into sideloaded signing.
180  uint32_t mode = kP384ModeSign;
181  HARDENED_TRY(otbn_dmem_write(kP384ModeWords, &mode, kOtbnVarMode));
182 
183  // Set the message digest.
184  HARDENED_TRY(set_message_digest(digest, kOtbnVarMsg));
185 
186  // Set the private key shares.
187  HARDENED_TRY(p384_masked_scalar_write(private_key, kOtbnVarD0, kOtbnVarD1));
188 
189  // Start the OTBN routine.
190  return otbn_execute();
191 }
192 
193 status_t p384_ecdsa_sideload_sign_start(
194  const uint32_t digest[kP384ScalarWords]) {
195  // Load the ECDSA/P-384 app. Fails if OTBN is non-idle.
196  HARDENED_TRY(otbn_load_app(kOtbnAppP384));
197 
198  // Set mode so start() will jump into sideloaded signing.
199  uint32_t mode = kP384ModeSideloadSign;
200  HARDENED_TRY(otbn_dmem_write(kP384ModeWords, &mode, kOtbnVarMode));
201 
202  // Set the message digest.
203  HARDENED_TRY(set_message_digest(digest, kOtbnVarMsg));
204 
205  // Start the OTBN routine.
206  return otbn_execute();
207 }
208 
209 status_t p384_ecdsa_sign_finalize(p384_ecdsa_signature_t *result) {
210  // Spin here waiting for OTBN to complete.
211  HARDENED_TRY(otbn_busy_wait_for_done());
212 
213  // Read signature R out of OTBN dmem.
214  HARDENED_TRY(otbn_dmem_read(kP384ScalarWords, kOtbnVarR, result->r));
215 
216  // Read signature S out of OTBN dmem.
217  HARDENED_TRY(otbn_dmem_read(kP384ScalarWords, kOtbnVarS, result->s));
218 
219  // Wipe DMEM.
220  HARDENED_TRY(otbn_dmem_sec_wipe());
221 
222  return OTCRYPTO_OK;
223 }
224 
225 status_t p384_ecdsa_verify_start(const p384_ecdsa_signature_t *signature,
226  const uint32_t digest[kP384ScalarWords],
227  const p384_point_t *public_key) {
228  // Load the ECDSA/P-384 app
229  HARDENED_TRY(otbn_load_app(kOtbnAppP384));
230 
231  // Set mode so start() will jump into ECDSA verify.
232  uint32_t mode = kP384ModeVerify;
233  HARDENED_TRY(otbn_dmem_write(kP384ModeWords, &mode, kOtbnVarMode));
234 
235  // Set the message digest.
236  HARDENED_TRY(set_message_digest(digest, kOtbnVarMsg));
237 
238  // Set the signature R.
239  HARDENED_TRY(otbn_dmem_write(kP384ScalarWords, signature->r, kOtbnVarR));
240 
241  // Set the signature S.
242  HARDENED_TRY(otbn_dmem_write(kP384ScalarWords, signature->s, kOtbnVarS));
243 
244  // Set the public key x coordinate.
245  HARDENED_TRY(otbn_dmem_write(kP384CoordWords, public_key->x, kOtbnVarX));
246 
247  // Set the public key y coordinate.
248  HARDENED_TRY(otbn_dmem_write(kP384CoordWords, public_key->y, kOtbnVarY));
249 
250  // Start the OTBN routine.
251  return otbn_execute();
252 }
253 
254 status_t p384_ecdsa_verify_finalize(const p384_ecdsa_signature_t *signature,
255  hardened_bool_t *result) {
256  // Spin here waiting for OTBN to complete.
257  HARDENED_TRY(otbn_busy_wait_for_done());
258 
259  // Read the status code out of DMEM (false if basic checks on the validity of
260  // the signature and public key failed).
261  uint32_t ok;
262  HARDENED_TRY(otbn_dmem_read(1, kOtbnVarOk, &ok));
263  if (launder32(ok) != kHardenedBoolTrue) {
264  return OTCRYPTO_BAD_ARGS;
265  }
267 
268  // Read x_r (recovered R) out of OTBN dmem.
269  uint32_t x_r[kP384ScalarWords];
270  HARDENED_TRY(otbn_dmem_read(kP384ScalarWords, kOtbnVarXr, x_r));
271 
272  *result = hardened_memeq(x_r, signature->r, kP384ScalarWords);
273 
274  // Wipe DMEM.
275  HARDENED_TRY(otbn_dmem_sec_wipe());
276 
277  return OTCRYPTO_OK;
278 }
279 
280 status_t p384_ecdh_start(const p384_masked_scalar_t *private_key,
281  const p384_point_t *public_key) {
282  // Load the ECDH/P-384 app. Fails if OTBN is non-idle.
283  HARDENED_TRY(otbn_load_app(kOtbnAppP384));
284 
285  // Set mode so start() will jump into shared-key generation.
286  uint32_t mode = kP384ModeEcdh;
287  HARDENED_TRY(otbn_dmem_write(kP384ModeWords, &mode, kOtbnVarMode));
288 
289  // Set the private key shares.
290  HARDENED_TRY(p384_masked_scalar_write(private_key, kOtbnVarD0, kOtbnVarD1));
291 
292  // Set the public key x coordinate.
293  HARDENED_TRY(otbn_dmem_write(kP384CoordWords, public_key->x, kOtbnVarX));
294 
295  // Set the public key y coordinate.
296  HARDENED_TRY(otbn_dmem_write(kP384CoordWords, public_key->y, kOtbnVarY));
297 
298  // Start the OTBN routine.
299  return otbn_execute();
300 }
301 
302 status_t p384_ecdh_finalize(p384_ecdh_shared_key_t *shared_key) {
303  // Spin here waiting for OTBN to complete.
304  HARDENED_TRY(otbn_busy_wait_for_done());
305 
306  // Read the status code out of DMEM (false if basic checks on the validity of
307  // the signature and public key failed).
308  uint32_t ok;
309  HARDENED_TRY(otbn_dmem_read(1, kOtbnVarOk, &ok));
310  if (launder32(ok) != kHardenedBoolTrue) {
311  return OTCRYPTO_BAD_ARGS;
312  }
314 
315  // Read the shares of the key from OTBN dmem (at vars x and y).
316  HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarX, shared_key->share0));
317  HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarY, shared_key->share1));
318 
319  // Wipe DMEM.
320  HARDENED_TRY(otbn_dmem_sec_wipe());
321 
322  return OTCRYPTO_OK;
323 }
324 
325 status_t p384_sideload_ecdh_start(const p384_point_t *public_key) {
326  // Load the ECDH/P-384 app. Fails if OTBN is non-idle.
327  HARDENED_TRY(otbn_load_app(kOtbnAppP384));
328 
329  // Set mode so start() will jump into shared-key generation.
330  uint32_t mode = kP384ModeSideloadEcdh;
331  HARDENED_TRY(otbn_dmem_write(kP384ModeWords, &mode, kOtbnVarMode));
332 
333  // Set the public key x coordinate.
334  HARDENED_TRY(otbn_dmem_write(kP384CoordWords, public_key->x, kOtbnVarX));
335 
336  // Set the public key y coordinate.
337  HARDENED_TRY(otbn_dmem_write(kP384CoordWords, public_key->y, kOtbnVarY));
338 
339  // Start the OTBN routine.
340  return otbn_execute();
341 }