Memory bounds checking in asn1 code.
authorPauli <paul.dale@oracle.com>
Thu, 6 Jul 2017 01:39:03 +0000 (11:39 +1000)
committerPauli <paul.dale@oracle.com>
Thu, 6 Jul 2017 02:59:51 +0000 (12:59 +1000)
Check that sprint, strcpy don't overflow.

Avoid some strlen operations when the previous sprintf return value can be used.

Also fix the undefined behaviour `*(long *)x = y` when x isn't a long or character pointer.
ISO/IEC 9899:1999 6.5/7 for the details.

Reviewed-by: Rich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3869)

crypto/asn1/a_gentm.c
crypto/asn1/a_mbstr.c
crypto/asn1/a_time.c
crypto/asn1/a_utctm.c
crypto/asn1/asn1_par.c
crypto/asn1/x_long.c

index 2c5fb1c..5cfc3ff 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -207,7 +207,7 @@ ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s,
     char *p;
     struct tm *ts;
     struct tm data;
-    size_t len = 20;
+    const size_t len = 20;
     ASN1_GENERALIZEDTIME *tmps = NULL;
 
     if (s == NULL)
@@ -237,10 +237,10 @@ ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s,
         tmps->data = (unsigned char *)p;
     }
 
-    sprintf(p, "%04d%02d%02d%02d%02d%02dZ", ts->tm_year + 1900,
-            ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min,
-            ts->tm_sec);
-    tmps->length = strlen(p);
+    tmps->length = BIO_snprintf(p, len, "%04d%02d%02d%02d%02d%02dZ",
+                                ts->tm_year + 1900, ts->tm_mon + 1,
+                                ts->tm_mday, ts->tm_hour, ts->tm_min,
+                                ts->tm_sec);
     tmps->type = V_ASN1_GENERALIZEDTIME;
 #ifdef CHARSET_EBCDIC_not
     ebcdic2ascii(tmps->data, tmps->data, tmps->length);
index 46764b2..e644fe0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1999-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -100,14 +100,14 @@ int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
 
     if ((minsize > 0) && (nchar < minsize)) {
         ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_SHORT);
-        sprintf(strbuf, "%ld", minsize);
+        BIO_snprintf(strbuf, sizeof(strbuf), "%ld", minsize);
         ERR_add_error_data(2, "minsize=", strbuf);
         return -1;
     }
 
     if ((maxsize > 0) && (nchar > maxsize)) {
         ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_LONG);
-        sprintf(strbuf, "%ld", maxsize);
+        BIO_snprintf(strbuf, sizeof(strbuf), "%ld", maxsize);
         ERR_add_error_data(2, "maxsize=", strbuf);
         return -1;
     }
index f0ec42f..fc78e30 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1999-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -81,17 +81,20 @@ ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(const ASN1_TIME *t,
         goto done;
     }
 
-    /* grow the string */
+    /*
+     * Grow the string by two bytes.
+     * The actual allocation is t->length + 3 to include a terminator byte.
+     */
     if (!ASN1_STRING_set(ret, NULL, t->length + 2))
         goto err;
     str = (char *)ret->data;
     /* Work out the century and prepend */
-    if (t->data[0] >= '5')
-        strcpy(str, "19");
-    else
-        strcpy(str, "20");
-
-    strcat(str, (const char *)t->data);
+    memcpy(str, t->data[0] >= '5' ? "19" : "20", 2);
+    /*
+     * t->length + 1 is the size of the data and the allocated buffer has
+     * this much space after the first two characters.
+     */
+    OPENSSL_strlcpy(str + 2, (const char *)t->data, t->length + 1);
 
  done:
    if (out != NULL && *out == NULL)
index 25393ee..5a4b174 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -21,7 +21,7 @@ int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d)
     int n, i, l, o, min_l = 11, strict = 0;
 
     if (d->type != V_ASN1_UTCTIME)
-        return (0);
+        return 0;
     l = d->length;
     a = (char *)d->data;
     o = 0;
@@ -150,9 +150,9 @@ int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str)
                 return 0;
             s->type = V_ASN1_UTCTIME;
         }
-        return (1);
-    } else
-        return (0);
+        return 1;
+    }
+    return 0;
 }
 
 ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t)
@@ -166,7 +166,7 @@ ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t,
     char *p;
     struct tm *ts;
     struct tm data;
-    size_t len = 20;
+    const size_t len = 20;
     int free_s = 0;
 
     if (s == NULL) {
@@ -199,15 +199,14 @@ ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t,
         s->data = (unsigned char *)p;
     }
 
