summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjsing <>2022-08-20 18:17:33 +0000
committerjsing <>2022-08-20 18:17:33 +0000
commit1f514c7f37e83673996474309b61dfea3714ed3c (patch)
tree4cb9ef4b674abb64415461782d6fc9a836aa8d14
parent8ac1b2953068d5c968e516c4bd4ab89d61c5f3d6 (diff)
downloadopenbsd-1f514c7f37e83673996474309b61dfea3714ed3c.tar.gz
openbsd-1f514c7f37e83673996474309b61dfea3714ed3c.tar.bz2
openbsd-1f514c7f37e83673996474309b61dfea3714ed3c.zip
Rewrite i2c_ASN1_INTEGER() using CBB/CBS.
This gives us cleaner and safer code, although it is worth noting that we now generate the encoding even when called with NULL as the output pointer (and then discard it, returning just the length). Resolves oss-fuzz #49963. ok tb@
-rw-r--r--src/lib/libcrypto/asn1/a_int.c197
1 files changed, 100 insertions, 97 deletions
diff --git a/src/lib/libcrypto/asn1/a_int.c b/src/lib/libcrypto/asn1/a_int.c
index d7790c787d..6a24c5183c 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.44 2022/07/13 20:07:44 jsing Exp $ */ 1/* $OpenBSD: a_int.c,v 1.45 2022/08/20 18:17:33 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 *
@@ -510,100 +510,6 @@ a2i_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *bs, char *buf, int size)
510 return (ret); 510 return (ret);
511} 511}
512 512
513/*
514 * This converts an ASN1 INTEGER into its content encoding.
515 * The internal representation is an ASN1_STRING whose data is a big endian
516 * representation of the value, ignoring the sign. The sign is determined by
517 * the type: V_ASN1_INTEGER for positive and V_ASN1_NEG_INTEGER for negative.
518 *
519 * Positive integers are no problem: they are almost the same as the DER
520 * encoding, except if the first byte is >= 0x80 we need to add a zero pad.
521 *
522 * Negative integers are a bit trickier...
523 * The DER representation of negative integers is in 2s complement form.
524 * The internal form is converted by complementing each octet and finally
525 * adding one to the result. This can be done less messily with a little trick.
526 * If the internal form has trailing zeroes then they will become FF by the
527 * complement and 0 by the add one (due to carry) so just copy as many trailing
528 * zeros to the destination as there are in the source. The carry will add one
529 * to the last none zero octet: so complement this octet and add one and finally
530 * complement any left over until you get to the start of the string.
531 *
532 * Padding is a little trickier too. If the first bytes is > 0x80 then we pad
533 * with 0xff. However if the first byte is 0x80 and one of the following bytes
534 * is non-zero we pad with 0xff. The reason for this distinction is that 0x80
535 * followed by optional zeros isn't padded.
536 */
537
538int
539i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp)
540{
541 int pad = 0, ret, i, neg;
542 unsigned char *p, *n, pb = 0;
543
544 if (!ASN1_INTEGER_valid(a))
545 return 0;
546
547 neg = a->type & V_ASN1_NEG;
548 if (a->length == 0)
549 ret = 1;
550 else {
551 ret = a->length;
552 i = a->data[0];
553 if (!neg && (i > 127)) {
554 pad = 1;
555 pb = 0;
556 } else if (neg) {
557 if (i > 128) {
558 pad = 1;
559 pb = 0xFF;
560 } else if (i == 128) {
561 /*
562 * Special case: if any other bytes non zero we pad:
563 * otherwise we don't.
564 */
565 for (i = 1; i < a->length; i++) if (a->data[i]) {
566 pad = 1;
567 pb = 0xFF;
568 break;
569 }
570 }
571 }
572 ret += pad;
573 }
574 if (pp == NULL)
575 return (ret);
576 p= *pp;
577
578 if (pad)
579 *(p++) = pb;
580 if (a->length == 0)
581 *(p++) = 0;
582 else if (!neg)
583 memcpy(p, a->data, a->length);
584 else {
585 /* Begin at the end of the encoding */
586 n = a->data + a->length - 1;
587 p += a->length - 1;
588 i = a->length;
589 /* Copy zeros to destination as long as source is zero */
590 while (!*n) {
591 *(p--) = 0;
592 n--;
593 i--;
594 }
595 /* Complement and increment next octet */
596 *(p--) = ((*(n--)) ^ 0xff) + 1;
597 i--;
598 /* Complement any octets left */
599 for (; i > 0; i--)
600 *(p--) = *(n--) ^ 0xff;
601 }
602
603 *pp += ret;
604 return (ret);
605}
606
607static void 513static void
608asn1_aint_twos_complement(uint8_t *data, size_t data_len) 514asn1_aint_twos_complement(uint8_t *data, size_t data_len)
609{ 515{
@@ -637,6 +543,103 @@ asn1_aint_keep_twos_padding(const uint8_t *data, size_t data_len)
637 return 1; 543 return 1;
638} 544}
639 545
546static int
547i2c_ASN1_INTEGER_cbb(ASN1_INTEGER *aint, CBB *cbb)
548{
549 uint8_t *data = NULL;
550 size_t data_len = 0;
551 uint8_t padding, val;
552 uint8_t msb;
553 CBS cbs;
554 int ret = 0;
555
556 if (aint->data == NULL || aint->length < 0)
557 goto err;
558
559 if ((aint->type & ~V_ASN1_NEG) != V_ASN1_ENUMERATED &&
560 (aint->type & ~V_ASN1_NEG) != V_ASN1_INTEGER)
561 goto err;
562
563 CBS_init(&cbs, aint->data, aint->length);
564
565 /* Find the first non-zero byte. */
566 while (CBS_len(&cbs) > 0) {
567 if (!CBS_peek_u8(&cbs, &val))
568 goto err;
569 if (val != 0)
570 break;
571 if (!CBS_skip(&cbs, 1))
572 goto err;
573 }
574
575 /* A zero value is encoded as a single octet. */
576 if (CBS_len(&cbs) == 0) {
577 if (!CBB_add_u8(cbb, 0))
578 goto err;
579 goto done;
580 }
581
582 if (!CBS_stow(&cbs, &data, &data_len))
583 goto err;
584
585 if ((aint->type & V_ASN1_NEG) != 0)
586 asn1_aint_twos_complement(data, data_len);
587
588 /* Topmost bit indicates sign, padding is all zeros or all ones. */
589 msb = (data[0] >> 7);
590 padding = (msb - 1) & 0xff;
591
592 /* See if we need a padding octet to avoid incorrect sign. */
593 if (((aint->type & V_ASN1_NEG) == 0 && msb == 1) ||
594 ((aint->type & V_ASN1_NEG) != 0 && msb == 0)) {
595 if (!CBB_add_u8(cbb, padding))
596 goto err;
597 }
598 if (!CBB_add_bytes(cbb, data, data_len))
599 goto err;
600
601 done:
602 ret = 1;
603
604 err:
605 freezero(data, data_len);
606
607 return ret;
608}
609
610int
611i2c_ASN1_INTEGER(ASN1_INTEGER *aint, unsigned char **pp)
612{
613 uint8_t *data = NULL;
614 size_t data_len = 0;
615 CBB cbb;
616 int ret = -3;
617
618 if (!CBB_init(&cbb, 0))
619 goto err;
620 if (!i2c_ASN1_INTEGER_cbb(aint, &cbb))
621 goto err;
622 if (!CBB_finish(&cbb, &data, &data_len))
623 goto err;
624 if (data_len > INT_MAX)
625 goto err;
626
627 if (pp != NULL) {
628 if ((uintptr_t)*pp > UINTPTR_MAX - data_len)
629 goto err;
630 memcpy(*pp, data, data_len);
631 *pp += data_len;
632 }
633
634 ret = data_len;
635
636 err:
637 freezero(data, data_len);
638 CBB_cleanup(&cbb);
639
640 return ret;
641}
642
640int 643int
641c2i_ASN1_INTEGER_cbs(ASN1_INTEGER **out_aint, CBS *cbs) 644c2i_ASN1_INTEGER_cbs(ASN1_INTEGER **out_aint, CBS *cbs)
642{ 645{
@@ -644,7 +647,7 @@ c2i_ASN1_INTEGER_cbs(ASN1_INTEGER **out_aint, CBS *cbs)
644 uint8_t *data = NULL; 647 uint8_t *data = NULL;
645 size_t data_len = 0; 648 size_t data_len = 0;
646 uint8_t padding, val; 649 uint8_t padding, val;
647 uint8_t negative = 0; 650 uint8_t negative;
648 int ret = 0; 651 int ret = 0;
649 652
650 if (out_aint == NULL) 653 if (out_aint == NULL)
@@ -663,7 +666,7 @@ c2i_ASN1_INTEGER_cbs(ASN1_INTEGER **out_aint, CBS *cbs)
663 if (!CBS_peek_u8(cbs, &val)) 666 if (!CBS_peek_u8(cbs, &val))
664 goto err; 667 goto err;
665 668
666 /* Top most bit indicates sign, padding is all zeros or all ones. */ 669 /* Topmost bit indicates sign, padding is all zeros or all ones. */
667 negative = (val >> 7); 670 negative = (val >> 7);
668 padding = ~(negative - 1) & 0xff; 671 padding = ~(negative - 1) & 0xff;
669 672