ASN.1: Add some sanity checks for input len <= 0; related coding improvements
authorDr. David von Oheimb <David.von.Oheimb@siemens.com>
Mon, 1 Mar 2021 13:45:23 +0000 (14:45 +0100)
committerDr. David von Oheimb <dev@ddvo.net>
Wed, 21 Apr 2021 13:06:21 +0000 (15:06 +0200)
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/14357)

crypto/asn1/a_d2i_fp.c
crypto/asn1/asn1_lib.c
crypto/asn1/tasn_dec.c

index 4151a965614319ddc3f4c492671487028139668b..6dfa37c7a2c94311216b49d636d186122f08ba2c 100644 (file)
@@ -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 */
index d45419e5f0f0297a79c1879a6787384668487efe..72d15acc7ef215eca291858b20728f9d98c1c953 100644 (file)
@@ -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;
index 00a460700bb0d5b05ab36b2bd6080bc3affdcb10..20717df461d2c0e8298f1382d26cfccaf4701d75 100644 (file)
@@ -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;
 }