summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjsing <>2023-05-28 10:34:17 +0000
committerjsing <>2023-05-28 10:34:17 +0000
commit5e6b0540238c981b8b8d04ce22ec411533860222 (patch)
tree63ba3aab3d0858fe20ca0250c3e68fb563dd2ea0 /src
parentce5a260afb8e68d35e4e7d5d0a4a86a2e0c94e84 (diff)
downloadopenbsd-5e6b0540238c981b8b8d04ce22ec411533860222.tar.gz
openbsd-5e6b0540238c981b8b8d04ce22ec411533860222.tar.bz2
openbsd-5e6b0540238c981b8b8d04ce22ec411533860222.zip
Rewrite BN_{asc,dec,hex}2bn() using CBS.
This gives us more readable and safer code. There are two intentional changes to behaviour - firstly, all three functions zero any BN that was passed in, prior to doing any further processing. This means that a passed BN is always in a known state, regardless of what happens later. Secondly, BN_asc2bn() now fails on NULL input, rather than crashing. This brings its behaviour inline with BN_dec2bn() and BN_hex2bn(). ok tb@
Diffstat (limited to 'src')
-rw-r--r--src/lib/libcrypto/bn/bn_convert.c347
1 files changed, 224 insertions, 123 deletions
diff --git a/src/lib/libcrypto/bn/bn_convert.c b/src/lib/libcrypto/bn/bn_convert.c
index 65834ffd1e..1a3abbc603 100644
--- a/src/lib/libcrypto/bn/bn_convert.c
+++ b/src/lib/libcrypto/bn/bn_convert.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: bn_convert.c,v 1.8 2023/05/09 05:15:55 jsing Exp $ */ 1/* $OpenBSD: bn_convert.c,v 1.9 2023/05/28 10:34:17 jsing Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
@@ -70,6 +70,9 @@
70#include "bn_local.h" 70#include "bn_local.h"
71#include "bytestring.h" 71#include "bytestring.h"
72 72
73static int bn_dec2bn_cbs(BIGNUM **bnp, CBS *cbs);
74static int bn_hex2bn_cbs(BIGNUM **bnp, CBS *cbs);
75
73static const char hex_digits[] = "0123456789ABCDEF"; 76static const char hex_digits[] = "0123456789ABCDEF";
74 77
75typedef enum { 78typedef enum {
@@ -253,21 +256,53 @@ BN_lebin2bn(const unsigned char *s, int len, BIGNUM *ret)
253} 256}
254 257
255int 258int
256BN_asc2bn(BIGNUM **bn, const char *a) 259BN_asc2bn(BIGNUM **bnp, const char *s)
257{ 260{
258 const char *p = a; 261 CBS cbs, cbs_hex;
259 if (*p == '-') 262 size_t s_len;
260 p++; 263 uint8_t v;
264 int neg;
261 265
262 if (p[0] == '0' && (p[1] == 'X' || p[1] == 'x')) { 266 if (bnp != NULL && *bnp != NULL)
263 if (!BN_hex2bn(bn, p + 2)) 267 BN_zero(*bnp);
264 return 0; 268
265 } else { 269 if (s == NULL)
266 if (!BN_dec2bn(bn, p)) 270 return 0;
271 if ((s_len = strlen(s)) == 0)
272 return 0;
273
274 CBS_init(&cbs, s, s_len);
275
276 /* Handle negative sign. */
277 if (!CBS_peek_u8(&cbs, &v))
278 return 0;
279 if ((neg = (v == '-'))) {
280 if (!CBS_skip(&cbs, 1))
267 return 0; 281 return 0;
268 } 282 }
269 if (*a == '-') 283
270 BN_set_negative(*bn, 1); 284 /* Try parsing as hexidecimal with a 0x prefix. */
285 CBS_dup(&cbs, &cbs_hex);
286 if (!CBS_get_u8(&cbs_hex, &v))
287 goto decimal;
288 if (v != '0')
289 goto decimal;
290 if (!CBS_get_u8(&cbs_hex, &v))
291 goto decimal;
292 if (v != 'X' && v != 'x')
293 goto decimal;
294 if (!bn_hex2bn_cbs(bnp, &cbs_hex))
295 return 0;
296
297 goto done;
298
299 decimal:
300 if (!bn_dec2bn_cbs(bnp, &cbs))
301 return 0;
302
303 done:
304 BN_set_negative(*bnp, neg);
305
271 return 1; 306 return 1;
272} 307}
273 308
@@ -349,73 +384,108 @@ BN_bn2dec(const BIGNUM *bn)
349 return s; 384 return s;
350} 385}
351 386
352int 387static int
353BN_dec2bn(BIGNUM **bn, const char *a) 388bn_dec2bn_cbs(BIGNUM **bnp, CBS *cbs)
354{ 389{
355 BIGNUM *ret = NULL; 390 CBS cbs_digits;
356 BN_ULONG l = 0; 391 BIGNUM *bn = NULL;
357 int neg = 0, i, j; 392 int d, neg, num;
358 int num; 393 size_t digits = 0;
394 BN_ULONG w;
395 uint8_t v;
359 396
360 if ((a == NULL) || (*a == '\0')) 397 /* Handle negative sign. */
361 return (0); 398 if (!CBS_peek_u8(cbs, &v))
362 if (*a == '-') { 399 goto err;
363 neg = 1; 400 if ((neg = (v == '-'))) {
364 a++; 401 if (!CBS_skip(cbs, 1))
402 goto err;
365 } 403 }
366 404
367 for (i = 0; i <= (INT_MAX / 4) && isdigit((unsigned char)a[i]); i++) 405 /* Scan to find last decimal digit. */
368 ; 406 CBS_dup(cbs, &cbs_digits);
369 if (i > INT_MAX / 4) 407 while (CBS_len(&cbs_digits) > 0) {
370 return (0); 408 if (!CBS_get_u8(&cbs_digits, &v))
371 409 goto err;
372 num = i + neg; 410 if (!isdigit(v))
373 if (bn == NULL) 411 break;
374 return (num); 412 digits++;
375
376 /* a is the start of the digits, and it is 'i' long.
377 * We chop it into BN_DEC_NUM digits at a time */
378 if (*bn == NULL) {
379 if ((ret = BN_new()) == NULL)
380 return (0);
381 } else {
382 ret = *bn;
383 BN_zero(ret);
384 } 413 }
414 if (digits > INT_MAX / 4)
415 goto err;
385 416
386 /* i is the number of digits, a bit of an over expand */ 417 num = digits + neg;
387 if (!bn_expand(ret, i * 4)) 418
419 if (bnp == NULL)
420 return num;
421
422 if ((bn = *bnp) == NULL)
423 bn = BN_new();
424 if (bn == NULL)
425 goto err;
426 if (!bn_expand(bn, digits * 4))
388 goto err; 427 goto err;
389 428
390 j = BN_DEC_NUM - (i % BN_DEC_NUM); 429 if ((d = digits % BN_DEC_NUM) == 0)
391 if (j == BN_DEC_NUM) 430 d = BN_DEC_NUM;
392 j = 0; 431
393 l = 0; 432 w = 0;
394 while (*a) { 433
395 l *= 10; 434 /* Work forwards from most significant digit. */
396 l += *a - '0'; 435 while (digits-- > 0) {
397 a++; 436 if (!CBS_get_u8(cbs, &v))
398 if (++j == BN_DEC_NUM) { 437 goto err;
399 if (!BN_mul_word(ret, BN_DEC_CONV)) 438
439 if (v < '0' || v > '9')
440 goto err;
441
442 v -= '0';
443 w = w * 10 + v;
444 d--;
445
446 if (d == 0) {
447 if (!BN_mul_word(bn, BN_DEC_CONV))
400 goto err; 448 goto err;
401 if (!BN_add_word(ret, l)) 449 if (!BN_add_word(bn, w))
402 goto err; 450 goto err;
403 l = 0; 451
404 j = 0; 452 d = BN_DEC_NUM;
453 w = 0;
405 } 454 }
406 } 455 }
407 456
408 bn_correct_top(ret); 457 bn_correct_top(bn);
409 458
410 BN_set_negative(ret, neg); 459 BN_set_negative(bn, neg);
411 460
412 *bn = ret; 461 *bnp = bn;
413 return (num);
414 462
415err: 463 return num;
416 if (*bn == NULL) 464
417 BN_free(ret); 465 err:
418 return (0); 466 if (bnp != NULL && *bnp == NULL)
467 BN_free(bn);
468
469 return 0;
470}
471
472int
473BN_dec2bn(BIGNUM **bnp, const char *s)
474{
475 size_t s_len;
476 CBS cbs;
477
478 if (bnp != NULL && *bnp != NULL)
479 BN_zero(*bnp);
480
481 if (s == NULL)
482 return 0;
483 if ((s_len = strlen(s)) == 0)
484 return 0;
485
486 CBS_init(&cbs, s, s_len);
487
488 return bn_dec2bn_cbs(bnp, &cbs);
419} 489}
420 490
421char * 491char *
@@ -463,81 +533,112 @@ BN_bn2hex(const BIGNUM *bn)
463 return s; 533 return s;
464} 534}
465 535
466int 536static int
467BN_hex2bn(BIGNUM **bn, const char *a) 537bn_hex2bn_cbs(BIGNUM **bnp, CBS *cbs)
468{ 538{
469 BIGNUM *ret = NULL; 539 CBS cbs_digits;
470 BN_ULONG l = 0; 540 BIGNUM *bn = NULL;
471 int neg = 0, h, m, i,j, k, c; 541 int b, i, neg, num;
472 int num; 542 size_t digits = 0;
543 BN_ULONG w;
544 uint8_t v;
473 545
474 if ((a == NULL) || (*a == '\0')) 546 /* Handle negative sign. */
475 return (0); 547 if (!CBS_peek_u8(cbs, &v))
548 goto err;
549 if ((neg = (v == '-'))) {
550 if (!CBS_skip(cbs, 1))
551 goto err;
552 }
476 553
477 if (*a == '-') { 554 /* Scan to find last hexadecimal digit. */
478 neg = 1; 555 CBS_dup(cbs, &cbs_digits);
479 a++; 556 while (CBS_len(&cbs_digits) > 0) {
557 if (!CBS_get_u8(&cbs_digits, &v))
558 goto err;
559 if (!isxdigit(v))
560 break;
561 digits++;
480 } 562 }
563 if (digits > INT_MAX / 4)
564 goto err;
481 565
482 for (i = 0; i <= (INT_MAX / 4) && isxdigit((unsigned char)a[i]); i++) 566 num = digits + neg;
483 ; 567
484 if (i > INT_MAX / 4) 568 if (bnp == NULL)
485 return (0); 569 return num;
486 570
487 num = i + neg; 571 if ((bn = *bnp) == NULL)
572 bn = BN_new();
488 if (bn == NULL) 573 if (bn == NULL)
489 return (num); 574 goto err;
490 575 if (!bn_expand(bn, digits * 4))
491 /* a is the start of the hex digits, and it is 'i' long */ 576 goto err;
492 if (*bn == NULL) {
493 if ((ret = BN_new()) == NULL)
494 return (0);
495 } else {
496 ret = *bn;
497 BN_zero(ret);
498 }
499 577
500 /* i is the number of hex digits */ 578 if (!CBS_get_bytes(cbs, cbs, digits))
501 if (!bn_expand(ret, i * 4))
502 goto err; 579 goto err;
503 580
504 j = i; /* least significant 'hex' */ 581 b = BN_BITS2;
505 m = 0; 582 i = 0;
506 h = 0; 583 w = 0;
507 while (j > 0) { 584
508 m = ((BN_BYTES * 2) <= j) ? (BN_BYTES * 2) : j; 585 /* Work backwards from least significant digit. */
509 l = 0; 586 while (digits-- > 0) {
510 for (;;) { 587 if (!CBS_get_last_u8(cbs, &v))
511 c = a[j - m]; 588 goto err;
512 if ((c >= '0') && (c <= '9')) 589
513 k = c - '0'; 590 if (v >= '0' && v <= '9')
514 else if ((c >= 'a') && (c <= 'f')) 591 v -= '0';
515 k = c - 'a' + 10; 592 else if (v >= 'a' && v <= 'f')
516 else if ((c >= 'A') && (c <= 'F')) 593 v -= 'a' - 10;
517 k = c - 'A' + 10; 594 else if (v >= 'A' && v <= 'F')
518 else 595 v -= 'A' - 10;
519 k = 0; /* paranoia */ 596 else
520 l = (l << 4) | k; 597 goto err;
521 598
522 if (--m <= 0) { 599 w |= (BN_ULONG)v << (BN_BITS2 - b);
523 ret->d[h++] = l; 600 b -= 4;
524 break; 601
525 } 602 if (b == 0 || digits == 0) {
603 b = BN_BITS2;
604 bn->d[i++] = w;
605 w = 0;
526 } 606 }
527 j -= (BN_BYTES * 2);
528 } 607 }
529 ret->top = h;
530 bn_correct_top(ret);
531 608
532 BN_set_negative(ret, neg); 609 bn->top = i;
610 bn_correct_top(bn);
611
612 BN_set_negative(bn, neg);
613
614 *bnp = bn;
615
616 return num;
617
618 err:
619 if (bnp != NULL && *bnp == NULL)
620 BN_free(bn);
621
622 return 0;
623}
624
625int
626BN_hex2bn(BIGNUM **bnp, const char *s)
627{
628 size_t s_len;
629 CBS cbs;
630
631 if (bnp != NULL && *bnp != NULL)
632 BN_zero(*bnp);
633
634 if (s == NULL)
635 return 0;
636 if ((s_len = strlen(s)) == 0)
637 return 0;
533 638
534 *bn = ret; 639 CBS_init(&cbs, s, s_len);
535 return (num);
536 640
537err: 641 return bn_hex2bn_cbs(bnp, &cbs);
538 if (*bn == NULL)
539 BN_free(ret);
540 return (0);
541} 642}
542 643
543int 644int