Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
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/* ----------------------------------------------------------------------- */
38cx_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
60end:
61 return error;
62}
63
64/* ----------------------------------------------------------------------- */
65/* */
66/* ----------------------------------------------------------------------- */
67cx_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
125OK:
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/* ----------------------------------------------------------------------- */
137cx_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
145cx_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
247end:
248 cx_bn_unlock();
249 return error;
250}
251
252cx_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
273end:
274 cx_bn_unlock();
275 return error;
276}
277
278/* ----------------------------------------------------------------------- */
279/* */
280/* ----------------------------------------------------------------------- */
281cx_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
296end:
297 cx_bn_unlock();
298 return error;
299}
300
301#ifdef HAVE_ECC_TWISTED_EDWARDS
302
303cx_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
320end:
321 cx_bn_unlock();
322 return error;
323}
324
325cx_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
342end:
343 cx_bn_unlock();
344 return error;
345}
346
347#endif // HAVE_ECC_TWISTED_EDWARDS
348
349static 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
366static 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
389static 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
399static 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
434static 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/* ----------------------------------------------------------------------- */
478size_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
510static 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
569static 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
583static 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
620end:
621 return ret;
622}
623
624/* ----------------------------------------------------------------------- */
625/* */
626/* ----------------------------------------------------------------------- */
627
628int 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;
668end:
669 return ret;
670}
671
672#endif // HAVE_ECC
Include cryptography files.
unsigned char uint8_t
Definition usbd_conf.h:53