diff options
author | jsing <> | 2023-05-28 10:34:17 +0000 |
---|---|---|
committer | jsing <> | 2023-05-28 10:34:17 +0000 |
commit | 5e6b0540238c981b8b8d04ce22ec411533860222 (patch) | |
tree | 63ba3aab3d0858fe20ca0250c3e68fb563dd2ea0 /src | |
parent | ce5a260afb8e68d35e4e7d5d0a4a86a2e0c94e84 (diff) | |
download | openbsd-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.c | 347 |
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 | ||
73 | static int bn_dec2bn_cbs(BIGNUM **bnp, CBS *cbs); | ||
74 | static int bn_hex2bn_cbs(BIGNUM **bnp, CBS *cbs); | ||
75 | |||
73 | static const char hex_digits[] = "0123456789ABCDEF"; | 76 | static const char hex_digits[] = "0123456789ABCDEF"; |
74 | 77 | ||
75 | typedef enum { | 78 | typedef enum { |
@@ -253,21 +256,53 @@ BN_lebin2bn(const unsigned char *s, int len, BIGNUM *ret) | |||
253 | } | 256 | } |
254 | 257 | ||
255 | int | 258 | int |
256 | BN_asc2bn(BIGNUM **bn, const char *a) | 259 | BN_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 | ||
352 | int | 387 | static int |
353 | BN_dec2bn(BIGNUM **bn, const char *a) | 388 | bn_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 | ||
415 | err: | 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 | |||
472 | int | ||
473 | BN_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 | ||
421 | char * | 491 | char * |
@@ -463,81 +533,112 @@ BN_bn2hex(const BIGNUM *bn) | |||
463 | return s; | 533 | return s; |
464 | } | 534 | } |
465 | 535 | ||
466 | int | 536 | static int |
467 | BN_hex2bn(BIGNUM **bn, const char *a) | 537 | bn_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 | |||
625 | int | ||
626 | BN_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 | ||
537 | err: | 641 | return bn_hex2bn_cbs(bnp, &cbs); |
538 | if (*bn == NULL) | ||
539 | BN_free(ret); | ||
540 | return (0); | ||
541 | } | 642 | } |
542 | 643 | ||
543 | int | 644 | int |