From 021fa4b973326cef53a0d18ef9c62bd8b0d63c33 Mon Sep 17 00:00:00 2001 From: Hugel <2712504175@qq.com> Date: Mon, 9 May 2022 19:34:00 +0800 Subject: [PATCH] fix CVE-2021-42782 --- ...2782-tcos-prevent-out-of-bounds-read.patch | 25 ++ ...42782-coolkey-Initialize-potentially.patch | 26 ++ ...-cardos-Correctly-calculate-the-left.patch | 0 ...21-42782-iasecc-Prevent-stack-buffer.patch | 26 ++ ...-CVE-2021-42782-PIV-Improved-parsing.patch | 223 ++++++++++++++++++ opensc.spec | 21 +- 6 files changed, 314 insertions(+), 7 deletions(-) create mode 100644 backport-0001-CVE-2021-42782-tcos-prevent-out-of-bounds-read.patch create mode 100644 backport-0002-CVE-2021-42782-coolkey-Initialize-potentially.patch rename cardos-Correctly-calculate-the-left-bytes-to-avoid-b.patch => backport-0003-CVE-2021-42782-cardos-Correctly-calculate-the-left.patch (100%) create mode 100644 backport-0004-CVE-2021-42782-iasecc-Prevent-stack-buffer.patch create mode 100644 backport-0005-CVE-2021-42782-PIV-Improved-parsing.patch diff --git a/backport-0001-CVE-2021-42782-tcos-prevent-out-of-bounds-read.patch b/backport-0001-CVE-2021-42782-tcos-prevent-out-of-bounds-read.patch new file mode 100644 index 0000000..249155d --- /dev/null +++ b/backport-0001-CVE-2021-42782-tcos-prevent-out-of-bounds-read.patch @@ -0,0 +1,25 @@ +From 78cdab949f098ad7e593d853229fccf57d749d0c Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Mon, 30 Nov 2020 17:43:03 +0100 +Subject: [PATCH] tcos: prevent out of bounds read + +Thanks oss-fuzz + +https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=27719 +--- + src/libopensc/pkcs15-tcos.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libopensc/pkcs15-tcos.c b/src/libopensc/pkcs15-tcos.c +index 60de1470eb..1134ac11ba 100644 +--- a/src/libopensc/pkcs15-tcos.c ++++ b/src/libopensc/pkcs15-tcos.c +@@ -152,7 +152,7 @@ static int insert_key( + sc_log(ctx, "No EF_KEYD-Record found\n"); + return 1; + } +- for (i = 0; i < r; i += 2 + buf[i + 1]) { ++ for (i = 0; i + 1 < r; i += 2 + buf[i + 1]) { + if (buf[i] == 0xB6) + can_sign++; + if (buf[i] == 0xB8) diff --git a/backport-0002-CVE-2021-42782-coolkey-Initialize-potentially.patch b/backport-0002-CVE-2021-42782-coolkey-Initialize-potentially.patch new file mode 100644 index 0000000..3e00d0d --- /dev/null +++ b/backport-0002-CVE-2021-42782-coolkey-Initialize-potentially.patch @@ -0,0 +1,26 @@ +From 7114fb71b54ddfe06ce5dfdab013f4c38f129d14 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Wed, 24 Mar 2021 10:57:27 +0100 +Subject: [PATCH] coolkey: Initialize potentially uninitialized memory + +Thanks oss-fuzz + +https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28855 +--- + src/libopensc/pkcs15-coolkey.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/libopensc/pkcs15-coolkey.c b/src/libopensc/pkcs15-coolkey.c +index 373ec7a5a9..586475ddee 100644 +--- a/src/libopensc/pkcs15-coolkey.c ++++ b/src/libopensc/pkcs15-coolkey.c +@@ -425,7 +425,8 @@ coolkey_get_public_key_from_certificate(sc_pkcs15_card_t *p15card, sc_cardctl_co + sc_pkcs15_pubkey_t *key = NULL; + int r; + +- cert_info.value.value = NULL; ++ memset(&cert_info, 0, sizeof(cert_info)); ++ + r = coolkey_get_certificate(p15card->card, obj, &cert_info.value); + if (r < 0) { + goto fail; diff --git a/cardos-Correctly-calculate-the-left-bytes-to-avoid-b.patch b/backport-0003-CVE-2021-42782-cardos-Correctly-calculate-the-left.patch similarity index 100% rename from cardos-Correctly-calculate-the-left-bytes-to-avoid-b.patch rename to backport-0003-CVE-2021-42782-cardos-Correctly-calculate-the-left.patch diff --git a/backport-0004-CVE-2021-42782-iasecc-Prevent-stack-buffer.patch b/backport-0004-CVE-2021-42782-iasecc-Prevent-stack-buffer.patch new file mode 100644 index 0000000..0fb3a7a --- /dev/null +++ b/backport-0004-CVE-2021-42782-iasecc-Prevent-stack-buffer.patch @@ -0,0 +1,26 @@ +From ae1cf0be90396fb6c0be95829bf0d3eecbd2fd1c Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Thu, 11 Feb 2021 11:22:54 +0100 +Subject: [PATCH] iasecc: Prevent stack buffer overflow when empty ACL is + returned + +Thanks oss-fuzz + +https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=30800 +--- + src/libopensc/card-iasecc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libopensc/card-iasecc.c b/src/libopensc/card-iasecc.c +index 166bc307bc..0eec63363a 100644 +--- a/src/libopensc/card-iasecc.c ++++ b/src/libopensc/card-iasecc.c +@@ -1171,7 +1171,7 @@ iasecc_process_fci(struct sc_card *card, struct sc_file *file, + else + acls = sc_asn1_find_tag(ctx, buf, buflen, IASECC_DOCP_TAG_ACLS_CONTACT, &taglen); + +- if (!acls) { ++ if (!acls || taglen < 7) { + sc_log(ctx, + "ACLs not found in data(%"SC_FORMAT_LEN_SIZE_T"u) %s", + buflen, sc_dump_hex(buf, buflen)); diff --git a/backport-0005-CVE-2021-42782-PIV-Improved-parsing.patch b/backport-0005-CVE-2021-42782-PIV-Improved-parsing.patch new file mode 100644 index 0000000..8267ed7 --- /dev/null +++ b/backport-0005-CVE-2021-42782-PIV-Improved-parsing.patch @@ -0,0 +1,223 @@ +From 456ac566938a1da774db06126a2fa6c0cba514b3 Mon Sep 17 00:00:00 2001 +From: Doug Engert +Date: Wed, 14 Jul 2021 11:15:10 -0500 +Subject: [PATCH] PIV Improved parsing of data from the card + +Based on Fuzz testing, many of the calls to sc_asn1_find_tag were replaced +with sc_asn1_read_tag. The input is also tested that the +expected tag is the first byte. Additional tests are also add. + +sc_asn1_find_tag will skip 0X00 or 0Xff if found. NIST sp800-73-x specs +do not allow these extra bytes. + + On branch PIV-improved-parsing + Changes to be committed: + modified: card-piv.c +--- + src/libopensc/card-piv.c | 112 +++++++++++++++++++++------------------ + 1 file changed, 60 insertions(+), 52 deletions(-) + +diff --git a/src/libopensc/card-piv.c b/src/libopensc/card-piv.c +index f144b2ccef..77e4864f66 100644 +--- a/src/libopensc/card-piv.c ++++ b/src/libopensc/card-piv.c +@@ -608,14 +608,12 @@ static int piv_generate_key(sc_card_t *card, + const u8 *cp; + keydata->exponent = 0; + +- /* expected tag is 7f49. */ +- /* we will whatever tag is present */ +- + cp = rbuf; + in_len = r; + ++ /* expected tag is 0x7f49,returned as cla_out == 0x60 and tag_out = 0x1F49 */ + r = sc_asn1_read_tag(&cp, in_len, &cla_out, &tag_out, &in_len); +- if (cp == NULL) { ++ if (cp == NULL || in_len == 0 || cla_out != 0x60 || tag_out != 0x1f49) { + r = SC_ERROR_ASN1_OBJECT_NOT_FOUND; + } + if (r != SC_SUCCESS) { +@@ -1032,7 +1030,7 @@ piv_cache_internal_data(sc_card_t *card, int enumtag) + priv->obj_cache[enumtag].obj_len, + 0x53, &bodylen); + +- if (body == NULL) ++ if (body == NULL || priv->obj_cache[enumtag].obj_data[0] != 0x53) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_OBJECT_NOT_VALID); + + /* get the certificate out */ +@@ -1611,7 +1609,7 @@ static int piv_general_mutual_authenticate(sc_card_t *card, + /* Remove the encompassing outer TLV of 0x7C and get the data */ + body = sc_asn1_find_tag(card->ctx, rbuf, + r, 0x7C, &body_len); +- if (!body) { ++ if (!body || rbuf[0] != 0x7C) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Invalid Witness Data response of NULL\n"); + r = SC_ERROR_INVALID_DATA; + goto err; +@@ -1753,7 +1751,7 @@ static int piv_general_mutual_authenticate(sc_card_t *card, + /* Remove the encompassing outer TLV of 0x7C and get the data */ + body = sc_asn1_find_tag(card->ctx, rbuf, + r, 0x7C, &body_len); +- if(!body) { ++ if(!body || rbuf[0] != 0x7C) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not find outer tag 0x7C in response"); + r = SC_ERROR_INVALID_DATA; + goto err; +@@ -1914,7 +1912,7 @@ static int piv_general_external_authenticate(sc_card_t *card, + /* Remove the encompassing outer TLV of 0x7C and get the data */ + body = sc_asn1_find_tag(card->ctx, rbuf, + r, 0x7C, &body_len); +- if (!body) { ++ if (!body || rbuf[0] != 0x7C) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Invalid Challenge Data response of NULL\n"); + r = SC_ERROR_INVALID_DATA; + goto err; +@@ -2079,7 +2077,7 @@ piv_get_serial_nr_from_CHUI(sc_card_t* card, sc_serial_number_t* serial) + r = SC_ERROR_INTERNAL; + if (rbuflen != 0) { + body = sc_asn1_find_tag(card->ctx, rbuf, rbuflen, 0x53, &bodylen); /* Pass the outer wrapper asn1 */ +- if (body != NULL && bodylen != 0) { ++ if (body != NULL && bodylen != 0 && rbuf[0] == 0x53) { + fascn = sc_asn1_find_tag(card->ctx, body, bodylen, 0x30, &fascnlen); /* Find the FASC-N data */ + guid = sc_asn1_find_tag(card->ctx, body, bodylen, 0x34, &guidlen); + +@@ -2311,10 +2309,10 @@ static int piv_validate_general_authentication(sc_card_t *card, + piv_private_data_t * priv = PIV_DATA(card); + int r, tmplen, tmplen2; + u8 *p; +- const u8 *tag; ++ const unsigned char *p2; + size_t taglen; +- const u8 *body; + size_t bodylen; ++ unsigned int cla, tag; + unsigned int real_alg_id, op_tag; + + u8 sbuf[4096]; /* needs work. for 3072 keys, needs 384+10 or so */ +@@ -2367,20 +2365,28 @@ static int piv_validate_general_authentication(sc_card_t *card, + + r = piv_general_io(card, 0x87, real_alg_id, priv->key_ref, + sbuf, p - sbuf, rbuf, sizeof rbuf); ++ if (r < 0) ++ goto err; + +- if (r >= 0) { +- body = sc_asn1_find_tag(card->ctx, rbuf, r, 0x7c, &bodylen); +- if (body) { +- tag = sc_asn1_find_tag(card->ctx, body, bodylen, 0x82, &taglen); +- if (tag) { +- memcpy(out, tag, taglen); +- r = taglen; +- } else +- r = SC_ERROR_INVALID_DATA; +- } else +- r = SC_ERROR_INVALID_DATA; ++ p2 = rbuf; ++ r = sc_asn1_read_tag(&p2, r, &cla, &tag, &bodylen); ++ if (p2 == NULL || r < 0 || bodylen == 0 || (cla|tag) != 0x7C) { ++ LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA, "Can't find 0x7C"); ++ } ++ ++ r = sc_asn1_read_tag(&p2, bodylen, &cla, &tag, &taglen); ++ if (p2 == NULL || r < 0 || taglen == 0 || (cla|tag) != 0x82) { ++ LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA, "Can't find 0x82"); + } + ++ if (taglen > outlen) { ++ LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA, "data read longer then buffer"); ++ } ++ ++ memcpy(out, p2, taglen); ++ r = taglen; ++ ++err: + LOG_FUNC_RETURN(card->ctx, r); + } + +@@ -2394,19 +2400,19 @@ piv_compute_signature(sc_card_t *card, const u8 * data, size_t datalen, + int i; + size_t nLen; + u8 rbuf[128]; /* For EC conversions 384 will fit */ +- const u8 * body; +- size_t bodylen; +- const u8 * tag; +- size_t taglen; ++ const unsigned char *pseq, *pint, *ptemp, *pend; ++ unsigned int cla, tag; ++ size_t seqlen; ++ size_t intlen; ++ size_t templen; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + + /* The PIV returns a DER SEQUENCE{INTEGER, INTEGER} +- * Which may have leading 00 to force positive +- * TODO: -DEE should check if PKCS15 want the same +- * But PKCS11 just wants 2* filed_length in bytes ++ * Which may have leading 00 to force a positive integer ++ * But PKCS11 just wants 2* field_length in bytes + * So we have to strip out the integers +- * if present and pad on left if too short. ++ * and pad on left if too short. + */ + + if (priv->alg_id == 0x11 || priv->alg_id == 0x14 ) { +@@ -2424,32 +2430,34 @@ piv_compute_signature(sc_card_t *card, const u8 * data, size_t datalen, + if (r < 0) + goto err; + +- body = sc_asn1_find_tag(card->ctx, rbuf, r, 0x30, &bodylen); +- +- for (i = 0; i<2; i++) { +- if (body) { +- tag = sc_asn1_find_tag(card->ctx, body, bodylen, 0x02, &taglen); +- if (tag) { +- bodylen -= taglen - (tag - body); +- body = tag + taglen; +- +- if (taglen > nLen) { /* drop leading 00 if present */ +- if (*tag != 0x00) { +- r = SC_ERROR_INVALID_DATA; +- goto err; +- } +- tag++; +- taglen--; +- } +- memcpy(out + nLen*i + nLen - taglen , tag, taglen); +- } else { ++ pseq = rbuf; ++ r = sc_asn1_read_tag(&pseq, r, &cla, &tag, &seqlen); ++ if (pseq == NULL || r < 0 || seqlen == 0 || (cla|tag) != 0x30) ++ LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA, "Can't find 0x30"); ++ ++ pint = pseq; ++ pend = pseq + seqlen; ++ for (i = 0; i < 2; i++) { ++ r = sc_asn1_read_tag(&pint, (pend - pint), &cla, &tag, &intlen); ++ if (pint == NULL || r < 0 || intlen == 0 || (cla|tag) != 0x02) ++ LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA, "Can't find 0x02"); ++ if (intlen > nLen + 1) ++ LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA,"Signature too long"); ++ ++ ptemp = pint; ++ templen = intlen; ++ if (intlen > nLen) { /* drop leading 00 if present */ ++ if (*ptemp != 0x00) { ++ LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA,"Signature too long"); + r = SC_ERROR_INVALID_DATA; + goto err; + } +- } else { +- r = SC_ERROR_INVALID_DATA; +- goto err; ++ ptemp++; ++ templen--; + } ++ memcpy(out + nLen*i + nLen - templen , ptemp, templen); ++ pint += intlen; /* next integer */ ++ + } + r = 2 * nLen; + } else { /* RSA is all set */ diff --git a/opensc.spec b/opensc.spec index bd377d3..b0d5e48 100644 --- a/opensc.spec +++ b/opensc.spec @@ -3,7 +3,7 @@ Name: opensc Version: 0.21.0 -Release: 5 +Release: 6 License: LGPLv2.1+ Summary: Smart card library and applications URL: https://github.com/OpenSC/OpenSC/wiki @@ -27,12 +27,16 @@ Patch6: oberthur-Correctly-check-for-return-values.patch Patch7: oberthur-Avoid-memory-leaks.patch Patch8: oberthur-fixed-Heap-buffer-overflow.patch Patch9: oberthur-One-more-overlooked-buffer-overflow.patch -Patch10: cardos-Correctly-calculate-the-left-bytes-to-avoid-b.patch -Patch11: oberthur-Handle-1B-OIDs.patch -Patch12: Fix-ACLs-support.patch -Patch13: backport-CVE-2021-42778-idprime-Use-temporary.patch -Patch14: backport-tcos-Reformat-insert_pin-for-readability.patch -Patch15: backport-CVE-2021-42780-tcos-Check-bounds-in-insert_pin.patch +Patch10: oberthur-Handle-1B-OIDs.patch +Patch11: Fix-ACLs-support.patch +Patch12: backport-CVE-2021-42778-idprime-Use-temporary.patch +Patch13: backport-tcos-Reformat-insert_pin-for-readability.patch +Patch14: backport-CVE-2021-42780-tcos-Check-bounds-in-insert_pin.patch +Patch15: backport-0001-CVE-2021-42782-tcos-prevent-out-of-bounds-read.patch +Patch16: backport-0002-CVE-2021-42782-coolkey-Initialize-potentially.patch +Patch17: backport-0003-CVE-2021-42782-cardos-Correctly-calculate-the-left.patch +Patch18: backport-0004-CVE-2021-42782-iasecc-Prevent-stack-buffer.patch +Patch19: backport-0005-CVE-2021-42782-PIV-Improved-parsing.patch %description OpenSC provides a set of libraries and utilities to work with smart cards. @@ -151,6 +155,9 @@ make check %{_datadir}/opensc/ %changelog +* Mon May 9 2022 Hugel - 0.21.0-6 +- fix CVE-2021-42782 + * Mon May 9 2022 Hugel - 0.21.0-5 - fix CVE-2021-42778 CVE-2021-42780 -- Gitee