diff options
author | jsing <> | 2022-04-27 17:42:08 +0000 |
---|---|---|
committer | jsing <> | 2022-04-27 17:42:08 +0000 |
commit | 9b4f52bd67002c10a6a97a6b20cb7c61be0a2cee (patch) | |
tree | a5428a80984a8a541bb3cf621d5ae890ff0dfcff | |
parent | 066ee7e25f2f9510191df30325a50ed15a2b910a (diff) | |
download | openbsd-9b4f52bd67002c10a6a97a6b20cb7c61be0a2cee.tar.gz openbsd-9b4f52bd67002c10a6a97a6b20cb7c61be0a2cee.tar.bz2 openbsd-9b4f52bd67002c10a6a97a6b20cb7c61be0a2cee.zip |
Rewrite c2i_ASN1_INTEGER() using CBS.
This also makes validation stricter and inline with X.690 - we now reject
zero length inputs (rather than treating them as zero values) and enforce
minimal encoding.
ok tb@
-rw-r--r-- | src/lib/libcrypto/asn1/a_int.c | 213 |
1 files changed, 129 insertions, 84 deletions
diff --git a/src/lib/libcrypto/asn1/a_int.c b/src/lib/libcrypto/asn1/a_int.c index c4b40ff7a4..aa4421c0e0 100644 --- a/src/lib/libcrypto/asn1/a_int.c +++ b/src/lib/libcrypto/asn1/a_int.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: a_int.c,v 1.38 2021/12/25 13:17:48 jsing Exp $ */ | 1 | /* $OpenBSD: a_int.c,v 1.39 2022/04/27 17:42:08 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 | * |
@@ -66,6 +66,8 @@ | |||
66 | #include <openssl/buffer.h> | 66 | #include <openssl/buffer.h> |
67 | #include <openssl/err.h> | 67 | #include <openssl/err.h> |
68 | 68 | ||
69 | #include "bytestring.h" | ||
70 | |||
69 | const ASN1_ITEM ASN1_INTEGER_it = { | 71 | const ASN1_ITEM ASN1_INTEGER_it = { |
70 | .itype = ASN1_ITYPE_PRIMITIVE, | 72 | .itype = ASN1_ITYPE_PRIMITIVE, |
71 | .utype = V_ASN1_INTEGER, | 73 | .utype = V_ASN1_INTEGER, |
@@ -486,104 +488,147 @@ i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp) | |||
486 | return (ret); | 488 | return (ret); |
487 | } | 489 | } |
488 | 490 | ||
489 | /* Convert just ASN1 INTEGER content octets to ASN1_INTEGER structure */ | 491 | static void |
490 | 492 | asn1_aint_twos_complement(uint8_t *data, size_t data_len) | |
491 | ASN1_INTEGER * | ||
492 | c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp, long len) | ||
493 | { | 493 | { |
494 | ASN1_INTEGER *ret = NULL; | 494 | uint8_t carry = 1; |
495 | const unsigned char *p, *pend; | 495 | ssize_t i; |
496 | unsigned char *to, *s; | ||
497 | int i; | ||
498 | 496 | ||
499 | if ((a == NULL) || ((*a) == NULL)) { | 497 | for (i = data_len - 1; i >= 0; i--) { |
500 | if ((ret = ASN1_INTEGER_new()) == NULL) | 498 | data[i] = (data[i] ^ 0xff) + carry; |
501 | return (NULL); | 499 | if (data[i] != 0) |
502 | } else | 500 | carry = 0; |
503 | ret = (*a); | 501 | } |
502 | } | ||
504 | 503 | ||
505 | if (!ASN1_INTEGER_valid(ret)) { | 504 | static int |
506 | /* | 505 | asn1_aint_keep_twos_padding(const uint8_t *data, size_t data_len) |
507 | * XXX using i for an alert is confusing, | 506 | { |
508 | * we should call this al | 507 | size_t i; |
509 | */ | 508 | |
510 | i = ERR_R_ASN1_LENGTH_MISMATCH; | 509 | /* |
511 | goto err; | 510 | * If a two's complement value has a padding byte (0xff) and the rest |
511 | * of the value is all zeros, the padding byte cannot be removed as when | ||
512 | * converted from two's complement this becomes 0x01 (in the place of | ||
513 | * the padding byte) followed by the same number of zero bytes. | ||
514 | */ | ||
515 | if (data_len <= 1 || data[0] != 0xff) | ||
516 | return 0; | ||
517 | for (i = 1; i < data_len; i++) { | ||
518 | if (data[i] != 0) | ||
519 | return 0; | ||
512 | } | 520 | } |
521 | return 1; | ||
522 | } | ||
513 | 523 | ||
514 | p = *pp; | 524 | int |
515 | pend = p + len; | 525 | c2i_ASN1_INTEGER_cbs(ASN1_INTEGER **out_aint, CBS *cbs) |
526 | { | ||
527 | ASN1_INTEGER *aint = NULL; | ||
528 | uint8_t *data = NULL; | ||
529 | size_t data_len = 0; | ||
530 | uint8_t padding, val; | ||
531 | uint8_t negative = 0; | ||
532 | int ret = 0; | ||
516 | 533 | ||
517 | /* We must malloc stuff, even for 0 bytes otherwise it | 534 | if (out_aint == NULL) |
518 | * signifies a missing NULL parameter. */ | ||
519 | if (len < 0 || len > INT_MAX) { | ||
520 | i = ERR_R_ASN1_LENGTH_MISMATCH; | ||
521 | goto err; | 535 | goto err; |
536 | |||
537 | if (*out_aint != NULL) { | ||
538 | ASN1_INTEGER_free(*out_aint); | ||
539 | *out_aint = NULL; | ||
522 | } | 540 | } |
523 | s = malloc(len + 1); | 541 | |
524 | if (s == NULL) { | 542 | if (CBS_len(cbs) == 0) { |
525 | i = ERR_R_MALLOC_FAILURE; | 543 | /* XXX INVALID ENCODING? */ |
544 | ASN1error(ERR_R_ASN1_LENGTH_MISMATCH); | ||
526 | goto err; | 545 | goto err; |
527 | } | 546 | } |
528 | to = s; | 547 | if (!CBS_peek_u8(cbs, &val)) |
529 | if (!len) { | 548 | goto err; |
530 | /* Strictly speaking this is an illegal INTEGER but we | 549 | |
531 | * tolerate it. | 550 | /* Top most bit indicates sign, padding is all zeros or all ones. */ |
532 | */ | 551 | negative = (val >> 7); |
533 | ret->type = V_ASN1_INTEGER; | 552 | padding = ~(negative - 1) & 0xff; |
534 | } else if (*p & 0x80) /* a negative number */ { | 553 | |
535 | ret->type = V_ASN1_NEG_INTEGER; | 554 | /* |
536 | if ((*p == 0xff) && (len != 1)) { | 555 | * Ensure that the first 9 bits are not all zero or all one, as per |
537 | p++; | 556 | * X.690 section 8.3.2. Remove the padding octet if possible. |
538 | len--; | 557 | */ |
539 | } | 558 | if (CBS_len(cbs) > 1 && val == padding) { |
540 | i = len; | 559 | if (!asn1_aint_keep_twos_padding(CBS_data(cbs), CBS_len(cbs))) { |
541 | p += i - 1; | 560 | if (!CBS_get_u8(cbs, &padding)) |
542 | to += i - 1; | 561 | goto err; |
543 | while((!*p) && i) { | 562 | if (!CBS_peek_u8(cbs, &val)) |
544 | *(to--) = 0; | 563 | goto err; |
545 | i--; | 564 | if ((val >> 7) == (padding >> 7)) { |
546 | p--; | 565 | /* XXX INVALID ENCODING? */ |
547 | } | 566 | ASN1error(ERR_R_ASN1_LENGTH_MISMATCH); |
548 | /* Special case: if all zeros then the number will be of | 567 | goto err; |
549 | * the form FF followed by n zero bytes: this corresponds to | 568 | } |
550 | * 1 followed by n zero bytes. We've already written n zeros | ||
551 | * so we just append an extra one and set the first byte to | ||
552 | * a 1. This is treated separately because it is the only case | ||
553 | * where the number of bytes is larger than len. | ||
554 | */ | ||
555 | if (!i) { | ||
556 | *s = 1; | ||
557 | s[len] = 0; | ||
558 | len++; | ||
559 | } else { | ||
560 | *(to--) = (*(p--) ^ 0xff) + 1; | ||
561 | i--; | ||
562 | for (; i > 0; i--) | ||
563 | *(to--) = *(p--) ^ 0xff; | ||
564 | } | ||
565 | } else { | ||
566 | ret->type = V_ASN1_INTEGER; | ||
567 | if ((*p == 0) && (len != 1)) { | ||
568 | p++; | ||
569 | len--; | ||
570 | } | 569 | } |
571 | memcpy(s, p, len); | ||
572 | } | 570 | } |
573 | 571 | ||
574 | free(ret->data); | 572 | if (!CBS_stow(cbs, &data, &data_len)) |
575 | ret->data = s; | 573 | goto err; |
576 | ret->length = (int)len; | 574 | if (data_len > INT_MAX) |
577 | if (a != NULL) | 575 | goto err; |
578 | (*a) = ret; | 576 | |
579 | *pp = pend; | 577 | if ((aint = ASN1_INTEGER_new()) == NULL) |
580 | return (ret); | 578 | goto err; |
579 | |||
580 | /* | ||
581 | * Negative integers are handled as a separate type - convert from | ||
582 | * two's complement for internal representation. | ||
583 | */ | ||
584 | if (negative) { | ||
585 | aint->type = V_ASN1_NEG_INTEGER; | ||
586 | asn1_aint_twos_complement(data, data_len); | ||
587 | } | ||
588 | |||
589 | aint->data = data; | ||
590 | aint->length = (int)data_len; | ||
591 | data = NULL; | ||
592 | |||
593 | *out_aint = aint; | ||
594 | aint = NULL; | ||
595 | |||
596 | ret = 1; | ||
581 | 597 | ||
582 | err: | 598 | err: |
583 | ASN1error(i); | 599 | ASN1_INTEGER_free(aint); |
584 | if (a == NULL || *a != ret) | 600 | freezero(data, data_len); |
585 | ASN1_INTEGER_free(ret); | 601 | |
586 | return (NULL); | 602 | return ret; |
603 | } | ||
604 | |||
605 | ASN1_INTEGER * | ||
606 | c2i_ASN1_INTEGER(ASN1_INTEGER **out_aint, const unsigned char **pp, long len) | ||
607 | { | ||
608 | ASN1_INTEGER *aint = NULL; | ||
609 | CBS content; | ||
610 | |||
611 | if (out_aint != NULL) { | ||
612 | ASN1_INTEGER_free(*out_aint); | ||
613 | *out_aint = NULL; | ||
614 | } | ||
615 | |||
616 | if (len < 0) { | ||
617 | ASN1error(ASN1_R_LENGTH_ERROR); | ||
618 | return NULL; | ||
619 | } | ||
620 | |||
621 | CBS_init(&content, *pp, len); | ||
622 | |||
623 | if (!c2i_ASN1_INTEGER_cbs(&aint, &content)) | ||
624 | return NULL; | ||
625 | |||
626 | *pp = CBS_data(&content); | ||
627 | |||
628 | if (out_aint != NULL) | ||
629 | *out_aint = aint; | ||
630 | |||
631 | return aint; | ||
587 | } | 632 | } |
588 | 633 | ||
589 | int | 634 | int |