From 6b243ca5a91bf4572dd358fb9af6b26cf19e8504 Mon Sep 17 00:00:00 2001 From: guoxiaoqi Date: Tue, 19 Jan 2021 17:18:04 +0800 Subject: [PATCH] fix CVE-2020-1971 --- ...is-a-CHOICE-type-and-therefore-uses-.patch | 41 ++ ...are-EdiPartyName-in-GENERAL_NAME_cmp.patch | 101 +++++ ...-strings-CHOICE-types-don-t-use-impl.patch | 103 +++++ ...re-attempting-to-encode-with-an-inva.patch | 116 ++++++ ...0005-Add-a-test-for-GENERAL_NAME_cmp.patch | 372 ++++++++++++++++++ ...ncoding-decoding-using-an-invalid-AS.patch | 121 ++++++ openssl.spec | 11 +- 7 files changed, 864 insertions(+), 1 deletion(-) create mode 100644 CVE-2020-1971-0001-DirectoryString-is-a-CHOICE-type-and-therefore-uses-.patch create mode 100644 CVE-2020-1971-0002-Correctly-compare-EdiPartyName-in-GENERAL_NAME_cmp.patch create mode 100644 CVE-2020-1971-0003-Check-that-multi-strings-CHOICE-types-don-t-use-impl.patch create mode 100644 CVE-2020-1971-0004-Complain-if-we-are-attempting-to-encode-with-an-inva.patch create mode 100644 CVE-2020-1971-0005-Add-a-test-for-GENERAL_NAME_cmp.patch create mode 100644 CVE-2020-1971-0006-Add-a-test-for-encoding-decoding-using-an-invalid-AS.patch diff --git a/CVE-2020-1971-0001-DirectoryString-is-a-CHOICE-type-and-therefore-uses-.patch b/CVE-2020-1971-0001-DirectoryString-is-a-CHOICE-type-and-therefore-uses-.patch new file mode 100644 index 0000000..0bf75e6 --- /dev/null +++ b/CVE-2020-1971-0001-DirectoryString-is-a-CHOICE-type-and-therefore-uses-.patch @@ -0,0 +1,41 @@ +From aa0ad2011d3e7ad8a611da274ef7d9c7706e289b Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Wed, 11 Nov 2020 15:19:34 +0000 +Subject: [PATCH 01/31] DirectoryString is a CHOICE type and therefore uses + explicit tagging + +EDIPartyName has 2 fields that use a DirectoryString. However they were +marked as implicit tagging - which is not correct for a CHOICE type. + +Additionally the partyName field was marked as Optional when, according to +RFC5280 it is not. + +Many thanks to github user @filipnavara for reporting this issue. Also to +David Benjamin from Google who independently identified and reported it. + +Fixes #6859 + +Reviewed-by: Tomas Mraz +--- + crypto/x509v3/v3_genn.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/crypto/x509v3/v3_genn.c b/crypto/x509v3/v3_genn.c +index 23e3bc4..b483f35 100644 +--- a/crypto/x509v3/v3_genn.c ++++ b/crypto/x509v3/v3_genn.c +@@ -22,8 +22,9 @@ ASN1_SEQUENCE(OTHERNAME) = { + IMPLEMENT_ASN1_FUNCTIONS(OTHERNAME) + + ASN1_SEQUENCE(EDIPARTYNAME) = { +- ASN1_IMP_OPT(EDIPARTYNAME, nameAssigner, DIRECTORYSTRING, 0), +- ASN1_IMP_OPT(EDIPARTYNAME, partyName, DIRECTORYSTRING, 1) ++ /* DirectoryString is a CHOICE type so use explicit tagging */ ++ ASN1_EXP_OPT(EDIPARTYNAME, nameAssigner, DIRECTORYSTRING, 0), ++ ASN1_EXP(EDIPARTYNAME, partyName, DIRECTORYSTRING, 1) + } ASN1_SEQUENCE_END(EDIPARTYNAME) + + IMPLEMENT_ASN1_FUNCTIONS(EDIPARTYNAME) +-- +1.8.3.1 + diff --git a/CVE-2020-1971-0002-Correctly-compare-EdiPartyName-in-GENERAL_NAME_cmp.patch b/CVE-2020-1971-0002-Correctly-compare-EdiPartyName-in-GENERAL_NAME_cmp.patch new file mode 100644 index 0000000..36954c1 --- /dev/null +++ b/CVE-2020-1971-0002-Correctly-compare-EdiPartyName-in-GENERAL_NAME_cmp.patch @@ -0,0 +1,101 @@ +From f960d81215ebf3f65e03d4d5d857fb9b666d6920 Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Wed, 11 Nov 2020 16:12:58 +0000 +Subject: [PATCH 02/31] Correctly compare EdiPartyName in GENERAL_NAME_cmp() + +If a GENERAL_NAME field contained EdiPartyName data then it was +incorrectly being handled as type "other". This could lead to a +segmentation fault. + +Many thanks to David Benjamin from Google for reporting this issue. + +CVE-2020-1971 + +Reviewed-by: Tomas Mraz +--- + crypto/x509v3/v3_genn.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 42 insertions(+), 3 deletions(-) + +diff --git a/crypto/x509v3/v3_genn.c b/crypto/x509v3/v3_genn.c +index b483f35..6f0a347 100644 +--- a/crypto/x509v3/v3_genn.c ++++ b/crypto/x509v3/v3_genn.c +@@ -58,6 +58,37 @@ GENERAL_NAME *GENERAL_NAME_dup(GENERAL_NAME *a) + (char *)a); + } + ++static int edipartyname_cmp(const EDIPARTYNAME *a, const EDIPARTYNAME *b) ++{ ++ int res; ++ ++ if (a == NULL || b == NULL) { ++ /* ++ * Shouldn't be possible in a valid GENERAL_NAME, but we handle it ++ * anyway. OTHERNAME_cmp treats NULL != NULL so we do the same here ++ */ ++ return -1; ++ } ++ if (a->nameAssigner == NULL && b->nameAssigner != NULL) ++ return -1; ++ if (a->nameAssigner != NULL && b->nameAssigner == NULL) ++ return 1; ++ /* If we get here then both have nameAssigner set, or both unset */ ++ if (a->nameAssigner != NULL) { ++ res = ASN1_STRING_cmp(a->nameAssigner, b->nameAssigner); ++ if (res != 0) ++ return res; ++ } ++ /* ++ * partyName is required, so these should never be NULL. We treat it in ++ * the same way as the a == NULL || b == NULL case above ++ */ ++ if (a->partyName == NULL || b->partyName == NULL) ++ return -1; ++ ++ return ASN1_STRING_cmp(a->partyName, b->partyName); ++} ++ + /* Returns 0 if they are equal, != 0 otherwise. */ + int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b) + { +@@ -67,8 +98,11 @@ int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b) + return -1; + switch (a->type) { + case GEN_X400: ++ result = ASN1_TYPE_cmp(a->d.x400Address, b->d.x400Address); ++ break; ++ + case GEN_EDIPARTY: +- result = ASN1_TYPE_cmp(a->d.other, b->d.other); ++ result = edipartyname_cmp(a->d.ediPartyName, b->d.ediPartyName); + break; + + case GEN_OTHERNAME: +@@ -115,8 +149,11 @@ void GENERAL_NAME_set0_value(GENERAL_NAME *a, int type, void *value) + { + switch (type) { + case GEN_X400: ++ a->d.x400Address = value; ++ break; ++ + case GEN_EDIPARTY: +- a->d.other = value; ++ a->d.ediPartyName = value; + break; + + case GEN_OTHERNAME: +@@ -150,8 +187,10 @@ void *GENERAL_NAME_get0_value(const GENERAL_NAME *a, int *ptype) + *ptype = a->type; + switch (a->type) { + case GEN_X400: ++ return a->d.x400Address; ++ + case GEN_EDIPARTY: +- return a->d.other; ++ return a->d.ediPartyName; + + case GEN_OTHERNAME: + return a->d.otherName; +-- +1.8.3.1 + diff --git a/CVE-2020-1971-0003-Check-that-multi-strings-CHOICE-types-don-t-use-impl.patch b/CVE-2020-1971-0003-Check-that-multi-strings-CHOICE-types-don-t-use-impl.patch new file mode 100644 index 0000000..6e810be --- /dev/null +++ b/CVE-2020-1971-0003-Check-that-multi-strings-CHOICE-types-don-t-use-impl.patch @@ -0,0 +1,103 @@ +From 1ecc76f6746cefd502c7e9000bdfa4e5d7911386 Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Thu, 12 Nov 2020 11:58:12 +0000 +Subject: [PATCH 03/31] Check that multi-strings/CHOICE types don't use + implicit tagging + +It never makes sense for multi-string or CHOICE types to use implicit +tagging since the content would be ambiguous. It is an error in the +template if this ever happens. If we detect it we should stop parsing. + +Thanks to David Benjamin from Google for reporting this issue. + +Reviewed-by: Tomas Mraz +--- + crypto/asn1/asn1_err.c | 1 + + crypto/asn1/tasn_dec.c | 19 +++++++++++++++++++ + crypto/err/openssl.txt | 1 + + include/openssl/asn1err.h | 1 + + 4 files changed, 22 insertions(+) + +diff --git a/crypto/asn1/asn1_err.c b/crypto/asn1/asn1_err.c +index 613f9ae..99a087d 100644 +--- a/crypto/asn1/asn1_err.c ++++ b/crypto/asn1/asn1_err.c +@@ -160,6 +160,7 @@ static const ERR_STRING_DATA ASN1_str_reasons[] = { + "asn1 sig parse error"}, + {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_AUX_ERROR), "aux error"}, + {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BAD_OBJECT_HEADER), "bad object header"}, ++ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BAD_TEMPLATE), "bad template"}, + {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BMPSTRING_IS_WRONG_LENGTH), + "bmpstring is wrong length"}, + {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BN_LIB), "bn lib"}, +diff --git a/crypto/asn1/tasn_dec.c b/crypto/asn1/tasn_dec.c +index 2332b20..1021705 100644 +--- a/crypto/asn1/tasn_dec.c ++++ b/crypto/asn1/tasn_dec.c +@@ -182,6 +182,15 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in, + tag, aclass, opt, ctx); + + case ASN1_ITYPE_MSTRING: ++ /* ++ * It never makes sense for multi-strings to have implicit tagging, so ++ * if tag != -1, then this looks like an error in the template. ++ */ ++ if (tag != -1) { ++ ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_BAD_TEMPLATE); ++ goto err; ++ } ++ + p = *in; + /* Just read in tag and class */ + ret = asn1_check_tlen(NULL, &otag, &oclass, NULL, NULL, +@@ -199,6 +208,7 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in, + ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_MSTRING_NOT_UNIVERSAL); + goto err; + } ++ + /* Check tag matches bit map */ + if (!(ASN1_tag2bit(otag) & it->utype)) { + /* If OPTIONAL, assume this is OK */ +@@ -215,6 +225,15 @@ static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in, + return ef->asn1_ex_d2i(pval, in, len, it, tag, aclass, opt, ctx); + + case ASN1_ITYPE_CHOICE: ++ /* ++ * It never makes sense for CHOICE types to have implicit tagging, so ++ * if tag != -1, then this looks like an error in the template. ++ */ ++ if (tag != -1) { ++ ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_BAD_TEMPLATE); ++ goto err; ++ } ++ + if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL)) + goto auxerr; + if (*pval) { +diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt +index 0b5873e..2f93221 100644 +--- a/crypto/err/openssl.txt ++++ b/crypto/err/openssl.txt +@@ -1771,6 +1771,7 @@ ASN1_R_ASN1_PARSE_ERROR:203:asn1 parse error + ASN1_R_ASN1_SIG_PARSE_ERROR:204:asn1 sig parse error + ASN1_R_AUX_ERROR:100:aux error + ASN1_R_BAD_OBJECT_HEADER:102:bad object header ++ASN1_R_BAD_TEMPLATE:230:bad template + ASN1_R_BMPSTRING_IS_WRONG_LENGTH:214:bmpstring is wrong length + ASN1_R_BN_LIB:105:bn lib + ASN1_R_BOOLEAN_IS_WRONG_LENGTH:106:boolean is wrong length +diff --git a/include/openssl/asn1err.h b/include/openssl/asn1err.h +index faed5a5..9070e26 100644 +--- a/include/openssl/asn1err.h ++++ b/include/openssl/asn1err.h +@@ -145,6 +145,7 @@ int ERR_load_ASN1_strings(void); + # define ASN1_R_ASN1_SIG_PARSE_ERROR 204 + # define ASN1_R_AUX_ERROR 100 + # define ASN1_R_BAD_OBJECT_HEADER 102 ++# define ASN1_R_BAD_TEMPLATE 230 + # define ASN1_R_BMPSTRING_IS_WRONG_LENGTH 214 + # define ASN1_R_BN_LIB 105 + # define ASN1_R_BOOLEAN_IS_WRONG_LENGTH 106 +-- +1.8.3.1 + diff --git a/CVE-2020-1971-0004-Complain-if-we-are-attempting-to-encode-with-an-inva.patch b/CVE-2020-1971-0004-Complain-if-we-are-attempting-to-encode-with-an-inva.patch new file mode 100644 index 0000000..c575a53 --- /dev/null +++ b/CVE-2020-1971-0004-Complain-if-we-are-attempting-to-encode-with-an-inva.patch @@ -0,0 +1,116 @@ +From 41d62636fd996c031c0c7cef746476278583dc9e Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Thu, 12 Nov 2020 14:55:31 +0000 +Subject: [PATCH 04/31] Complain if we are attempting to encode with an invalid + ASN.1 template + +It never makes sense for multi-string or CHOICE types to have implicit +tagging. If we have a template that uses the in this way then we +should immediately fail. + +Thanks to David Benjamin from Google for reporting this issue. + +Reviewed-by: Tomas Mraz +--- + crypto/asn1/asn1_err.c | 3 ++- + crypto/asn1/tasn_enc.c | 16 ++++++++++++++++ + crypto/err/openssl.txt | 1 + + include/openssl/asn1err.h | 7 +++---- + 4 files changed, 22 insertions(+), 5 deletions(-) + +diff --git a/crypto/asn1/asn1_err.c b/crypto/asn1/asn1_err.c +index 99a087d..cc0a59c 100644 +--- a/crypto/asn1/asn1_err.c ++++ b/crypto/asn1/asn1_err.c +@@ -1,6 +1,6 @@ + /* + * Generated by util/mkerr.pl DO NOT EDIT +- * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. ++ * Copyright 1995-2020 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 +@@ -49,6 +49,7 @@ static const ERR_STRING_DATA ASN1_str_functs[] = { + "asn1_item_embed_d2i"}, + {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_ITEM_EMBED_NEW, 0), + "asn1_item_embed_new"}, ++ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_ITEM_EX_I2D, 0), "ASN1_item_ex_i2d"}, + {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_ITEM_FLAGS_I2D, 0), + "asn1_item_flags_i2d"}, + {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_ITEM_I2D_BIO, 0), "ASN1_item_i2d_bio"}, +diff --git a/crypto/asn1/tasn_enc.c b/crypto/asn1/tasn_enc.c +index d600c7a..52a051d 100644 +--- a/crypto/asn1/tasn_enc.c ++++ b/crypto/asn1/tasn_enc.c +@@ -103,9 +103,25 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, + return asn1_i2d_ex_primitive(pval, out, it, tag, aclass); + + case ASN1_ITYPE_MSTRING: ++ /* ++ * It never makes sense for multi-strings to have implicit tagging, so ++ * if tag != -1, then this looks like an error in the template. ++ */ ++ if (tag != -1) { ++ ASN1err(ASN1_F_ASN1_ITEM_EX_I2D, ASN1_R_BAD_TEMPLATE); ++ return -1; ++ } + return asn1_i2d_ex_primitive(pval, out, it, -1, aclass); + + case ASN1_ITYPE_CHOICE: ++ /* ++ * It never makes sense for CHOICE types to have implicit tagging, so ++ * if tag != -1, then this looks like an error in the template. ++ */ ++ if (tag != -1) { ++ ASN1err(ASN1_F_ASN1_ITEM_EX_I2D, ASN1_R_BAD_TEMPLATE); ++ return -1; ++ } + if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL)) + return 0; + i = asn1_get_choice_selector(pval, it); +diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt +index 2f93221..815460b 100644 +--- a/crypto/err/openssl.txt ++++ b/crypto/err/openssl.txt +@@ -36,6 +36,7 @@ ASN1_F_ASN1_ITEM_D2I_FP:206:ASN1_item_d2i_fp + ASN1_F_ASN1_ITEM_DUP:191:ASN1_item_dup + ASN1_F_ASN1_ITEM_EMBED_D2I:120:asn1_item_embed_d2i + ASN1_F_ASN1_ITEM_EMBED_NEW:121:asn1_item_embed_new ++ASN1_F_ASN1_ITEM_EX_I2D:144:ASN1_item_ex_i2d + ASN1_F_ASN1_ITEM_FLAGS_I2D:118:asn1_item_flags_i2d + ASN1_F_ASN1_ITEM_I2D_BIO:192:ASN1_item_i2d_bio + ASN1_F_ASN1_ITEM_I2D_FP:193:ASN1_item_i2d_fp +diff --git a/include/openssl/asn1err.h b/include/openssl/asn1err.h +index 9070e26..e1ad1fe 100644 +--- a/include/openssl/asn1err.h ++++ b/include/openssl/asn1err.h +@@ -1,6 +1,6 @@ + /* + * Generated by util/mkerr.pl DO NOT EDIT +- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. ++ * Copyright 1995-2020 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 +@@ -11,9 +11,7 @@ + #ifndef HEADER_ASN1ERR_H + # define HEADER_ASN1ERR_H + +-# ifndef HEADER_SYMHACKS_H +-# include +-# endif ++# include + + # ifdef __cplusplus + extern "C" +@@ -53,6 +51,7 @@ int ERR_load_ASN1_strings(void); + # define ASN1_F_ASN1_ITEM_DUP 191 + # define ASN1_F_ASN1_ITEM_EMBED_D2I 120 + # define ASN1_F_ASN1_ITEM_EMBED_NEW 121 ++# define ASN1_F_ASN1_ITEM_EX_I2D 144 + # define ASN1_F_ASN1_ITEM_FLAGS_I2D 118 + # define ASN1_F_ASN1_ITEM_I2D_BIO 192 + # define ASN1_F_ASN1_ITEM_I2D_FP 193 +-- +1.8.3.1 + diff --git a/CVE-2020-1971-0005-Add-a-test-for-GENERAL_NAME_cmp.patch b/CVE-2020-1971-0005-Add-a-test-for-GENERAL_NAME_cmp.patch new file mode 100644 index 0000000..614df6c --- /dev/null +++ b/CVE-2020-1971-0005-Add-a-test-for-GENERAL_NAME_cmp.patch @@ -0,0 +1,372 @@ +From 94ece6af0c89d596f9c5221b7df7d6582168c8ba Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Mon, 30 Nov 2020 13:50:52 +0000 +Subject: [PATCH 05/31] Add a test for GENERAL_NAME_cmp + +Based on a boringssl test contributed by David Benjamin + +Reviewed-by: Tomas Mraz +--- + test/v3nametest.c | 344 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 344 insertions(+) + +diff --git a/test/v3nametest.c b/test/v3nametest.c +index 86f3829..4c8af92 100644 +--- a/test/v3nametest.c ++++ b/test/v3nametest.c +@@ -359,8 +359,352 @@ static int call_run_cert(int i) + return failed == 0; + } + ++struct gennamedata { ++ const unsigned char der[22]; ++ size_t derlen; ++} gennames[] = { ++ { ++ /* ++ * [0] { ++ * OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.2.1 } ++ * [0] { ++ * SEQUENCE {} ++ * } ++ * } ++ */ ++ { ++ 0xa0, 0x13, 0x06, 0x0d, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, ++ 0x01, 0x84, 0xb7, 0x09, 0x02, 0x01, 0xa0, 0x02, 0x30, 0x00 ++ }, ++ 21 ++ }, { ++ /* ++ * [0] { ++ * OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.2.1 } ++ * [0] { ++ * [APPLICATION 0] {} ++ * } ++ * } ++ */ ++ { ++ 0xa0, 0x13, 0x06, 0x0d, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, ++ 0x01, 0x84, 0xb7, 0x09, 0x02, 0x01, 0xa0, 0x02, 0x60, 0x00 ++ }, ++ 21 ++ }, { ++ /* ++ * [0] { ++ * OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.2.1 } ++ * [0] { ++ * UTF8String { "a" } ++ * } ++ * } ++ */ ++ { ++ 0xa0, 0x14, 0x06, 0x0d, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, ++ 0x01, 0x84, 0xb7, 0x09, 0x02, 0x01, 0xa0, 0x03, 0x0c, 0x01, 0x61 ++ }, ++ 22 ++ }, { ++ /* ++ * [0] { ++ * OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.2.2 } ++ * [0] { ++ * UTF8String { "a" } ++ * } ++ * } ++ */ ++ { ++ 0xa0, 0x14, 0x06, 0x0d, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, ++ 0x01, 0x84, 0xb7, 0x09, 0x02, 0x02, 0xa0, 0x03, 0x0c, 0x01, 0x61 ++ }, ++ 22 ++ }, { ++ /* ++ * [0] { ++ * OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.2.1 } ++ * [0] { ++ * UTF8String { "b" } ++ * } ++ * } ++ */ ++ { ++ 0xa0, 0x14, 0x06, 0x0d, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, ++ 0x01, 0x84, 0xb7, 0x09, 0x02, 0x01, 0xa0, 0x03, 0x0c, 0x01, 0x62 ++ }, ++ 22 ++ }, { ++ /* ++ * [0] { ++ * OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.2.1 } ++ * [0] { ++ * BOOLEAN { TRUE } ++ * } ++ * } ++ */ ++ { ++ 0xa0, 0x14, 0x06, 0x0d, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, ++ 0x01, 0x84, 0xb7, 0x09, 0x02, 0x01, 0xa0, 0x03, 0x01, 0x01, 0xff ++ }, ++ 22 ++ }, { ++ /* ++ * [0] { ++ * OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.2.1 } ++ * [0] { ++ * BOOLEAN { FALSE } ++ * } ++ * } ++ */ ++ { ++ 0xa0, 0x14, 0x06, 0x0d, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, ++ 0x01, 0x84, 0xb7, 0x09, 0x02, 0x01, 0xa0, 0x03, 0x01, 0x01, 0x00 ++ }, ++ 22 ++ }, { ++ /* [1 PRIMITIVE] { "a" } */ ++ { ++ 0x81, 0x01, 0x61 ++ }, ++ 3 ++ }, { ++ /* [1 PRIMITIVE] { "b" } */ ++ { ++ 0x81, 0x01, 0x62 ++ }, ++ 3 ++ }, { ++ /* [2 PRIMITIVE] { "a" } */ ++ { ++ 0x82, 0x01, 0x61 ++ }, ++ 3 ++ }, { ++ /* [2 PRIMITIVE] { "b" } */ ++ { ++ 0x82, 0x01, 0x62 ++ }, ++ 3 ++ }, { ++ /* ++ * [4] { ++ * SEQUENCE { ++ * SET { ++ * SEQUENCE { ++ * # commonName ++ * OBJECT_IDENTIFIER { 2.5.4.3 } ++ * UTF8String { "a" } ++ * } ++ * } ++ * } ++ * } ++ */ ++ { ++ 0xa4, 0x0e, 0x30, 0x0c, 0x31, 0x0a, 0x30, 0x08, 0x06, 0x03, 0x55, ++ 0x04, 0x03, 0x0c, 0x01, 0x61 ++ }, ++ 16 ++ }, { ++ /* ++ * [4] { ++ * SEQUENCE { ++ * SET { ++ * SEQUENCE { ++ * # commonName ++ * OBJECT_IDENTIFIER { 2.5.4.3 } ++ * UTF8String { "b" } ++ * } ++ * } ++ * } ++ * } ++ */ ++ { ++ 0xa4, 0x0e, 0x30, 0x0c, 0x31, 0x0a, 0x30, 0x08, 0x06, 0x03, 0x55, ++ 0x04, 0x03, 0x0c, 0x01, 0x62 ++ }, ++ 16 ++ }, { ++ /* ++ * [5] { ++ * [1] { ++ * UTF8String { "a" } ++ * } ++ * } ++ */ ++ { ++ 0xa5, 0x05, 0xa1, 0x03, 0x0c, 0x01, 0x61 ++ }, ++ 7 ++ }, { ++ /* ++ * [5] { ++ * [1] { ++ * UTF8String { "b" } ++ * } ++ * } ++ */ ++ { ++ 0xa5, 0x05, 0xa1, 0x03, 0x0c, 0x01, 0x62 ++ }, ++ 7 ++ }, { ++ /* ++ * [5] { ++ * [0] { ++ * UTF8String {} ++ * } ++ * [1] { ++ * UTF8String { "a" } ++ * } ++ * } ++ */ ++ { ++ 0xa5, 0x09, 0xa0, 0x02, 0x0c, 0x00, 0xa1, 0x03, 0x0c, 0x01, 0x61 ++ }, ++ 11 ++ }, { ++ /* ++ * [5] { ++ * [0] { ++ * UTF8String { "a" } ++ * } ++ * [1] { ++ * UTF8String { "a" } ++ * } ++ * } ++ */ ++ { ++ 0xa5, 0x0a, 0xa0, 0x03, 0x0c, 0x01, 0x61, 0xa1, 0x03, 0x0c, 0x01, ++ 0x61 ++ }, ++ 12 ++ }, { ++ /* ++ * [5] { ++ * [0] { ++ * UTF8String { "b" } ++ * } ++ * [1] { ++ * UTF8String { "a" } ++ * } ++ * } ++ */ ++ { ++ 0xa5, 0x0a, 0xa0, 0x03, 0x0c, 0x01, 0x62, 0xa1, 0x03, 0x0c, 0x01, ++ 0x61 ++ }, ++ 12 ++ }, { ++ /* [6 PRIMITIVE] { "a" } */ ++ { ++ 0x86, 0x01, 0x61 ++ }, ++ 3 ++ }, { ++ /* [6 PRIMITIVE] { "b" } */ ++ { ++ 0x86, 0x01, 0x62 ++ }, ++ 3 ++ }, { ++ /* [7 PRIMITIVE] { `11111111` } */ ++ { ++ 0x87, 0x04, 0x11, 0x11, 0x11, 0x11 ++ }, ++ 6 ++ }, { ++ /* [7 PRIMITIVE] { `22222222`} */ ++ { ++ 0x87, 0x04, 0x22, 0x22, 0x22, 0x22 ++ }, ++ 6 ++ }, { ++ /* [7 PRIMITIVE] { `11111111111111111111111111111111` } */ ++ { ++ 0x87, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, ++ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 ++ }, ++ 18 ++ }, { ++ /* [7 PRIMITIVE] { `22222222222222222222222222222222` } */ ++ { ++ 0x87, 0x10, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, ++ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 ++ }, ++ 18 ++ }, { ++ /* [8 PRIMITIVE] { 1.2.840.113554.4.1.72585.2.1 } */ ++ { ++ 0x88, 0x0d, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, ++ 0xb7, 0x09, 0x02, 0x01 ++ }, ++ 15 ++ }, { ++ /* [8 PRIMITIVE] { 1.2.840.113554.4.1.72585.2.2 } */ ++ { ++ 0x88, 0x0d, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, ++ 0xb7, 0x09, 0x02, 0x02 ++ }, ++ 15 ++ } ++}; ++ ++static int test_GENERAL_NAME_cmp(void) ++{ ++ size_t i, j; ++ GENERAL_NAME **namesa = OPENSSL_malloc(sizeof(*namesa) ++ * OSSL_NELEM(gennames)); ++ GENERAL_NAME **namesb = OPENSSL_malloc(sizeof(*namesb) ++ * OSSL_NELEM(gennames)); ++ int testresult = 0; ++ ++ if (!TEST_ptr(namesa) || !TEST_ptr(namesb)) ++ goto end; ++ ++ for (i = 0; i < OSSL_NELEM(gennames); i++) { ++ const unsigned char *derp = gennames[i].der; ++ ++ /* ++ * We create two versions of each GENERAL_NAME so that we ensure when ++ * we compare them they are always different pointers. ++ */ ++ namesa[i] = d2i_GENERAL_NAME(NULL, &derp, gennames[i].derlen); ++ derp = gennames[i].der; ++ namesb[i] = d2i_GENERAL_NAME(NULL, &derp, gennames[i].derlen); ++ if (!TEST_ptr(namesa[i]) || !TEST_ptr(namesb[i])) ++ goto end; ++ } ++ ++ /* Every name should be equal to itself and not equal to any others. */ ++ for (i = 0; i < OSSL_NELEM(gennames); i++) { ++ for (j = 0; j < OSSL_NELEM(gennames); j++) { ++ if (i == j) { ++ if (!TEST_int_eq(GENERAL_NAME_cmp(namesa[i], namesb[j]), 0)) ++ goto end; ++ } else { ++ if (!TEST_int_ne(GENERAL_NAME_cmp(namesa[i], namesb[j]), 0)) ++ goto end; ++ } ++ } ++ } ++ testresult = 1; ++ ++ end: ++ for (i = 0; i < OSSL_NELEM(gennames); i++) { ++ if (namesa != NULL) ++ GENERAL_NAME_free(namesa[i]); ++ if (namesb != NULL) ++ GENERAL_NAME_free(namesb[i]); ++ } ++ OPENSSL_free(namesa); ++ OPENSSL_free(namesb); ++ ++ return testresult; ++} ++ + int setup_tests(void) + { + ADD_ALL_TESTS(call_run_cert, OSSL_NELEM(name_fns)); ++ ADD_TEST(test_GENERAL_NAME_cmp); + return 1; + } +-- +1.8.3.1 + diff --git a/CVE-2020-1971-0006-Add-a-test-for-encoding-decoding-using-an-invalid-AS.patch b/CVE-2020-1971-0006-Add-a-test-for-encoding-decoding-using-an-invalid-AS.patch new file mode 100644 index 0000000..8569490 --- /dev/null +++ b/CVE-2020-1971-0006-Add-a-test-for-encoding-decoding-using-an-invalid-AS.patch @@ -0,0 +1,121 @@ +From 433974af7b188d55b1da049b84f3fdeca320cb6a Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Mon, 30 Nov 2020 14:46:47 +0000 +Subject: [PATCH 06/31] Add a test for encoding/decoding using an invalid ASN.1 + Template + +If you have a CHOICE type that it must use explicit tagging - otherwise +the template is invalid. We add tests for this. + +Reviewed-by: Tomas Mraz +--- + test/asn1_decode_test.c | 36 ++++++++++++++++++++++++++++++++++++ + test/asn1_encode_test.c | 33 +++++++++++++++++++++++++++++++++ + 2 files changed, 69 insertions(+) + +diff --git a/test/asn1_decode_test.c b/test/asn1_decode_test.c +index 369023d..94a22c6 100644 +--- a/test/asn1_decode_test.c ++++ b/test/asn1_decode_test.c +@@ -160,6 +160,41 @@ static int test_uint64(void) + return 1; + } + ++typedef struct { ++ ASN1_STRING *invalidDirString; ++} INVALIDTEMPLATE; ++ ++ASN1_SEQUENCE(INVALIDTEMPLATE) = { ++ /* ++ * DirectoryString is a CHOICE type so it must use explicit tagging - ++ * but we deliberately use implicit here, which makes this template invalid. ++ */ ++ ASN1_IMP(INVALIDTEMPLATE, invalidDirString, DIRECTORYSTRING, 12) ++} static_ASN1_SEQUENCE_END(INVALIDTEMPLATE) ++ ++IMPLEMENT_STATIC_ASN1_ENCODE_FUNCTIONS(INVALIDTEMPLATE) ++IMPLEMENT_STATIC_ASN1_ALLOC_FUNCTIONS(INVALIDTEMPLATE) ++ ++/* Empty sequence for invalid template test */ ++static unsigned char t_invalid_template[] = { ++ 0x30, 0x03, /* SEQUENCE tag + length */ ++ 0x0c, 0x01, 0x41 /* UTF8String, length 1, "A" */ ++}; ++ ++static int test_invalid_template(void) ++{ ++ const unsigned char *p = t_invalid_template; ++ INVALIDTEMPLATE *tmp = d2i_INVALIDTEMPLATE(NULL, &p, ++ sizeof(t_invalid_template)); ++ ++ /* We expect a NULL pointer return */ ++ if (TEST_ptr_null(tmp)) ++ return 1; ++ ++ INVALIDTEMPLATE_free(tmp); ++ return 0; ++} ++ + int setup_tests(void) + { + #if OPENSSL_API_COMPAT < 0x10200000L +@@ -169,5 +204,6 @@ int setup_tests(void) + ADD_TEST(test_uint32); + ADD_TEST(test_int64); + ADD_TEST(test_uint64); ++ ADD_TEST(test_invalid_template); + return 1; + } +diff --git a/test/asn1_encode_test.c b/test/asn1_encode_test.c +index ed920a4..afbd18b 100644 +--- a/test/asn1_encode_test.c ++++ b/test/asn1_encode_test.c +@@ -856,6 +856,38 @@ static int test_uint64(void) + return test_intern(&uint64_test_package); + } + ++typedef struct { ++ ASN1_STRING *invalidDirString; ++} INVALIDTEMPLATE; ++ ++ASN1_SEQUENCE(INVALIDTEMPLATE) = { ++ /* ++ * DirectoryString is a CHOICE type so it must use explicit tagging - ++ * but we deliberately use implicit here, which makes this template invalid. ++ */ ++ ASN1_IMP(INVALIDTEMPLATE, invalidDirString, DIRECTORYSTRING, 12) ++} static_ASN1_SEQUENCE_END(INVALIDTEMPLATE) ++ ++IMPLEMENT_STATIC_ASN1_ENCODE_FUNCTIONS(INVALIDTEMPLATE) ++IMPLEMENT_STATIC_ASN1_ALLOC_FUNCTIONS(INVALIDTEMPLATE) ++ ++static int test_invalid_template(void) ++{ ++ INVALIDTEMPLATE *temp = INVALIDTEMPLATE_new(); ++ int ret; ++ ++ if (!TEST_ptr(temp)) ++ return 0; ++ ++ ret = i2d_INVALIDTEMPLATE(temp, NULL); ++ ++ INVALIDTEMPLATE_free(temp); ++ ++ /* We expect the i2d operation to fail */ ++ return ret < 0; ++} ++ ++ + int setup_tests(void) + { + #if OPENSSL_API_COMPAT < 0x10200000L +@@ -866,5 +898,6 @@ int setup_tests(void) + ADD_TEST(test_uint32); + ADD_TEST(test_int64); + ADD_TEST(test_uint64); ++ ADD_TEST(test_invalid_template); + return 1; + } +-- +1.8.3.1 + diff --git a/openssl.spec b/openssl.spec index 7f8db34..934ff62 100644 --- a/openssl.spec +++ b/openssl.spec @@ -2,7 +2,7 @@ Name: openssl Epoch: 1 Version: 1.1.1f -Release: 2 +Release: 3 Summary: Cryptography and SSL/TLS Toolkit License: OpenSSL and SSLeay URL: https://www.openssl.org/ @@ -11,6 +11,12 @@ Source1: Makefile.certificate Patch1: openssl-1.1.1-build.patch Patch2: openssl-1.1.1-fips.patch Patch3: CVE-2020-1967.patch +Patch4: CVE-2020-1971-0001-DirectoryString-is-a-CHOICE-type-and-therefore-uses-.patch +Patch5: CVE-2020-1971-0002-Correctly-compare-EdiPartyName-in-GENERAL_NAME_cmp.patch +Patch6: CVE-2020-1971-0003-Check-that-multi-strings-CHOICE-types-don-t-use-impl.patch +Patch7: CVE-2020-1971-0004-Complain-if-we-are-attempting-to-encode-with-an-inva.patch +Patch8: CVE-2020-1971-0005-Add-a-test-for-GENERAL_NAME_cmp.patch +Patch9: CVE-2020-1971-0006-Add-a-test-for-encoding-decoding-using-an-invalid-AS.patch BuildRequires: gcc make lksctp-tools-devel coreutils util-linux zlib-devel @@ -187,6 +193,9 @@ make test || : %{_pkgdocdir}/html/ %changelog +* Mon Jan 19 2021 openEuler Buildteam - 1:1.1.1f-3 +- fix CVE-2020-1971 + * Fri Sep 11 2020 Liquor - 1:1.1.1f-2 - provides openssl-perl -- Gitee