diff options
author | jsing <> | 2022-03-26 14:54:58 +0000 |
---|---|---|
committer | jsing <> | 2022-03-26 14:54:58 +0000 |
commit | 33c81c3e0f1ee210c394320c35bce015fbf8e11e (patch) | |
tree | 13e45ed0ae5c37667b0c07f86645e65bf9b2c686 /src/lib | |
parent | c6fe14d607c4444cd5cbc220cf8ca19aee4d8609 (diff) | |
download | openbsd-33c81c3e0f1ee210c394320c35bce015fbf8e11e.tar.gz openbsd-33c81c3e0f1ee210c394320c35bce015fbf8e11e.tar.bz2 openbsd-33c81c3e0f1ee210c394320c35bce015fbf8e11e.zip |
Convert c2i_ASN1_OBJECT() and d2i_ASN1_OBJECT to CBS.
Along the way, rather than having yet another piece of code that parses
OID arcs, reuse oid_parse_arc(). Always allocate a new ASN1_OBJECT rather
than doing a crazy dance with ASN1_OBJECT_FLAG_DYNAMIC and trying to free
parts of an ASN1_OBJECT if one is passed in.
ok inoguchi@ tb@
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/libcrypto/asn1/a_object.c | 173 |
1 files changed, 92 insertions, 81 deletions
diff --git a/src/lib/libcrypto/asn1/a_object.c b/src/lib/libcrypto/asn1/a_object.c index 1d94d49679..0cf649910b 100644 --- a/src/lib/libcrypto/asn1/a_object.c +++ b/src/lib/libcrypto/asn1/a_object.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: a_object.c,v 1.44 2022/03/20 13:27:23 jsing Exp $ */ | 1 | /* $OpenBSD: a_object.c,v 1.45 2022/03/26 14:54:58 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 | * |
@@ -155,12 +155,13 @@ oid_parse_arc(CBS *cbs, uint64_t *out_arc) | |||
155 | return 0; | 155 | return 0; |
156 | if (arc == 0 && val == 0x80) | 156 | if (arc == 0 && val == 0x80) |
157 | return 0; | 157 | return 0; |
158 | if (arc > (UINT64_MAX >> 7)) | 158 | if (out_arc != NULL && arc > (UINT64_MAX >> 7)) |
159 | return 0; | 159 | return 0; |
160 | arc = (arc << 7) | (val & 0x7f); | 160 | arc = (arc << 7) | (val & 0x7f); |
161 | } while (val & 0x80); | 161 | } while (val & 0x80); |
162 | 162 | ||
163 | *out_arc = arc; | 163 | if (out_arc != NULL) |
164 | *out_arc = arc; | ||
164 | 165 | ||
165 | return 1; | 166 | return 1; |
166 | } | 167 | } |
@@ -519,80 +520,81 @@ i2a_ASN1_OBJECT(BIO *bp, const ASN1_OBJECT *aobj) | |||
519 | return ret; | 520 | return ret; |
520 | } | 521 | } |
521 | 522 | ||
522 | ASN1_OBJECT * | 523 | int |
523 | c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp, long len) | 524 | c2i_ASN1_OBJECT_cbs(ASN1_OBJECT **out_aobj, CBS *content) |
524 | { | 525 | { |
525 | ASN1_OBJECT *ret; | 526 | ASN1_OBJECT *aobj = NULL; |
526 | const unsigned char *p; | 527 | uint8_t *data = NULL; |
527 | unsigned char *data; | 528 | size_t data_len; |
528 | int i, length; | 529 | CBS cbs; |
529 | 530 | ||
530 | /* | 531 | if (out_aobj == NULL || *out_aobj != NULL) |
531 | * Sanity check OID encoding: | 532 | goto err; |
532 | * - need at least one content octet | 533 | |
533 | * - MSB must be clear in the last octet | 534 | /* Parse and validate OID encoding per X.690 8.19.2. */ |
534 | * - can't have leading 0x80 in subidentifiers, see: X.690 8.19.2 | 535 | CBS_dup(content, &cbs); |
535 | */ | 536 | if (CBS_len(&cbs) == 0) { |
536 | if (len <= 0 || len > INT_MAX || pp == NULL || (p = *pp) == NULL || | ||
537 | p[len - 1] & 0x80) { | ||
538 | ASN1error(ASN1_R_INVALID_OBJECT_ENCODING); | 537 | ASN1error(ASN1_R_INVALID_OBJECT_ENCODING); |
539 | return (NULL); | 538 | goto err; |
540 | } | 539 | } |
541 | 540 | while (CBS_len(&cbs) > 0) { | |
542 | /* Now 0 < len <= INT_MAX, so the cast is safe. */ | 541 | if (!oid_parse_arc(&cbs, NULL)) { |
543 | length = (int)len; | ||
544 | for (i = 0; i < length; i++, p++) { | ||
545 | if (*p == 0x80 && (!i || !(p[-1] & 0x80))) { | ||
546 | ASN1error(ASN1_R_INVALID_OBJECT_ENCODING); | 542 | ASN1error(ASN1_R_INVALID_OBJECT_ENCODING); |
547 | return (NULL); | 543 | goto err; |
548 | } | 544 | } |
549 | } | 545 | } |
550 | 546 | ||
551 | if ((a == NULL) || ((*a) == NULL) || | 547 | if (!CBS_stow(content, &data, &data_len)) |
552 | !((*a)->flags & ASN1_OBJECT_FLAG_DYNAMIC)) { | 548 | goto err; |
553 | if ((ret = ASN1_OBJECT_new()) == NULL) | ||
554 | return (NULL); | ||
555 | } else | ||
556 | ret = *a; | ||
557 | |||
558 | p = *pp; | ||
559 | 549 | ||
560 | /* detach data from object */ | 550 | if (data_len > INT_MAX) |
561 | data = (unsigned char *)ret->data; | 551 | goto err; |
562 | freezero(data, ret->length); | ||
563 | 552 | ||
564 | data = malloc(length); | 553 | if ((aobj = ASN1_OBJECT_new()) == NULL) |
565 | if (data == NULL) { | ||
566 | ASN1error(ERR_R_MALLOC_FAILURE); | ||
567 | goto err; | 554 | goto err; |
568 | } | ||
569 | 555 | ||
570 | memcpy(data, p, length); | 556 | aobj->data = data; |
557 | aobj->length = (int)data_len; /* XXX - change length to size_t. */ | ||
558 | aobj->flags |= ASN1_OBJECT_FLAG_DYNAMIC_DATA; | ||
559 | |||
560 | *out_aobj = aobj; | ||
571 | 561 | ||
572 | /* If there are dynamic strings, free them here, and clear the flag. */ | 562 | return 1; |
573 | if ((ret->flags & ASN1_OBJECT_FLAG_DYNAMIC_STRINGS) != 0) { | 563 | |
574 | free((void *)ret->sn); | 564 | err: |
575 | free((void *)ret->ln); | 565 | ASN1_OBJECT_free(aobj); |
576 | ret->flags &= ~ASN1_OBJECT_FLAG_DYNAMIC_STRINGS; | 566 | free(data); |
567 | |||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | ASN1_OBJECT * | ||
572 | c2i_ASN1_OBJECT(ASN1_OBJECT **out_aobj, const unsigned char **pp, long len) | ||
573 | { | ||
574 | ASN1_OBJECT *aobj = NULL; | ||
575 | CBS content; | ||
576 | |||
577 | if (out_aobj != NULL) { | ||
578 | ASN1_OBJECT_free(*out_aobj); | ||
579 | *out_aobj = NULL; | ||
577 | } | 580 | } |
578 | 581 | ||
579 | /* reattach data to object, after which it remains const */ | 582 | if (len < 0) { |
580 | ret->data = data; | 583 | ASN1error(ASN1_R_LENGTH_ERROR); |
581 | ret->length = length; | 584 | return NULL; |
582 | ret->sn = NULL; | 585 | } |
583 | ret->ln = NULL; | ||
584 | ret->flags |= ASN1_OBJECT_FLAG_DYNAMIC_DATA; | ||
585 | p += length; | ||
586 | 586 | ||
587 | if (a != NULL) | 587 | CBS_init(&content, *pp, len); |
588 | *a = ret; | ||
589 | *pp = p; | ||
590 | return (ret); | ||
591 | 588 | ||
592 | err: | 589 | if (!c2i_ASN1_OBJECT_cbs(&aobj, &content)) |
593 | if (a == NULL || ret != *a) | 590 | return NULL; |
594 | ASN1_OBJECT_free(ret); | 591 | |
595 | return (NULL); | 592 | *pp = CBS_data(&content); |
593 | |||
594 | if (out_aobj != NULL) | ||
595 | *out_aobj = aobj; | ||
596 | |||
597 | return aobj; | ||
596 | } | 598 | } |
597 | 599 | ||
598 | int | 600 | int |
@@ -618,31 +620,40 @@ i2d_ASN1_OBJECT(const ASN1_OBJECT *a, unsigned char **pp) | |||
618 | } | 620 | } |
619 | 621 | ||
620 | ASN1_OBJECT * | 622 | ASN1_OBJECT * |
621 | d2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp, long length) | 623 | d2i_ASN1_OBJECT(ASN1_OBJECT **out_aobj, const unsigned char **pp, long length) |
622 | { | 624 | { |
623 | const unsigned char *p; | 625 | ASN1_OBJECT *aobj = NULL; |
624 | long len; | 626 | uint32_t tag_number; |
625 | int tag, xclass; | 627 | CBS cbs, content; |
626 | int inf, i; | ||
627 | ASN1_OBJECT *ret = NULL; | ||
628 | 628 | ||
629 | p = *pp; | 629 | if (out_aobj != NULL) { |
630 | inf = ASN1_get_object(&p, &len, &tag, &xclass, length); | 630 | ASN1_OBJECT_free(*out_aobj); |
631 | if (inf & 0x80) { | 631 | *out_aobj = NULL; |
632 | i = ASN1_R_BAD_OBJECT_HEADER; | ||
633 | goto err; | ||
634 | } | 632 | } |
635 | 633 | ||
636 | if (tag != V_ASN1_OBJECT) { | 634 | if (length < 0) { |
637 | i = ASN1_R_EXPECTING_AN_OBJECT; | 635 | ASN1error(ASN1_R_LENGTH_ERROR); |
638 | goto err; | 636 | return NULL; |
639 | } | 637 | } |
640 | ret = c2i_ASN1_OBJECT(a, &p, len); | ||
641 | if (ret) | ||
642 | *pp = p; | ||
643 | return ret; | ||
644 | 638 | ||
645 | err: | 639 | CBS_init(&cbs, *pp, length); |
646 | ASN1error(i); | 640 | |
647 | return (NULL); | 641 | if (!asn1_get_primitive(&cbs, 0, &tag_number, &content)) { |
642 | ASN1error(ASN1_R_BAD_OBJECT_HEADER); | ||
643 | return NULL; | ||
644 | } | ||
645 | if (tag_number != V_ASN1_OBJECT) { | ||
646 | ASN1error(ASN1_R_EXPECTING_AN_OBJECT); | ||
647 | return NULL; | ||
648 | } | ||
649 | |||
650 | if (!c2i_ASN1_OBJECT_cbs(&aobj, &content)) | ||
651 | return NULL; | ||
652 | |||
653 | *pp = CBS_data(&content); | ||
654 | |||
655 | if (out_aobj != NULL) | ||
656 | *out_aobj = aobj; | ||
657 | |||
658 | return aobj; | ||
648 | } | 659 | } |