From 3e73111d133dda63ec42437ff5706ac3142f17a5 Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Mon, 1 Mar 2021 14:45:23 +0100 Subject: [PATCH] ASN.1: Add some sanity checks for input len <= 0; related coding improvements Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/14357) --- crypto/asn1/a_d2i_fp.c | 16 ++++++++++------ crypto/asn1/asn1_lib.c | 6 ++++-- crypto/asn1/tasn_dec.c | 19 +++++++++++++------ 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/crypto/asn1/a_d2i_fp.c b/crypto/asn1/a_d2i_fp.c index 4151a96561..6dfa37c7a2 100644 --- a/crypto/asn1/a_d2i_fp.c +++ b/crypto/asn1/a_d2i_fp.c @@ -101,6 +101,7 @@ int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) uint32_t eos = 0; size_t off = 0; size_t len = 0; + size_t diff; const unsigned char *q; long slen; @@ -114,15 +115,16 @@ int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) ERR_clear_error(); for (;;) { - if (want >= (len - off)) { - want -= (len - off); + diff = len - off; + if (want >= diff) { + want -= diff; if (len + want < len || !BUF_MEM_grow_clean(b, len + want)) { ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); goto err; } i = BIO_read(in, &(b->data[len]), want); - if ((i < 0) && ((len - off) == 0)) { + if (i < 0 && diff == 0) { ERR_raise(ERR_LIB_ASN1, ASN1_R_NOT_ENOUGH_DATA); goto err; } @@ -138,15 +140,17 @@ int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) p = (unsigned char *)&(b->data[off]); q = p; - inf = ASN1_get_object(&q, &slen, &tag, &xclass, len - off); + diff = len - off; + if (diff == 0) + goto err; + inf = ASN1_get_object(&q, &slen, &tag, &xclass, diff); if (inf & 0x80) { unsigned long e; e = ERR_GET_REASON(ERR_peek_error()); if (e != ASN1_R_TOO_LONG) goto err; - else - ERR_clear_error(); /* clear error */ + ERR_clear_error(); } i = q - p; /* header length */ off += i; /* end of data */ diff --git a/crypto/asn1/asn1_lib.c b/crypto/asn1/asn1_lib.c index d45419e5f0..72d15acc7e 100644 --- a/crypto/asn1/asn1_lib.c +++ b/crypto/asn1/asn1_lib.c @@ -52,8 +52,10 @@ int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag, int tag, xclass, inf; long max = omax; - if (!max) - goto err; + if (omax <= 0) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_SMALL); + return 0x80; + } ret = (*p & V_ASN1_CONSTRUCTED); xclass = (*p & V_ASN1_PRIVATE); i = *p & V_ASN1_PRIMITIVE_TAG; diff --git a/crypto/asn1/tasn_dec.c b/crypto/asn1/tasn_dec.c index 00a460700b..20717df461 100644 --- a/crypto/asn1/tasn_dec.c +++ b/crypto/asn1/tasn_dec.c @@ -159,6 +159,10 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in, ERR_raise(ERR_LIB_ASN1, ERR_R_PASSED_NULL_PARAMETER); return 0; } + if (len <= 0) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_SMALL); + return 0; + } aux = it->funcs; if (aux && aux->asn1_cb) asn1_cb = aux->asn1_cb; @@ -1108,6 +1112,10 @@ static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, p = *in; q = p; + if (len <= 0) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_SMALL); + goto err; + } if (ctx != NULL && ctx->valid) { i = ctx->ret; plen = ctx->plen; @@ -1129,14 +1137,15 @@ static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, */ if ((i & 0x81) == 0 && (plen + ctx->hdrlen) > len) { ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG); - asn1_tlc_clear(ctx); - return 0; + goto err; } } } - if ((i & 0x80) != 0) + if ((i & 0x80) != 0) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_BAD_OBJECT_HEADER); goto err; + } if (exptag >= 0) { if (exptag != ptag || expclass != pclass) { /* @@ -1144,9 +1153,8 @@ static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, */ if (opt != 0) return -1; - asn1_tlc_clear(ctx); ERR_raise(ERR_LIB_ASN1, ASN1_R_WRONG_TAG); - return 0; + goto err; } /* * We have a tag and class match: assume we are going to do something @@ -1177,7 +1185,6 @@ static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, return 1; err: - ERR_raise(ERR_LIB_ASN1, ASN1_R_BAD_OBJECT_HEADER); asn1_tlc_clear(ctx); return 0; }