Embedded SDK
Embedded SDK
cx_ecfp.c
Go to the documentation of this file.
1 
2 /*******************************************************************************
3  * Ledger Nano S - Secure firmware
4  * (c) 2022 Ledger
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  ********************************************************************************/
18 
19 #ifdef HAVE_ECC
20 
21 #include "cx_ecfp.h"
22 #include "libcxng.h"
23 #include "cx_eddsa.h"
24 #include "cx_utils.h"
25 #include "cx_ram.h"
26 
27 #include <string.h>
28 
29 /* ========================================================================= */
30 /* ========================================================================= */
31 /* === APIs === */
32 /* ========================================================================= */
33 /* ========================================================================= */
34 
35 /* ----------------------------------------------------------------------- */
36 /* */
37 /* ----------------------------------------------------------------------- */
38 cx_err_t cx_ecfp_init_private_key_no_throw(cx_curve_t curve,
39  const uint8_t *raw_key,
40  size_t key_len,
41  cx_ecfp_private_key_t *key)
42 {
43  size_t domain_length;
44  cx_err_t error;
45 
46  CX_CHECK(cx_ecdomain_parameters_length(curve, &domain_length));
47 
48  if (!(((raw_key == NULL) && (key_len == 0)) || ((raw_key) && (key_len == domain_length)))) {
49  error = CX_INVALID_PARAMETER;
50  goto end;
51  }
52 
53  if (raw_key) {
54  key->d_len = key_len;
55  memmove(key->d, raw_key, key_len);
56  }
57 
58  key->curve = curve;
59 
60 end:
61  return error;
62 }
63 
64 /* ----------------------------------------------------------------------- */
65 /* */
66 /* ----------------------------------------------------------------------- */
67 cx_err_t cx_ecfp_init_public_key_no_throw(cx_curve_t curve,
68  const uint8_t *rawkey,
69  size_t key_len,
70  cx_ecfp_public_key_t *key)
71 {
72  size_t expected_key_len;
73  size_t expected_compressed_key_len;
74  size_t size;
75  cx_err_t error;
76 
77  error = cx_ecdomain_parameters_length(curve, &size);
78  if (error) {
79  return error;
80  }
81 
82  // SEC: complex assert param dispatched in code....
83 
84  memset(key, 0, sizeof(cx_ecfp_public_key_t));
85 
86  if (rawkey) {
87  if (key_len) {
88  expected_key_len = 0;
89  expected_compressed_key_len = 0;
90 
91 // check key length vs curve
92 #ifdef HAVE_ECC_WEIERSTRASS
93  if (CX_CURVE_RANGE(curve, WEIERSTRASS)) {
94  expected_key_len = 1 + (size) *2;
95  }
96 #endif
97 
98 #ifdef HAVE_ECC_TWISTED_EDWARDS
99  if (CX_CURVE_RANGE(curve, TWISTED_EDWARDS)) {
100  expected_key_len = 1 + (size) *2;
101  expected_compressed_key_len = 1 + (size);
102  }
103 #endif
104 
105 #ifdef HAVE_ECC_MONTGOMERY
106  if (CX_CURVE_RANGE(curve, MONTGOMERY)) {
107  expected_compressed_key_len = 1 + (size);
108  }
109 #endif
110 
111  // check key format
112  if ((key_len == expected_key_len) && (rawkey[0] == 0x04)) {
113  goto OK;
114  }
115  if ((key_len == expected_compressed_key_len) && (rawkey[0] == 0x02)) {
116  goto OK;
117  }
118  }
119  return INVALID_PARAMETER;
120  }
121  else {
122  key_len = 0;
123  }
124 
125 OK:
126  // init key
127  key->curve = curve;
128  key->W_len = key_len;
129  memmove(key->W, rawkey, key_len);
130 
131  return CX_OK;
132 }
133 
134 /* ----------------------------------------------------------------------- */
135 /* */
136 /* ----------------------------------------------------------------------- */
137 cx_err_t cx_ecfp_generate_pair_no_throw(cx_curve_t curve,
138  cx_ecfp_public_key_t *public_key,
139  cx_ecfp_private_key_t *private_key,
140  bool keep_private)
141 {
142  return cx_ecfp_generate_pair2_no_throw(curve, public_key, private_key, keep_private, CX_SHA512);
143 }
144 
145 cx_err_t cx_ecfp_generate_pair2_no_throw(cx_curve_t curve,
146  cx_ecfp_public_key_t *public_key,
147  cx_ecfp_private_key_t *private_key,
148  bool keep_private,
149  cx_md_t hashID)
150 {
151  // domain used
152  size_t size;
153  cx_bn_t r, a, n;
154  cx_ecpoint_t W;
155  cx_err_t error;
156 
157 #ifndef HAVE_ECC_TWISTED_EDWARDS
158  (void) hashID;
159 #endif
160 
161  CX_CHECK(cx_ecdomain_parameters_length(curve, &size));
162 
163  // SEC: complex assert param dispatched in code....
164 
165  CX_CHECK(cx_bn_lock(size, 0));
166  CX_CHECK(cx_bn_alloc(&n, size));
167  CX_CHECK(cx_ecdomain_parameter_bn(curve, CX_CURVE_PARAM_Order, n));
168  CX_CHECK(cx_bn_alloc(&r, size));
169 
170  // generate private key
171  if (keep_private) {
172  // keep => check private key
173  if ((private_key->curve != curve) || (private_key->d_len != size)) {
174  error = CX_INVALID_PARAMETER;
175  goto end;
176  }
177  CX_CHECK(cx_bn_init(r, private_key->d, private_key->d_len));
178  }
179  else {
180  CX_CHECK(cx_bn_alloc(&a, 2 * size));
181  CX_CHECK(cx_bn_rand(a));
182  CX_CHECK(cx_bn_reduce(r, a, n));
183  CX_CHECK(cx_bn_destroy(&a));
184  CX_CHECK(cx_bn_export(r, private_key->d, size));
185  private_key->curve = curve;
186  private_key->d_len = size;
187 
188 #ifdef HAVE_ECC_MONTGOMERY
189  if (CX_CURVE_RANGE(curve, MONTGOMERY)) {
190  if (curve == CX_CURVE_Curve25519) {
191  private_key->d[size - 1] &= 0xF8;
192  private_key->d[0] = (private_key->d[0] & 0x7F) | 0x40;
193  }
194  else /* CX_CURVE_Curve448*/ {
195  private_key->d[size - 1] &= 0xFC;
196  private_key->d[0] |= 0x80;
197  }
198  }
199 #endif
200  }
201 
202  // generate public key
203 #ifdef HAVE_ECC_WEIERSTRASS
204  if (CX_CURVE_RANGE(curve, WEIERSTRASS)) {
205  CX_CHECK(cx_ecpoint_alloc(&W, private_key->curve));
206  CX_CHECK(cx_ecdomain_generator_bn(curve, &W));
207  // 'cx_ecpoint_rnd_fixed_scalarmul' doesn't support BLS12-381 so far
208  // use cx_ecpoint_rnd_scalarmul for now
209  if (CX_CURVE_BLS12_381_G1 == private_key->curve) {
210  CX_CHECK(cx_ecpoint_rnd_scalarmul(&W, private_key->d, private_key->d_len));
211  }
212  else {
213  CX_CHECK(cx_ecpoint_rnd_fixed_scalarmul(&W, private_key->d, private_key->d_len));
214  }
215  public_key->curve = curve;
216  public_key->W_len = 1 + 2 * size;
217  public_key->W[0] = 0x04;
218  CX_CHECK(cx_ecpoint_export(&W, &public_key->W[1], size, &public_key->W[1 + size], size));
219  goto end;
220  }
221 #endif
222 
223 #ifdef HAVE_ECC_TWISTED_EDWARDS
224  if (CX_CURVE_RANGE(curve, TWISTED_EDWARDS)) {
225  uint8_t scal[114];
226  CX_CHECK(cx_eddsa_get_public_key_internal(
227  private_key, hashID, public_key, NULL, 0, NULL, 0, scal));
228  goto end;
229  }
230 #endif
231 
232 #ifdef HAVE_ECC_MONTGOMERY
233  if (CX_CURVE_RANGE(curve, MONTGOMERY)) {
234  CX_CHECK(cx_ecpoint_alloc(&W, private_key->curve));
235  CX_CHECK(cx_ecdomain_generator_bn(curve, &W));
236  CX_CHECK(cx_ecpoint_rnd_scalarmul(&W, private_key->d, private_key->d_len));
237  public_key->curve = curve;
238  public_key->W_len = 1 + 2 * size;
239  public_key->W[0] = 0x04;
240  CX_CHECK(cx_ecpoint_export(&W, &public_key->W[1], size, &public_key->W[1 + size], size));
241  goto end;
242  }
243 #endif
244 
245  error = CX_EC_INVALID_POINT;
246 
247 end:
248  cx_bn_unlock();
249  return error;
250 }
251 
252 cx_err_t cx_ecfp_add_point_no_throw(cx_curve_t curve,
253  unsigned char *R,
254  const unsigned char *P,
255  const unsigned char *Q)
256 {
257  size_t size;
258  cx_ecpoint_t ecR, ecP, ecQ;
259  cx_err_t error;
260 
261  CX_CHECK(cx_ecdomain_parameters_length(curve, &size));
262  CX_CHECK(cx_bn_lock(size, 0));
263 
264  CX_CHECK(cx_ecpoint_alloc(&ecP, curve));
265  CX_CHECK(cx_ecpoint_alloc(&ecQ, curve));
266  CX_CHECK(cx_ecpoint_alloc(&ecR, curve));
267  CX_CHECK(cx_ecpoint_init(&ecP, P + 1, size, P + 1 + size, size));
268  CX_CHECK(cx_ecpoint_init(&ecQ, Q + 1, size, Q + 1 + size, size));
269  CX_CHECK(cx_ecpoint_add(&ecR, &ecP, &ecQ));
270  R[0] = 0x04;
271  CX_CHECK(cx_ecpoint_export(&ecR, &R[1], size, &R[1 + size], size));
272 
273 end:
274  cx_bn_unlock();
275  return error;
276 }
277 
278 /* ----------------------------------------------------------------------- */
279 /* */
280 /* ----------------------------------------------------------------------- */
281 cx_err_t cx_ecfp_scalar_mult_no_throw(cx_curve_t curve, uint8_t *P, const uint8_t *k, size_t k_len)
282 {
283  size_t size;
284  cx_ecpoint_t ecP;
285  cx_err_t error;
286 
287  CX_CHECK(cx_ecdomain_parameters_length(curve, &size));
288  CX_CHECK(cx_bn_lock(size, 0));
289 
290  CX_CHECK(cx_ecpoint_alloc(&ecP, curve));
291  CX_CHECK(cx_ecpoint_init(&ecP, P + 1, size, P + 1 + size, size));
292  CX_CHECK(cx_ecpoint_rnd_scalarmul(&ecP, k, k_len));
293  P[0] = 0x04;
294  CX_CHECK(cx_ecpoint_export(&ecP, &P[1], size, &P[1 + size], size));
295 
296 end:
297  cx_bn_unlock();
298  return error;
299 }
300 
301 #ifdef HAVE_ECC_TWISTED_EDWARDS
302 
303 cx_err_t cx_edwards_compress_point_no_throw(cx_curve_t curve, uint8_t *P, size_t P_len)
304 {
305  cx_ecpoint_t P_ec;
306  cx_err_t error;
307  uint32_t sign;
308  size_t size;
309 
310  UNUSED(P_len);
311  CX_CHECK(cx_ecdomain_parameters_length(curve, &size));
312  CX_CHECK(cx_bn_lock(size, 0));
313  CX_CHECK(cx_ecpoint_alloc(&P_ec, curve));
314  CX_CHECK(cx_ecpoint_init(&P_ec, P + 1, size, P + 1 + size, size));
315  CX_CHECK(cx_ecpoint_compress(&P_ec, P + 1, size, &sign));
316  cx_encode_coord(P + 1, size, sign);
317  memmove(P + 1 + size, P + 1, size);
318  P[0] = 0x02;
319 
320 end:
321  cx_bn_unlock();
322  return error;
323 }
324 
325 cx_err_t cx_edwards_decompress_point_no_throw(cx_curve_t curve, uint8_t *P, size_t P_len)
326 {
327  cx_ecpoint_t P_ec;
328  cx_err_t error;
329  uint32_t sign;
330  size_t size;
331 
332  UNUSED(P_len);
333  CX_CHECK(cx_ecdomain_parameters_length(curve, &size));
334  CX_CHECK(cx_bn_lock(size, 0));
335  sign = cx_decode_coord(P + 1, size);
336  CX_CHECK(cx_ecpoint_alloc(&P_ec, curve));
337  memmove(P + 1 + size, P + 1, size);
338  CX_CHECK(cx_ecpoint_decompress(&P_ec, P + 1, size, sign));
339  CX_CHECK(cx_ecpoint_export(&P_ec, P + 1, size, P + 1 + size, size));
340  P[0] = 0x04;
341 
342 end:
343  cx_bn_unlock();
344  return error;
345 }
346 
347 #endif // HAVE_ECC_TWISTED_EDWARDS
348 
349 static size_t asn1_get_encoded_length_size(size_t len)
350 {
351  if (len < 0x80) { // ..
352  return 1;
353  }
354  if (len < 0x100) {
355  // 81 ..
356  return 2;
357  }
358  if (len < 0x10000) {
359  // 82 .. ..
360  return 3;
361  }
362  return 0;
363 }
364 
365 // return the length of an asn1 integer, aka '02' L V
366 static size_t asn1_get_encoded_integer_size(uint8_t const *val, size_t len)
367 {
368  size_t l0;
369 
370  while (len && (*val == 0)) {
371  val++;
372  len--;
373  }
374 
375  if (len == 0) {
376  len = 1;
377  }
378  else if (*val & 0x80u) {
379  len++;
380  }
381 
382  l0 = asn1_get_encoded_length_size(len);
383  if (l0 == 0) {
384  return 0;
385  }
386  return 1 + l0 + len;
387 }
388 
389 static int asn1_insert_tag(uint8_t **p, const uint8_t *end, unsigned int tag)
390 {
391  if ((end - *p) < 1) {
392  return 0;
393  }
394  **p = tag;
395  (*p)++;
396  return 1;
397 }
398 
399 static int asn1_insert_len(uint8_t **p, const uint8_t *end, size_t len)
400 {
401  if (len < 0x80) {
402  if ((end - *p) < 1) {
403  return 0;
404  }
405  (*p)[0] = len & 0xFF;
406  (*p) += 1;
407  return 1;
408  }
409 
410  if (len < 0x100) {
411  if ((end - *p) < 2) {
412  return 0;
413  }
414  (*p)[0] = 0x81u;
415  (*p)[1] = len & 0xFF;
416  (*p) += 2;
417  return 2;
418  }
419 
420  if (len < 0x10000) {
421  if ((end - *p) < 3) {
422  return 0;
423  }
424  (*p)[0] = 0x82u;
425  (*p)[1] = (len >> 8) & 0xFF;
426  (*p)[2] = len & 0xFF;
427  (*p) += 3;
428  return 3;
429  }
430 
431  return 0;
432 }
433 
434 static int asn1_insert_integer(uint8_t **p, const uint8_t *end, const uint8_t *val, size_t len)
435 {
436  while (len && (*val == 0)) {
437  val++;
438  len--;
439  }
440  if (!asn1_insert_tag(p, end, 0x02)) {
441  return 0;
442  }
443 
444  // special case for 0
445  if (len == 0) {
446  if ((end - *p) < 2) {
447  return 0;
448  }
449  (*p)[0] = 0x01u;
450  (*p)[1] = 0x00u;
451  (*p) += 2;
452  return 1;
453  }
454 
455  // cont with len != 0, so val != 0
456  if (!asn1_insert_len(p, end, (*val & 0x80) ? len + 1 : len)) {
457  return 0;
458  }
459 
460  if (*val & 0x80) {
461  if ((end - *p) < 1) {
462  return 0;
463  }
464  **p = 0;
465  (*p)++;
466  }
467  if ((end - *p) < (int) len) {
468  return 0;
469  }
470  memmove(*p, val, len);
471  (*p) += len;
472  return 1;
473 }
474 
475 /* ----------------------------------------------------------------------- */
476 /* */
477 /* ----------------------------------------------------------------------- */
478 size_t cx_ecfp_encode_sig_der(uint8_t *sig,
479  size_t sig_len,
480  const uint8_t *r,
481  size_t r_len,
482  const uint8_t *s,
483  size_t s_len)
484 {
485  size_t l0, len;
486  const uint8_t *sig_end = sig + sig_len;
487 
488  len = 0;
489 
490  l0 = asn1_get_encoded_integer_size(r, r_len);
491  if (l0 == 0) {
492  return 0;
493  }
494  len += l0;
495 
496  l0 = asn1_get_encoded_integer_size(s, s_len);
497  if (l0 == 0) {
498  return 0;
499  }
500  len += l0;
501 
502  if (!asn1_insert_tag(&sig, sig_end, 0x30) || !asn1_insert_len(&sig, sig_end, len)
503  || !asn1_insert_integer(&sig, sig_end, r, r_len)
504  || !asn1_insert_integer(&sig, sig_end, s, s_len)) {
505  return 0;
506  }
507  return sig_len - (sig_end - sig);
508 }
509 
510 static int asn1_read_len(const uint8_t **p, const uint8_t *end, size_t *len)
511 {
512  /* Adapted from secp256k1 */
513  int lenleft;
514  unsigned int b1;
515  *len = 0;
516 
517  if (*p >= end) {
518  return 0;
519  }
520 
521  b1 = *((*p)++);
522  if (b1 == 0xff) {
523  /* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */
524  return 0;
525  }
526  if ((b1 & 0x80u) == 0) {
527  /* X.690-0207 8.1.3.4 short form length octets */
528  *len = b1;
529  return 1;
530  }
531  if (b1 == 0x80) {
532  /* Indefinite length is not allowed in DER. */
533  return 0;
534  }
535  /* X.690-207 8.1.3.5 long form length octets */
536  lenleft = b1 & 0x7Fu;
537  if (lenleft > end - *p) {
538  return 0;
539  }
540  if (**p == 0) {
541  /* Not the shortest possible length encoding. */
542  return 0;
543  }
544  if ((size_t) lenleft > sizeof(size_t)) {
545  /* The resulting length would exceed the range of a size_t, so
546  * certainly longer than the passed array size.
547  */
548  return 0;
549  }
550  while (lenleft > 0) {
551  if ((*len >> ((sizeof(size_t) - 1) * 8)) != 0) {
552  return 0;
553  }
554  *len = (*len << 8u) | **p;
555  if (*len + lenleft > (size_t) (end - *p)) {
556  /* Result exceeds the length of the passed array. */
557  return 0;
558  }
559  (*p)++;
560  lenleft--;
561  }
562  if (*len < 128) {
563  /* Not the shortest possible length encoding. */
564  return 0;
565  }
566  return 1;
567 }
568 
569 static int asn1_read_tag(const uint8_t **p, const uint8_t *end, size_t *len, int tag)
570 {
571  if ((end - *p) < 1) {
572  return 0;
573  }
574 
575  if (**p != tag) {
576  return 0;
577  }
578 
579  (*p)++;
580  return asn1_read_len(p, end, len);
581 }
582 
583 static int asn1_parse_integer(const uint8_t **p,
584  const uint8_t *end,
585  const uint8_t **n,
586  size_t *n_len)
587 {
588  size_t len;
589  int ret = 0;
590 
591  if (!asn1_read_tag(p, end, &len, 0x02)) { /* INTEGER */
592  goto end;
593  }
594 
595  if (len == 0 || len > (size_t) (end - *p)) {
596  goto end;
597  }
598 
599  if (((*p)[0] & 0x80u) == 0x80u) {
600  /* Truncated, missing leading 0 (negative number) */
601  goto end;
602  }
603 
604  if ((*p)[0] == 0 && len >= 2 && ((*p)[1] & 0x80u) == 0) {
605  /* Zeroes have been prepended to the integer */
606  goto end;
607  }
608 
609  while (len > 0 && **p == 0 && *p != end) { /* Skip leading null bytes */
610  (*p)++;
611  len--;
612  }
613 
614  *n = *p;
615  *n_len = len;
616 
617  *p += len;
618  ret = 1;
619 
620 end:
621  return ret;
622 }
623 
624 /* ----------------------------------------------------------------------- */
625 /* */
626 /* ----------------------------------------------------------------------- */
627 
628 int cx_ecfp_decode_sig_der(const uint8_t *input,
629  size_t input_len,
630  size_t max_size,
631  const uint8_t **r,
632  size_t *r_len,
633  const uint8_t **s,
634  size_t *s_len)
635 {
636  size_t len;
637  int ret = 0;
638  const uint8_t *input_end = input + input_len;
639 
640  *s = NULL;
641  *r = NULL;
642  *s_len = 0;
643  *r_len = 0;
644 
645  const uint8_t *p = (const uint8_t *) input;
646 
647  if (!asn1_read_tag(&p, input_end, &len, 0x30)) { /* SEQUENCE */
648  goto end;
649  }
650 
651  if (p + len != input_end) {
652  goto end;
653  }
654 
655  if (!asn1_parse_integer(&p, input_end, r, r_len)
656  || !asn1_parse_integer(&p, input_end, s, s_len)) {
657  goto end;
658  }
659 
660  if (p != input_end) { /* Check if bytes have been appended to the sequence */
661  goto end;
662  }
663 
664  if (*r_len > max_size || *s_len > max_size) {
665  return 0;
666  }
667  ret = 1;
668 end:
669  return ret;
670 }
671 
672 #endif // HAVE_ECC
Include cryptography files.
unsigned char uint8_t
Definition: usbd_conf.h:53