summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjsing <>2022-04-27 17:42:08 +0000
committerjsing <>2022-04-27 17:42:08 +0000
commit9b4f52bd67002c10a6a97a6b20cb7c61be0a2cee (patch)
treea5428a80984a8a541bb3cf621d5ae890ff0dfcff
parent066ee7e25f2f9510191df30325a50ed15a2b910a (diff)
downloadopenbsd-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.c213
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
69const ASN1_ITEM ASN1_INTEGER_it = { 71const 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 */ 491static void
490 492asn1_aint_twos_complement(uint8_t *data, size_t data_len)
491ASN1_INTEGER *
492c2i_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)) { 504static int
506 /* 505asn1_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; 524int
515 pend = p + len; 525c2i_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
605ASN1_INTEGER *
606c2i_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
589int 634int