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 0000000000000000000000000000000000000000..249155d1ad7a7b973eaeee9287580e89f2ed8f43 --- /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 0000000000000000000000000000000000000000..3e00d0d2b9c764d6b68239ccfcc8c7d3596fce6f --- /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 0000000000000000000000000000000000000000..0fb3a7a3efa52fbfeb2ac68ef7eff995b504579d --- /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 0000000000000000000000000000000000000000..4c8c3978486a8b243be1080f5a6ae70526b20f28 --- /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; + 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; + + 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/backport-simplify-PIV-IO.patch b/backport-simplify-PIV-IO.patch new file mode 100644 index 0000000000000000000000000000000000000000..d91c16c2a37a4df27eb31f21b1ee44cf33bbeb1e --- /dev/null +++ b/backport-simplify-PIV-IO.patch @@ -0,0 +1,378 @@ +From cfd5519b981c1aeb8f150a13b0f116fb281c8782 Mon Sep 17 00:00:00 2001 +From: Frank Morgner +Date: Tue, 17 Sep 2019 15:15:30 +0200 +Subject: [PATCH] simplify PIV I/O + +--- + src/libopensc/card-piv.c | 126 +++++++++++---------------------------- + 1 file changed, 34 insertions(+), 92 deletions(-) + +diff --git a/src/libopensc/card-piv.c b/src/libopensc/card-piv.c +index 7098e64ecf..6e5e116699 100644 +--- a/src/libopensc/card-piv.c ++++ b/src/libopensc/card-piv.c +@@ -513,34 +513,17 @@ put_tag_and_len(unsigned int tag, size_t len, u8 **ptr) + * Used by GET DATA, PUT DATA, GENERAL AUTHENTICATE + * and GENERATE ASYMMETRIC KEY PAIR. + * GET DATA may call to get the first 128 bytes to get the length from the tag. +- * +- * A caller may provide a buffer, and length to read. If not provided, +- * an internal 4096 byte buffer is used, and a copy is returned to the +- * caller. that need to be freed by the caller. + */ + + static int piv_general_io(sc_card_t *card, int ins, int p1, int p2, +- const u8 * sendbuf, size_t sendbuflen, u8 ** recvbuf, +- size_t * recvbuflen) ++ const u8 * sendbuf, size_t sendbuflen, u8 *recvbuf, ++ size_t recvbuflen) + { + int r; + sc_apdu_t apdu; +- u8 rbufinitbuf[4096]; +- u8 *rbuf; +- size_t rbuflen; +- + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + +- rbuf = rbufinitbuf; +- rbuflen = sizeof(rbufinitbuf); +- +- /* if caller provided a buffer and length */ +- if (recvbuf && *recvbuf && recvbuflen && *recvbuflen) { +- rbuf = *recvbuf; +- rbuflen = *recvbuflen; +- } +- + r = sc_lock(card); + if (r != SC_SUCCESS) + LOG_FUNC_RETURN(card->ctx, r); +@@ -553,15 +536,14 @@ static int piv_general_io(sc_card_t *card, int ins, int p1, int p2, + apdu.datalen = sendbuflen; + apdu.data = sendbuf; + +- if (recvbuf) { +- apdu.resp = rbuf; +- apdu.le = (rbuflen > 256) ? 256 : rbuflen; +- apdu.resplen = rbuflen; ++ if (recvbuf && recvbuflen) { ++ apdu.le = (recvbuflen > 256) ? 256 : recvbuflen; ++ apdu.resplen = recvbuflen; + } else { +- apdu.resp = rbuf; + apdu.le = 0; + apdu.resplen = 0; + } ++ apdu.resp = recvbuf; + + /* with new adpu.c and chaining, this actually reads the whole object */ + r = sc_transmit_apdu(card, &apdu); +@@ -578,18 +560,7 @@ static int piv_general_io(sc_card_t *card, int ins, int p1, int p2, + goto err; + } + +- if (recvbuflen) { +- if (recvbuf && *recvbuf == NULL) { +- *recvbuf = malloc(apdu.resplen); +- if (*recvbuf == NULL) { +- r = SC_ERROR_OUT_OF_MEMORY; +- goto err; +- } +- memcpy(*recvbuf, rbuf, apdu.resplen); /* copy tag too */ +- } +- *recvbuflen = apdu.resplen; +- r = *recvbuflen; +- } ++ r = apdu.resplen; + + err: + sc_unlock(card); +@@ -604,8 +575,7 @@ static int piv_generate_key(sc_card_t *card, + sc_cardctl_piv_genkey_info_t *keydata) + { + int r; +- u8 *rbuf = NULL; +- size_t rbuflen = 0; ++ u8 rbuf[4096]; + u8 *p; + const u8 *tag; + u8 tagbuf[16]; +@@ -654,7 +624,7 @@ static int piv_generate_key(sc_card_t *card, + p+=out_len; + + r = piv_general_io(card, 0x47, 0x00, keydata->key_num, +- tagbuf, p - tagbuf, &rbuf, &rbuflen); ++ tagbuf, p - tagbuf, rbuf, sizeof rbuf); + + if (r >= 0) { + const u8 *cp; +@@ -664,9 +634,9 @@ static int piv_generate_key(sc_card_t *card, + /* we will whatever tag is present */ + + cp = rbuf; +- in_len = rbuflen; ++ in_len = r; + +- r = sc_asn1_read_tag(&cp, rbuflen, &cla_out, &tag_out, &in_len); ++ r = sc_asn1_read_tag(&cp, in_len, &cla_out, &tag_out, &in_len); + if (cp == NULL) { + r = SC_ERROR_ASN1_OBJECT_NOT_FOUND; + } +@@ -710,8 +680,6 @@ static int piv_generate_key(sc_card_t *card, + } + + err: +- if (rbuf) +- free(rbuf); + LOG_FUNC_RETURN(card->ctx, r); + } + +@@ -927,27 +895,23 @@ piv_get_data(sc_card_t * card, int enumtag, u8 **buf, size_t *buf_len) + + if (*buf_len == 1 && *buf == NULL) { /* we need to get the length */ + u8 rbufinitbuf[8]; /* tag of 53 with 82 xx xx will fit in 4 */ +- u8 *rbuf; +- size_t rbuflen; + size_t bodylen; + unsigned int cla_out, tag_out; + const u8 *body; + + sc_log(card->ctx, "get len of #%d", enumtag); +- rbuf = rbufinitbuf; +- rbuflen = sizeof(rbufinitbuf); +- r = piv_general_io(card, 0xCB, 0x3F, 0xFF, tagbuf, p - tagbuf, &rbuf, &rbuflen); ++ r = piv_general_io(card, 0xCB, 0x3F, 0xFF, tagbuf, p - tagbuf, rbufinitbuf, sizeof rbufinitbuf); + if (r > 0) { + int r_tag; +- body = rbuf; +- r_tag = sc_asn1_read_tag(&body, rbuflen, &cla_out, &tag_out, &bodylen); ++ body = rbufinitbuf; ++ r_tag = sc_asn1_read_tag(&body, r, &cla_out, &tag_out, &bodylen); + if ((r_tag != SC_SUCCESS && r_tag != SC_ERROR_ASN1_END_OF_CONTENTS) + || body == NULL) { + sc_log(card->ctx, "r_tag:%d body:%p", r_tag, body); + r = SC_ERROR_FILE_NOT_FOUND; + goto err; + } +- *buf_len = (body - rbuf) + bodylen; ++ *buf_len = (body - rbufinitbuf) + bodylen; + } else if ( r == 0 ) { + r = SC_ERROR_FILE_NOT_FOUND; + goto err; +@@ -970,7 +934,7 @@ piv_get_data(sc_card_t * card, int enumtag, u8 **buf, size_t *buf_len) + } + } + +- r = piv_general_io(card, 0xCB, 0x3F, 0xFF, tagbuf, p - tagbuf, buf, buf_len); ++ r = piv_general_io(card, 0xCB, 0x3F, 0xFF, tagbuf, p - tagbuf, *buf, *buf_len); + + err: + sc_unlock(card); +@@ -1270,7 +1234,7 @@ piv_put_data(sc_card_t *card, int tag, const u8 *buf, size_t buf_len) + memcpy(p, buf, buf_len); + p += buf_len; + +- r = piv_general_io(card, 0xDB, 0x3F, 0xFF, sbuf, p - sbuf, NULL, NULL); ++ r = piv_general_io(card, 0xDB, 0x3F, 0xFF, sbuf, p - sbuf, NULL, 0); + + if (sbuf) + free(sbuf); +@@ -1584,8 +1548,7 @@ static int piv_general_mutual_authenticate(sc_card_t *card, + #ifdef ENABLE_OPENSSL + int N; + int locked = 0; +- u8 *rbuf = NULL; +- size_t rbuflen; ++ u8 rbuf[4096]; + u8 *nonce = NULL; + size_t nonce_len; + u8 *p; +@@ -1645,7 +1608,7 @@ static int piv_general_mutual_authenticate(sc_card_t *card, + *p++ = 0x00; + + /* get the encrypted nonce */ +- r = piv_general_io(card, 0x87, alg_id, key_ref, sbuf, p - sbuf, &rbuf, &rbuflen); ++ r = piv_general_io(card, 0x87, alg_id, key_ref, sbuf, p - sbuf, rbuf, sizeof rbuf); + + if (r < 0) goto err; + +@@ -1765,12 +1728,8 @@ static int piv_general_mutual_authenticate(sc_card_t *card, + put_tag_and_len(0x81, witness_len, &p); + memcpy(p, nonce, witness_len); + +- /* Don't leak rbuf from above */ +- free(rbuf); +- rbuf = NULL; +- + /* Send constructed data */ +- r = piv_general_io(card, 0x87, alg_id, key_ref, built,built_len, &rbuf, &rbuflen); ++ r = piv_general_io(card, 0x87, alg_id, key_ref, built,built_len, rbuf, sizeof rbuf); + if (r < 0) goto err; + + /* Remove the encompassing outer TLV of 0x7C and get the data */ +@@ -1840,8 +1799,6 @@ static int piv_general_mutual_authenticate(sc_card_t *card, + EVP_CIPHER_CTX_free(ctx); + if (locked) + sc_unlock(card); +- if (rbuf) +- free(rbuf); + if (decrypted_reponse) + free(decrypted_reponse); + if (built) +@@ -1872,13 +1829,12 @@ static int piv_general_external_authenticate(sc_card_t *card, + int outlen; + int locked = 0; + u8 *p; +- u8 *rbuf = NULL; ++ u8 rbuf[4096]; + u8 *key = NULL; + u8 *cypher_text = NULL; + u8 *output_buf = NULL; + const u8 *body = NULL; + const u8 *challenge_data = NULL; +- size_t rbuflen; + size_t body_len; + size_t output_len; + size_t challenge_len; +@@ -1925,7 +1881,7 @@ static int piv_general_external_authenticate(sc_card_t *card, + *p++ = 0x00; + + /* get a challenge */ +- r = piv_general_io(card, 0x87, alg_id, key_ref, sbuf, p - sbuf, &rbuf, &rbuflen); ++ r = piv_general_io(card, 0x87, alg_id, key_ref, sbuf, p - sbuf, rbuf, sizeof rbuf); + if (r < 0) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Error getting Challenge\n"); + goto err; +@@ -2037,7 +1993,7 @@ static int piv_general_external_authenticate(sc_card_t *card, + goto err; + } + +- r = piv_general_io(card, 0x87, alg_id, key_ref, output_buf, output_len, NULL, NULL); ++ r = piv_general_io(card, 0x87, alg_id, key_ref, output_buf, output_len, NULL, 0); + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Got response challenge\n"); + + err: +@@ -2052,9 +2008,6 @@ static int piv_general_external_authenticate(sc_card_t *card, + free(key); + } + +- if (rbuf) +- free(rbuf); +- + if (cypher_text) + free(cypher_text); + +@@ -2221,9 +2174,9 @@ static int piv_get_challenge(sc_card_t *card, u8 *rnd, size_t len) + { + /* Dynamic Authentication Template (Challenge) */ + u8 sbuf[] = {0x7c, 0x02, 0x81, 0x00}; +- u8 *rbuf = NULL; ++ u8 rbuf[4096]; + const u8 *p; +- size_t rbuf_len = 0, out_len = 0; ++ size_t out_len = 0; + int r; + unsigned int tag, cla; + piv_private_data_t * priv = PIV_DATA(card); +@@ -2236,7 +2189,7 @@ static int piv_get_challenge(sc_card_t *card, u8 *rnd, size_t len) + } + + /* NIST 800-73-3 says use 9B, previous verisons used 00 */ +- r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, sizeof sbuf, &rbuf, &rbuf_len); ++ r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, sizeof sbuf, rbuf, sizeof rbuf); + /* + * piv_get_challenge is called in a loop. + * some cards may allow 1 challenge expecting it to be part of +@@ -2245,10 +2198,7 @@ static int piv_get_challenge(sc_card_t *card, u8 *rnd, size_t len) + * Now that the card returned error, we can try one more time. + */ + if (r == SC_ERROR_INCORRECT_PARAMETERS) { +- if (rbuf) +- free(rbuf); +- rbuf_len = 0; +- r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, sizeof sbuf, &rbuf, &rbuf_len); ++ r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, sizeof sbuf, rbuf, sizeof rbuf); + if (r == SC_ERROR_INCORRECT_PARAMETERS) { + r = SC_ERROR_NOT_SUPPORTED; + } +@@ -2256,13 +2206,12 @@ static int piv_get_challenge(sc_card_t *card, u8 *rnd, size_t len) + LOG_TEST_GOTO_ERR(card->ctx, r, "GENERAL AUTHENTICATE failed"); + + p = rbuf; +- r = sc_asn1_read_tag(&p, rbuf_len, &cla, &tag, &out_len); ++ r = sc_asn1_read_tag(&p, r, &cla, &tag, &out_len); + if (r < 0 || (cla|tag) != 0x7C) { + LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA, "Can't find Dynamic Authentication Template"); + } + +- rbuf_len = out_len; +- r = sc_asn1_read_tag(&p, rbuf_len, &cla, &tag, &out_len); ++ r = sc_asn1_read_tag(&p, out_len, &cla, &tag, &out_len); + if (r < 0 || (cla|tag) != 0x81) { + LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA, "Can't find Challenge"); + } +@@ -2275,8 +2224,6 @@ static int piv_get_challenge(sc_card_t *card, u8 *rnd, size_t len) + r = (int) out_len; + + err: +- free(rbuf); +- + LOG_FUNC_RETURN(card->ctx, r); + + } +@@ -2345,8 +2292,7 @@ static int piv_validate_general_authentication(sc_card_t *card, + unsigned int real_alg_id; + + u8 sbuf[4096]; /* needs work. for 3072 keys, needs 384+10 or so */ +- u8 *rbuf = NULL; +- size_t rbuflen = 0; ++ u8 rbuf[4096]; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + +@@ -2383,10 +2329,10 @@ static int piv_validate_general_authentication(sc_card_t *card, + /* EC alg_id was already set */ + + r = piv_general_io(card, 0x87, real_alg_id, priv->key_ref, +- sbuf, p - sbuf, &rbuf, &rbuflen); ++ sbuf, p - sbuf, rbuf, sizeof rbuf); + + if (r >= 0) { +- body = sc_asn1_find_tag(card->ctx, rbuf, rbuflen, 0x7c, &bodylen); ++ 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) { +@@ -2398,9 +2344,6 @@ static int piv_validate_general_authentication(sc_card_t *card, + r = SC_ERROR_INVALID_DATA; + } + +- if (rbuf) +- free(rbuf); +- + LOG_FUNC_RETURN(card->ctx, r); + } + +@@ -2414,7 +2357,6 @@ 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 */ +- size_t rbuflen = sizeof(rbuf); + const u8 * body; + size_t bodylen; + const u8 * tag; +@@ -2441,11 +2383,11 @@ piv_compute_signature(sc_card_t *card, const u8 * data, size_t datalen, + } + memset(out, 0, outlen); + +- r = piv_validate_general_authentication(card, data, datalen, rbuf, rbuflen); ++ r = piv_validate_general_authentication(card, data, datalen, rbuf, sizeof rbuf); + if (r < 0) + goto err; + +- body = sc_asn1_find_tag(card->ctx, rbuf, rbuflen, 0x30, &bodylen); ++ body = sc_asn1_find_tag(card->ctx, rbuf, r, 0x30, &bodylen); + + for (i = 0; i<2; i++) { + if (body) { diff --git a/backport-tcos-Reformat-insert_key.patch b/backport-tcos-Reformat-insert_key.patch new file mode 100644 index 0000000000000000000000000000000000000000..d7ab5cda3dd28a426bf9792d3879beeb47fb88e8 --- /dev/null +++ b/backport-tcos-Reformat-insert_key.patch @@ -0,0 +1,116 @@ +From d3451faa2190e9f4c12bb00adf00149b7af1d18d Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Mon, 16 Nov 2020 11:57:10 +0100 +Subject: [PATCH] tcos: Reformat insert_key + +--- + src/libopensc/pkcs15-tcos.c | 65 ++++++++++++++++++++++--------------- + 1 file changed, 38 insertions(+), 27 deletions(-) + +diff --git a/src/libopensc/pkcs15-tcos.c b/src/libopensc/pkcs15-tcos.c +index c62a3765f9..06cb1a9010 100644 +--- a/src/libopensc/pkcs15-tcos.c ++++ b/src/libopensc/pkcs15-tcos.c +@@ -99,9 +99,10 @@ static int insert_key( + int key_length, + unsigned char auth_id, + const char *label +-){ +- sc_card_t *card=p15card->card; +- sc_context_t *ctx=p15card->card->ctx; ++) ++{ ++ sc_card_t *card = p15card->card; ++ sc_context_t *ctx = p15card->card->ctx; + sc_file_t *f; + struct sc_pkcs15_prkey_info prkey_info; + struct sc_pkcs15_object prkey_obj; +@@ -121,13 +122,14 @@ static int insert_key( + prkey_obj.auth_id.len = 1; + prkey_obj.auth_id.value[0] = auth_id; + +- can_sign=can_crypt=0; +- if(card->type==SC_CARD_TYPE_TCOS_V3){ ++ can_sign = can_crypt = 0; ++ if (card->type == SC_CARD_TYPE_TCOS_V3) { + unsigned char buf[256]; +- int i, rec_no=0; +- if(prkey_info.path.len>=2) prkey_info.path.len-=2; ++ int i, rec_no = 0; ++ if (prkey_info.path.len >= 2) ++ prkey_info.path.len -= 2; + sc_append_file_id(&prkey_info.path, 0x5349); +- if(sc_select_file(card, &prkey_info.path, NULL)!=SC_SUCCESS){ ++ if (sc_select_file(card, &prkey_info.path, NULL) != SC_SUCCESS) { + sc_log(ctx, + "Select(%s) failed\n", + sc_print_path(&prkey_info.path)); +@@ -135,24 +137,29 @@ static int insert_key( + } + sc_log(ctx, + "Searching for Key-Ref %02X\n", key_reference); +- while((r=sc_read_record(card, ++rec_no, buf, sizeof(buf), SC_RECORD_BY_REC_NR))>0){ +- int found=0; +- if(buf[0]!=0xA0) continue; +- for(i=2;i 0) { ++ int found = 0; ++ if (buf[0] != 0xA0) ++ continue; ++ for (i = 2; i < buf[1] + 2; i += 2 + buf[i + 1]) { ++ if (buf[i] == 0x83 && buf[i + 1] == 1 && buf[i + 2] == key_reference) ++ ++found; + } +- if(found) break; ++ if (found) ++ break; + } +- if(r<=0){ ++ if (r <= 0) { + sc_log(ctx, "No EF_KEYD-Record found\n"); + return 1; + } +- for(i=0;iprop_attr || f->prop_attr_len < 2){ + sc_log(ctx, + "Select(%s) failed\n", +@@ -160,15 +167,19 @@ static int insert_key( + return 1; + } +- if (f->prop_attr[1] & 0x04) can_crypt=1; +- if (f->prop_attr[1] & 0x08) can_sign=1; ++ if (f->prop_attr[1] & 0x04) ++ can_crypt = 1; ++ if (f->prop_attr[1] & 0x08) ++ can_sign = 1; + sc_file_free(f); + } +- prkey_info.usage= SC_PKCS15_PRKEY_USAGE_SIGN; +- if(can_crypt) prkey_info.usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT|SC_PKCS15_PRKEY_USAGE_DECRYPT; +- if(can_sign) prkey_info.usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; +- +- r=sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info); +- if(r!=SC_SUCCESS){ ++ prkey_info.usage = SC_PKCS15_PRKEY_USAGE_SIGN; ++ if (can_crypt) ++ prkey_info.usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_DECRYPT; ++ if (can_sign) ++ prkey_info.usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; ++ ++ r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info); ++ if(r != SC_SUCCESS) { + sc_log(ctx, "sc_pkcs15emu_add_rsa_prkey(%s) failed\n", path); + return 4; + } diff --git a/opensc.spec b/opensc.spec index 73ff3eb0de1bf8838c060fbddd59f6d720384878..957e03202437eb03a394ce4428dc1a789e666196 100644 --- a/opensc.spec +++ b/opensc.spec @@ -3,7 +3,7 @@ Name: opensc Version: 0.20.0 -Release: 9 +Release: 10 License: LGPLv2.1+ Summary: Smart card library and applications URL: https://github.com/OpenSC/OpenSC/wiki @@ -22,11 +22,17 @@ Patch9: oberthur-Fix-memory-leaks.patch Patch10: oberthur-Avoid-memory-leaks.patch Patch11: oberthur-fixed-Heap-buffer-overflow.patch Patch12: oberthur-One-more-overlooked-buffer-overflow.patch -Patch13: cardos-Correctly-calculate-the-left-bytes-to-avoid-b.patch -Patch14: oberthur-Handle-1B-OIDs.patch -Patch15: Fix-ACLs-support.patch -Patch16: backport-tcos-Reformat-insert_pin-for-readability.patch -Patch17: backport-CVE-2021-42780-tcos-Check-bounds-in-insert_pin.patch +Patch13: oberthur-Handle-1B-OIDs.patch +Patch14: Fix-ACLs-support.patch +Patch15: backport-tcos-Reformat-insert_pin-for-readability.patch +Patch16: backport-CVE-2021-42780-tcos-Check-bounds-in-insert_pin.patch +Patch17: backport-simplify-PIV-IO.patch +Patch18: backport-tcos-Reformat-insert_key.patch +Patch19: backport-0001-CVE-2021-42782-tcos-prevent-out-of-bounds-read.patch +Patch20: backport-0002-CVE-2021-42782-coolkey-Initialize-potentially.patch +Patch21: backport-0003-CVE-2021-42782-cardos-Correctly-calculate-the-left.patch +Patch22: backport-0004-CVE-2021-42782-iasecc-Prevent-stack-buffer.patch +Patch23: backport-0005-CVE-2021-42782-PIV-Improved-parsing.patch BuildRequires: openssl-devel pcsc-lite-devel bash-completion docbook-style-xsl readline-devel BuildRequires: desktop-file-utils /usr/bin/xsltproc autoconf automake libtool gcc @@ -150,6 +156,9 @@ make check %{_sysconfdir}/xdg/autostart/pkcs11-register.desktop %changelog +* Mon May 9 2022 Hugel - 0.20.0-10 +- fix CVE-2021-42782 + * Mon May 9 2022 Hugel - 0.20.0-9 - fix CVE-2021-42780