diff options
| author | jsing <> | 2022-04-27 17:42:08 +0000 |
|---|---|---|
| committer | jsing <> | 2022-04-27 17:42:08 +0000 |
| commit | 1dab1c519c285b7655ab6fa3196fe83b7b110a56 (patch) | |
| tree | a5428a80984a8a541bb3cf621d5ae890ff0dfcff /src | |
| parent | a8d2bb1f6939a805dcd605eb24d943001c518eba (diff) | |
| download | openbsd-1dab1c519c285b7655ab6fa3196fe83b7b110a56.tar.gz openbsd-1dab1c519c285b7655ab6fa3196fe83b7b110a56.tar.bz2 openbsd-1dab1c519c285b7655ab6fa3196fe83b7b110a56.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@
Diffstat (limited to 'src')
| -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 |