-    sprintf(p, "%02d%02d%02d%02d%02d%02dZ", ts->tm_year % 100,
-            ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min,
-            ts->tm_sec);
-    s->length = strlen(p);
+    s->length = BIO_snprintf(p, len, "%02d%02d%02d%02d%02d%02dZ",
+                             ts->tm_year % 100, ts->tm_mon + 1, ts->tm_mday,
+                             ts->tm_hour, ts->tm_min, ts->tm_sec);
     s->type = V_ASN1_UTCTIME;
 #ifdef CHARSET_EBCDIC_not
     ebcdic2ascii(s->data, s->data, s->length);
 #endif
-    return (s);
+    return s;
  err:
     if (free_s)
         ASN1_UTCTIME_free(s);
@@ -272,10 +271,9 @@ int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm)
     if (BIO_printf(bp, "%s %2d %02d:%02d:%02d %d%s",
                    _asn1_mon[M - 1], d, h, m, s, y + 1900,
                    (gmt) ? " GMT" : "") <= 0)
-        return (0);
-    else
-        return (1);
+        return 0;
+    return 1;
  err:
     BIO_write(bp, "Bad time value", 14);
-    return (0);
+    return 0;
 }
index 19b21e7..4b60c61 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -38,32 +38,32 @@ static int asn1_print_info(BIO *bp, int tag, int xclass, int constructed,
 
     p = str;
     if ((xclass & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
-        sprintf(str, "priv [ %d ] ", tag);
+        BIO_snprintf(str, sizeof(str), "priv [ %d ] ", tag);
     else if ((xclass & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
-        sprintf(str, "cont [ %d ]", tag);
+        BIO_snprintf(str, sizeof(str), "cont [ %d ]", tag);
     else if ((xclass & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
-        sprintf(str, "appl [ %d ]", tag);
+        BIO_snprintf(str, sizeof(str), "appl [ %d ]", tag);
     else if (tag > 30)
-        sprintf(str, "<ASN1 %d>", tag);
+        BIO_snprintf(str, sizeof(str), "<ASN1 %d>", tag);
     else
         p = ASN1_tag2str(tag);
 
     if (BIO_printf(bp, fmt, p) <= 0)
         goto err;
-    return (1);
+    return 1;
  err:
-    return (0);
+    return 0;
 }
 
 int ASN1_parse(BIO *bp, const unsigned char *pp, long len, int indent)
 {
-    return (asn1_parse2(bp, &pp, len, 0, 0, indent, 0));
+    return asn1_parse2(bp, &pp, len, 0, 0, indent, 0);
 }
 
 int ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len, int indent,
                     int dump)
 {
-    return (asn1_parse2(bp, &pp, len, 0, 0, indent, dump));
+    return asn1_parse2(bp, &pp, len, 0, 0, indent, dump);
 }
 
 static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
@@ -342,7 +342,7 @@ static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
     ASN1_OBJECT_free(o);
     ASN1_OCTET_STRING_free(os);
     *pp = p;
-    return (ret);
+    return ret;
 }
 
 const char *ASN1_tag2str(int tag)
index 78f4b76..bf9371e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2000-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -14,6 +14,9 @@
 #if !(OPENSSL_API_COMPAT < 0x10200000L)
 NON_EMPTY_TRANSLATION_UNIT
 #else
+
+#define COPY_SIZE(a, b) (sizeof(a) < sizeof(b) ? sizeof(a) : sizeof(b))
+
 /*
  * Custom primitive type for long handling. This converts between an
  * ASN1_INTEGER and a long directly.
@@ -49,13 +52,13 @@ ASN1_ITEM_end(ZLONG)
 
 static int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
 {
-    *(long *)pval = it->size;
+    memcpy(pval, &it->size, COPY_SIZE(*pval, it->size));
     return 1;
 }
 
 static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
 {
-    *(long *)pval = it->size;
+    memcpy(pval, &it->size, COPY_SIZE(*pval, it->size));
 }
 
 /*
@@ -90,7 +93,7 @@ static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
     unsigned long utmp, sign;
     int clen, pad, i;
 
-    ltmp = *(long *)pval;
+    memcpy(&ltmp, pval, COPY_SIZE(*pval, ltmp));
     if (ltmp == it->size)
         return -1;
     /*
@@ -183,13 +186,16 @@ static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
         ASN1err(ASN1_F_LONG_C2I, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
         return 0;
     }
-    *(long*)pval = ltmp;
+    memcpy(pval, &ltmp, COPY_SIZE(*pval, ltmp));
     return 1;
 }
 
 static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it,
                       int indent, const ASN1_PCTX *pctx)
 {
-    return BIO_printf(out, "%ld\n", *(long *)pval);
+    long l;
+
+    memcpy(&l, pval, COPY_SIZE(*pval, l));
+    return BIO_printf(out, "%ld\n", l);
 }
 #endif