From ebdeeb363f03848cea5028e63c6be294a34a8426 Mon Sep 17 00:00:00 2001 From: "Dr. Matthias St. Pierre" Date: Thu, 26 Apr 2018 20:36:41 +0200 Subject: [PATCH] a_strex.c: prevent out of bound read in do_buf() which is used for ASN1_STRING_print_ex*() and X509_NAME_print_ex*(). Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/6117) --- crypto/asn1/a_strex.c | 25 +++++++++++++++++++++++-- crypto/asn1/asn1_err.c | 1 + include/openssl/asn1.h | 1 + 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/crypto/asn1/a_strex.c b/crypto/asn1/a_strex.c index b91266b3c5..75bc4319c7 100644 --- a/crypto/asn1/a_strex.c +++ b/crypto/asn1/a_strex.c @@ -139,7 +139,7 @@ static int do_buf(unsigned char *buf, int buflen, int type, unsigned short flags, char *quotes, char_io *io_ch, void *arg) { - int i, outlen, len; + int i, outlen, len, charwidth; unsigned short orflags; unsigned char *p, *q; unsigned long c; @@ -147,12 +147,32 @@ static int do_buf(unsigned char *buf, int buflen, p = buf; q = buf + buflen; outlen = 0; + charwidth = type & BUF_TYPE_WIDTH_MASK; + + switch (charwidth) { + case 4: + if (buflen & 3) { + ASN1err(ASN1_F_DO_BUF, ASN1_R_INVALID_UNIVERSALSTRING_LENGTH); + return -1; + } + break; + case 2: + if (buflen & 1) { + ASN1err(ASN1_F_DO_BUF, ASN1_R_INVALID_BMPSTRING_LENGTH); + return -1; + } + break; + default: + break; + } + while (p != q) { if (p == buf && flags & ASN1_STRFLGS_ESC_2253) orflags = CHARTYPE_FIRST_ESC_2253; else orflags = 0; - switch (type & BUF_TYPE_WIDTH_MASK) { + + switch (charwidth) { case 4: c = ((unsigned long)*p++) << 24; c |= ((unsigned long)*p++) << 16; @@ -173,6 +193,7 @@ static int do_buf(unsigned char *buf, int buflen, i = UTF8_getc(p, buflen, &c); if (i < 0) return -1; /* Invalid UTF8String */ + buflen -= i; p += i; break; default: diff --git a/crypto/asn1/asn1_err.c b/crypto/asn1/asn1_err.c index 8602c408d9..7068c0c54f 100644 --- a/crypto/asn1/asn1_err.c +++ b/crypto/asn1/asn1_err.c @@ -92,6 +92,7 @@ static ERR_STRING_DATA ASN1_str_functs[] = { {ERR_FUNC(ASN1_F_D2I_AUTOPRIVATEKEY), "d2i_AutoPrivateKey"}, {ERR_FUNC(ASN1_F_D2I_PRIVATEKEY), "d2i_PrivateKey"}, {ERR_FUNC(ASN1_F_D2I_PUBLICKEY), "d2i_PublicKey"}, + {ERR_FUNC(ASN1_F_DO_BUF), "do_buf"}, {ERR_FUNC(ASN1_F_DO_TCREATE), "do_tcreate"}, {ERR_FUNC(ASN1_F_I2D_ASN1_BIO_STREAM), "i2d_ASN1_bio_stream"}, {ERR_FUNC(ASN1_F_I2D_DSA_PUBKEY), "i2d_DSA_PUBKEY"}, diff --git a/include/openssl/asn1.h b/include/openssl/asn1.h index 05ae1dbe1c..88e6469e4d 100644 --- a/include/openssl/asn1.h +++ b/include/openssl/asn1.h @@ -953,6 +953,7 @@ int ERR_load_ASN1_strings(void); # define ASN1_F_D2I_AUTOPRIVATEKEY 207 # define ASN1_F_D2I_PRIVATEKEY 154 # define ASN1_F_D2I_PUBLICKEY 155 +# define ASN1_F_DO_BUF 142 # define ASN1_F_DO_TCREATE 222 # define ASN1_F_I2D_ASN1_BIO_STREAM 211 # define ASN1_F_I2D_DSA_PUBKEY 161 -- 2.25.1