ASN.1 DER: Make INT32 / INT64 types read badly encoded LONG zeroes
authorRichard Levitte <levitte@openssl.org>
Thu, 6 Sep 2018 20:09:11 +0000 (22:09 +0200)
committerRichard Levitte <levitte@openssl.org>
Sun, 9 Sep 2018 01:39:37 +0000 (03:39 +0200)
The deprecated ASN.1 type LONG / ZLONG (incorrectly) produced zero
length INTEGER encoding for zeroes.  For the sake of backward
compatibility, we allow those to be read without fault when using the
replacement types INT32 / UINT32 / INT64 / UINT64.

Fixes #7134

Reviewed-by: Tim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/7144)

crypto/asn1/x_int64.c

index f07ca3c..0ee552c 100644 (file)
@@ -81,6 +81,16 @@ static int uint64_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
         return 0;
 
     cp = (char *)*pval;
+
+    /*
+     * Strictly speaking, zero length is malformed.  However, long_c2i
+     * (x_long.c) encodes 0 as a zero length INTEGER (wrongly, of course),
+     * so for the sake of backward compatibility, we still decode zero
+     * length INTEGERs as the number zero.
+     */
+    if (len == 0)
+        goto long_compat;
+
     if (!c2i_uint64_int(&utmp, &neg, &cont, len))
         return 0;
     if ((it->size & INTxx_FLAG_SIGNED) == 0 && neg) {
@@ -95,6 +105,8 @@ static int uint64_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
     if (neg)
         /* c2i_uint64_int() returns positive values */
         utmp = 0 - utmp;
+
+ long_compat:
     memcpy(cp, &utmp, sizeof(utmp));
     return 1;
 }
@@ -172,6 +184,16 @@ static int uint32_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
         return 0;
 
     cp = (char *)*pval;
+
+    /*
+     * Strictly speaking, zero length is malformed.  However, long_c2i
+     * (x_long.c) encodes 0 as a zero length INTEGER (wrongly, of course),
+     * so for the sake of backward compatibility, we still decode zero
+     * length INTEGERs as the number zero.
+     */
+    if (len == 0)
+        goto long_compat;
+
     if (!c2i_uint64_int(&utmp, &neg, &cont, len))
         return 0;
     if ((it->size & INTxx_FLAG_SIGNED) == 0 && neg) {
@@ -191,6 +213,8 @@ static int uint32_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
             return 0;
         }
     }
+
+ long_compat:
     utmp2 = (uint32_t)utmp;
     memcpy(cp, &utmp2, sizeof(utmp2));
     return 1;