Memory bounds checking in asn1 code.

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)
This commit is contained in:
Pauli 2017-07-06 11:39:03 +10:00
parent eee9552212
commit 60eba30f60
6 changed files with 55 additions and 48 deletions

View 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);

View 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;
}

View 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)

View 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;
}

View 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)

View 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