diff --git a/0003-opensc-CVE-2023-40660-1of2.patch b/0003-opensc-CVE-2023-40660-1of2.patch new file mode 100644 index 0000000000000000000000000000000000000000..b7a77d5d29ac3e03793984305963ead00ab6c6dc --- /dev/null +++ b/0003-opensc-CVE-2023-40660-1of2.patch @@ -0,0 +1,50 @@ +From 74ddc3636db18ae78de62922a74bfdefae015c76 Mon Sep 17 00:00:00 2001 +From: Frank Morgner +Date: Wed, 21 Jun 2023 12:27:23 +0200 +Subject: [PATCH] Fixed PIN authentication bypass + +If two processes are accessing a token, then one process may leave the +card usable with an authenticated PIN so that a key may sign/decrypt any +data. This is especially the case if the token does not support a way of +resetting the authentication status (logout). + +We have some tracking of the authentication status in software via +PKCS#11, Minidriver (os-wise) and CryptoTokenKit, which is why a +PIN-prompt will appear even though the card may technically be unlocked +as described in the above example. However, before this change, an empty +PIN was not verified (likely yielding an error during PIN-verification), +but it was just checked whether the PIN is authenticated. This defeats +the purpose of the PIN verification, because an empty PIN is not the +correct one. Especially during OS Logon, we don't want that kind of +shortcut, but we want the user to verify the correct PIN (even though +the token was left unattended and authentication at the computer). + +This essentially reverts commit e6f7373ef066cfab6e3162e8b5f692683db23864. +--- + src/libopensc/pkcs15-pin.c | 13 ------------- + 1 file changed, 13 deletions(-) + +diff --git a/src/libopensc/pkcs15-pin.c b/src/libopensc/pkcs15-pin.c +index 48e16fdc1c..2402675316 100644 +--- a/src/libopensc/pkcs15-pin.c ++++ b/src/libopensc/pkcs15-pin.c +@@ -307,19 +307,6 @@ sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *pi + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_PIN_REFERENCE); + auth_info = (struct sc_pkcs15_auth_info *)pin_obj->data; + +- /* +- * if pin cache is disabled, we can get here with no PIN data. +- * in this case, to avoid error or unnecessary pin prompting on pinpad, +- * check if the PIN has been already verified and the access condition +- * is still open on card. +- */ +- if (pinlen == 0) { +- r = sc_pkcs15_get_pin_info(p15card, pin_obj); +- +- if (r == SC_SUCCESS && auth_info->logged_in == SC_PIN_STATE_LOGGED_IN) +- LOG_FUNC_RETURN(ctx, r); +- } +- + r = _validate_pin(p15card, auth_info, pinlen); + + if (r) diff --git a/0004-opensc-CVE-2023-40660-2of2.patch b/0004-opensc-CVE-2023-40660-2of2.patch new file mode 100644 index 0000000000000000000000000000000000000000..c9a4ca7a21c22a25038d73a833c02943874e67a1 --- /dev/null +++ b/0004-opensc-CVE-2023-40660-2of2.patch @@ -0,0 +1,490 @@ +From d7fadae950f6d33b32f979759c06ab78a3475c22 Mon Sep 17 00:00:00 2001 +From: Frank Morgner +Date: Wed, 21 Jun 2023 13:49:40 +0200 +Subject: [PATCH 01/15] PIV: implemented logout + +--- + src/libopensc/card-asepcos.c | 15 +++++++++++++ + src/libopensc/card-authentic.c | 11 ++++++++++ + src/libopensc/card-cac.c | 10 ++++++--- + src/libopensc/card-cac1.c | 10 ++++++--- + src/libopensc/card-coolkey.c | 3 -- + src/libopensc/card-edo.c | 7 ++++++ + src/libopensc/card-epass2003.c | 18 ++++++++++++++++ + src/libopensc/card-esteid2018.c | 5 ++++ + src/libopensc/card-gemsafeV1.c | 8 +++++++ + src/libopensc/card-isoApplet.c | 8 +++++++ + src/libopensc/card-jpki.c | 6 +++++ + src/libopensc/card-mcrd.c | 10 +++++++++ + src/libopensc/card-muscle.c | 18 ++++++++++++---- + src/libopensc/card-piv.c | 20 ++++++++++-------- + src/libopensc/card-westcos.c | 44 ++++++++++++++++++++++++---------------- + 16 files changed, 155 insertions(+), 49 deletions(-) + +--- a/src/libopensc/card-asepcos.c ++++ b/src/libopensc/card-asepcos.c +@@ -1050,6 +1050,20 @@ static int asepcos_card_reader_lock_obta + LOG_FUNC_RETURN(card->ctx, r); + } + ++static int asepcos_logout(sc_card_t *card) ++{ ++ int r = SC_ERROR_NOT_SUPPORTED; ++ ++ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); ++ ++ if (card->type == SC_CARD_TYPE_ASEPCOS_JAVA) { ++ /* in case of a Java card try to select the ASEPCOS applet */ ++ r = asepcos_select_asepcos_applet(card); ++ } ++ ++ LOG_FUNC_RETURN(card->ctx, r); ++} ++ + static struct sc_card_driver * sc_get_driver(void) + { + if (iso_ops == NULL) +@@ -1066,6 +1080,7 @@ static struct sc_card_driver * sc_get_dr + asepcos_ops.list_files = asepcos_list_files; + asepcos_ops.card_ctl = asepcos_card_ctl; + asepcos_ops.pin_cmd = asepcos_pin_cmd; ++ asepcos_ops.logout = asepcos_logout; + asepcos_ops.card_reader_lock_obtained = asepcos_card_reader_lock_obtained; + + return &asepcos_drv; +--- a/src/libopensc/card-authentic.c ++++ b/src/libopensc/card-authentic.c +@@ -2311,6 +2311,17 @@ authentic_sm_get_wrapped_apdu(struct sc_ + } + #endif + ++int authentic_logout(sc_card_t *card) ++{ ++ int r = SC_ERROR_NOT_SUPPORTED; ++ ++ if (card->type == SC_CARD_TYPE_OBERTHUR_AUTHENTIC_3_2) { ++ r = authentic_select_aid(card, aid_AuthentIC_3_2, sizeof(aid_AuthentIC_3_2), NULL, NULL); ++ } ++ ++ return r; ++} ++ + static struct sc_card_driver * + sc_get_driver(void) + { +--- a/src/libopensc/card-cac.c ++++ b/src/libopensc/card-cac.c +@@ -1831,9 +1831,6 @@ static int cac_match_card(sc_card_t *car + { + int r; + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); +- /* Since we send an APDU, the card's logout function may be called... +- * however it may be in dirty memory */ +- card->ops->logout = NULL; + + r = cac_find_and_initialize(card, 0); + return (r == SC_SUCCESS); /* never match */ +@@ -1862,6 +1859,12 @@ static int cac_init(sc_card_t *card) + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); + } + ++static int cac_logout(sc_card_t *card) ++{ ++ int index; ++ return cac_find_first_pki_applet(card, &index); ++} ++ + static int cac_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left) + { + /* CAC, like PIV needs Extra validation of (new) PIN during +@@ -1933,6 +1936,7 @@ static struct sc_card_driver * sc_get_dr + cac_ops.decipher = cac_decipher; + cac_ops.card_ctl = cac_card_ctl; + cac_ops.pin_cmd = cac_pin_cmd; ++ cac_ops.logout = cac_logout; + + return &cac_drv; + } +--- a/src/libopensc/card-cac1.c ++++ b/src/libopensc/card-cac1.c +@@ -498,9 +498,6 @@ static int cac_match_card(sc_card_t *car + { + int r; + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); +- /* Since we send an APDU, the card's logout function may be called... +- * however it may be in dirty memory */ +- card->ops->logout = NULL; + + r = cac_find_and_initialize(card, 0); + return (r == SC_SUCCESS); /* never match */ +@@ -529,6 +526,12 @@ static int cac_init(sc_card_t *card) + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); + } + ++static int cac_logout(sc_card_t *card) ++{ ++ int index; ++ return cac_find_first_pki_applet(card, &index); ++} ++ + static struct sc_card_operations cac_ops; + + static struct sc_card_driver cac1_drv = { +@@ -550,6 +553,7 @@ static struct sc_card_driver * sc_get_dr + + cac_ops.select_file = cac_select_file; /* need to record object type */ + cac_ops.read_binary = cac_read_binary; ++ cac_ops.logout = cac_logout; + + return &cac1_drv; + } +--- a/src/libopensc/card-coolkey.c ++++ b/src/libopensc/card-coolkey.c +@@ -2264,9 +2264,6 @@ static int coolkey_match_card(sc_card_t + int r; + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); +- /* Since we send an APDU, the card's logout function may be called... +- * however it may be in dirty memory */ +- card->ops->logout = NULL; + + r = coolkey_select_applet(card); + if (r == SC_SUCCESS) { +--- a/src/libopensc/card-edo.c ++++ b/src/libopensc/card-edo.c +@@ -302,6 +302,12 @@ static int edo_init(sc_card_t* card) { + } + + ++static int edo_logout(sc_card_t* card) { ++ sc_sm_stop(card); ++ return edo_unlock(card); ++} ++ ++ + struct sc_card_driver* sc_get_edo_driver(void) { + edo_ops = *sc_get_iso7816_driver()->ops; + edo_ops.match_card = edo_match_card; +@@ -309,6 +315,7 @@ struct sc_card_driver* sc_get_edo_driver + edo_ops.select_file = edo_select_file; + edo_ops.set_security_env = edo_set_security_env; + edo_ops.compute_signature = edo_compute_signature; ++ edo_ops.logout = edo_logout; + + return &edo_drv; + } +--- a/src/libopensc/card-epass2003.c ++++ b/src/libopensc/card-epass2003.c +@@ -3278,6 +3278,23 @@ epass2003_pin_cmd(struct sc_card *card, + return r; + } + ++static int ++epass2003_logout(struct sc_card *card) ++{ ++ epass2003_exdata *exdata = NULL; ++ ++ if (!card->drv_data) ++ return SC_ERROR_INVALID_ARGUMENTS; ++ ++ exdata = (epass2003_exdata *)card->drv_data; ++ if (exdata->sm) { ++ sc_sm_stop(card); ++ return epass2003_refresh(card); ++ } ++ ++ return SC_ERROR_NOT_SUPPORTED; ++} ++ + static struct sc_card_driver *sc_get_driver(void) + { + struct sc_card_driver *iso_drv = sc_get_iso7816_driver(); +@@ -3307,6 +3324,7 @@ static struct sc_card_driver *sc_get_dri + epass2003_ops.pin_cmd = epass2003_pin_cmd; + epass2003_ops.check_sw = epass2003_check_sw; + epass2003_ops.get_challenge = epass2003_get_challenge; ++ epass2003_ops.logout = epass2003_logout; + return &epass2003_drv; + } + +--- a/src/libopensc/card-esteid2018.c ++++ b/src/libopensc/card-esteid2018.c +@@ -306,6 +306,10 @@ static int esteid_finish(sc_card_t *card + return 0; + } + ++static int esteid_logout(sc_card_t *card) { ++ return gp_select_aid(card, &IASECC_AID); ++} ++ + struct sc_card_driver *sc_get_esteid2018_driver(void) { + struct sc_card_driver *iso_drv = sc_get_iso7816_driver(); + +@@ -323,6 +327,7 @@ struct sc_card_driver *sc_get_esteid2018 + esteid_ops.set_security_env = esteid_set_security_env; + esteid_ops.compute_signature = esteid_compute_signature; + esteid_ops.pin_cmd = esteid_pin_cmd; ++ esteid_ops.logout = esteid_logout; + + return &esteid2018_driver; + } +--- a/src/libopensc/card-gemsafeV1.c ++++ b/src/libopensc/card-gemsafeV1.c +@@ -582,6 +582,13 @@ static int gemsafe_card_reader_lock_obta + LOG_FUNC_RETURN(card->ctx, r); + } + ++static int gemsafe_logout(sc_card_t *card) ++{ ++ gemsafe_exdata *exdata = (gemsafe_exdata *)card->drv_data; ++ ++ return gp_select_applet(card, exdata->aid, exdata->aid_len); ++} ++ + static struct sc_card_driver *sc_get_driver(void) + { + struct sc_card_driver *iso_drv = sc_get_iso7816_driver(); +@@ -602,6 +609,7 @@ static struct sc_card_driver *sc_get_dri + gemsafe_ops.process_fci = gemsafe_process_fci; + gemsafe_ops.pin_cmd = iso_ops->pin_cmd; + gemsafe_ops.card_reader_lock_obtained = gemsafe_card_reader_lock_obtained; ++ gemsafe_ops.logout = gemsafe_logout; + + return &gemsafe_drv; + } +--- a/src/libopensc/card-isoApplet.c ++++ b/src/libopensc/card-isoApplet.c +@@ -1244,6 +1244,13 @@ static int isoApplet_card_reader_lock_ob + LOG_FUNC_RETURN(card->ctx, r); + } + ++static int isoApplet_logout(sc_card_t *card) ++{ ++ size_t rlen = SC_MAX_APDU_BUFFER_SIZE; ++ u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; ++ return isoApplet_select_applet(card, isoApplet_aid, sizeof(isoApplet_aid), rbuf, &rlen); ++} ++ + static struct sc_card_driver *sc_get_driver(void) + { + sc_card_driver_t *iso_drv = sc_get_iso7816_driver(); +@@ -1267,6 +1274,7 @@ static struct sc_card_driver *sc_get_dri + isoApplet_ops.compute_signature = isoApplet_compute_signature; + isoApplet_ops.get_challenge = isoApplet_get_challenge; + isoApplet_ops.card_reader_lock_obtained = isoApplet_card_reader_lock_obtained; ++ isoApplet_ops.logout = isoApplet_logout; + + /* unsupported functions */ + isoApplet_ops.write_binary = NULL; +--- a/src/libopensc/card-jpki.c ++++ b/src/libopensc/card-jpki.c +@@ -361,6 +361,11 @@ static int jpki_card_reader_lock_obtaine + LOG_FUNC_RETURN(card->ctx, r); + } + ++static int jpki_logout(sc_card_t *card) ++{ ++ return jpki_select_ap(card); ++} ++ + static struct sc_card_driver * + sc_get_driver(void) + { +@@ -375,6 +380,7 @@ sc_get_driver(void) + jpki_ops.set_security_env = jpki_set_security_env; + jpki_ops.compute_signature = jpki_compute_signature; + jpki_ops.card_reader_lock_obtained = jpki_card_reader_lock_obtained; ++ jpki_ops.logout = jpki_logout; + + return &jpki_drv; + } +--- a/src/libopensc/card-mcrd.c ++++ b/src/libopensc/card-mcrd.c +@@ -1174,6 +1174,15 @@ static int mcrd_pin_cmd(sc_card_t * card + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, iso_ops->pin_cmd(card, data, tries_left)); + } + ++static int mcrd_logout(sc_card_t * card) ++{ ++ if (card->type == SC_CARD_TYPE_MCRD_ESTEID_V30) { ++ return gp_select_aid(card, &EstEID_v35_AID); ++ } else { ++ return SC_ERROR_NOT_SUPPORTED; ++ } ++} ++ + /* Driver binding */ + static struct sc_card_driver *sc_get_driver(void) + { +@@ -1190,6 +1199,7 @@ static struct sc_card_driver *sc_get_dri + mcrd_ops.compute_signature = mcrd_compute_signature; + mcrd_ops.decipher = mcrd_decipher; + mcrd_ops.pin_cmd = mcrd_pin_cmd; ++ mcrd_ops.logout = mcrd_logout; + + return &mcrd_drv; + } +--- a/src/libopensc/card-muscle.c ++++ b/src/libopensc/card-muscle.c +@@ -81,10 +81,6 @@ static int muscle_match_card(sc_card_t * + u8 response[64]; + int r; + +- /* Since we send an APDU, the card's logout function may be called... +- * however it's not always properly nulled out... */ +- card->ops->logout = NULL; +- + if (msc_select_applet(card, muscleAppletId, sizeof muscleAppletId) == 1) { + /* Muscle applet is present, check the protocol version to be sure */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x3C, 0x00, 0x00); +@@ -853,6 +849,19 @@ static int muscle_card_reader_lock_obtai + LOG_FUNC_RETURN(card->ctx, r); + } + ++static int muscle_logout(sc_card_t *card) ++{ ++ int r = SC_ERROR_NOT_SUPPORTED; ++ ++ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); ++ ++ if (msc_select_applet(card, muscleAppletId, sizeof muscleAppletId) == 1) { ++ r = SC_SUCCESS; ++ } ++ ++ LOG_FUNC_RETURN(card->ctx, r); ++} ++ + + static struct sc_card_driver * sc_get_driver(void) + { +@@ -881,6 +890,7 @@ static struct sc_card_driver * sc_get_dr + muscle_ops.delete_file = muscle_delete_file; + muscle_ops.list_files = muscle_list_files; + muscle_ops.card_reader_lock_obtained = muscle_card_reader_lock_obtained; ++ muscle_ops.logout = muscle_logout; + + return &muscle_drv; + } +--- a/src/libopensc/card-piv.c ++++ b/src/libopensc/card-piv.c +@@ -2183,11 +2183,11 @@ static int piv_is_object_present(sc_card + * or the global pin for the card 0x00. Look at Discovery object to get this. + * called by pkcs15-piv.c via cardctl when setting up the pins. + */ +-static int piv_get_pin_preference(sc_card_t *card, int *ptr) ++static int piv_get_pin_preference(sc_card_t *card, int *pin_ref) + { + piv_private_data_t * priv = PIV_DATA(card); + +- *ptr = priv->pin_preference; ++ *pin_ref = priv->pin_preference; + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); + } + +@@ -3082,10 +3082,6 @@ static int piv_match_card_continued(sc_c + piv_private_data_t *priv = NULL; + int saved_type = card->type; + +- /* Since we send an APDU, the card's logout function may be called... +- * however it may be in dirty memory */ +- card->ops->logout = NULL; +- + /* piv_match_card may be called with card->type, set by opensc.conf */ + /* user provide card type must be one we know */ + switch (card->type) { +@@ -3747,12 +3743,18 @@ piv_pin_cmd(sc_card_t *card, struct sc_p + + static int piv_logout(sc_card_t *card) + { +- int r = SC_ERROR_NOT_SUPPORTED; /* TODO Some PIV cards may support a logout */ +- /* piv_private_data_t * priv = PIV_DATA(card); */ ++ int r = SC_ERROR_NOT_SUPPORTED; ++ piv_private_data_t * priv = PIV_DATA(card); + + LOG_FUNC_CALLED(card->ctx); + +- /* TODO 800-73-3 does not define a logout, 800-73-4 does */ ++ if (priv) { ++ /* logout defined since 800-73-4 */ ++ r = iso7816_logout(card, priv->pin_preference); ++ if (r == SC_SUCCESS) { ++ priv->logged_in = SC_PIN_STATE_LOGGED_OUT; ++ } ++ } + + LOG_FUNC_RETURN(card->ctx, r); + } +--- a/src/libopensc/card-westcos.c ++++ b/src/libopensc/card-westcos.c +@@ -166,6 +166,26 @@ static int westcos_finish(sc_card_t * ca + return 0; + } + ++static int select_westcos_applet(sc_card_t *card) ++{ ++ int r; ++ sc_apdu_t apdu; ++ u8 aid[] = { ++ 0xA0, 0x00, 0xCE, 0x00, 0x07, 0x01 ++ }; ++ sc_format_apdu(card, &apdu, ++ SC_APDU_CASE_3_SHORT, 0xA4, 0x04, ++ 0); ++ apdu.cla = 0x00; ++ apdu.lc = sizeof(aid); ++ apdu.datalen = sizeof(aid); ++ apdu.data = aid; ++ r = sc_transmit_apdu(card, &apdu); ++ if (r) ++ return r; ++ return sc_check_sw(card, apdu.sw1, apdu.sw2); ++} ++ + static int westcos_match_card(sc_card_t * card) + { + int i; +@@ -176,23 +196,7 @@ static int westcos_match_card(sc_card_t + + /* JAVACARD, look for westcos applet */ + if (i == 1) { +- int r; +- sc_apdu_t apdu; +- u8 aid[] = { +- 0xA0, 0x00, 0xCE, 0x00, 0x07, 0x01 +- }; +- sc_format_apdu(card, &apdu, +- SC_APDU_CASE_3_SHORT, 0xA4, 0x04, +- 0); +- apdu.cla = 0x00; +- apdu.lc = sizeof(aid); +- apdu.datalen = sizeof(aid); +- apdu.data = aid; +- r = sc_transmit_apdu(card, &apdu); +- if (r) +- return 0; +- r = sc_check_sw(card, apdu.sw1, apdu.sw2); +- if (r) ++ if (select_westcos_applet(card)) + return 0; + } + +@@ -1257,6 +1261,11 @@ static int westcos_decipher(sc_card_t *c + return westcos_sign_decipher(1, card, crgram, crgram_len, out, outlen); + } + ++static int westcos_logout(sc_card_t *card) ++{ ++ return select_westcos_applet(card); ++} ++ + struct sc_card_driver *sc_get_westcos_driver(void) + { + if (iso_ops == NULL) +@@ -1288,6 +1297,7 @@ struct sc_card_driver *sc_get_westcos_dr + westcos_ops.process_fci = westcos_process_fci; + westcos_ops.construct_fci = NULL; + westcos_ops.pin_cmd = westcos_pin_cmd; ++ westcos_ops.logout = westcos_logout; + + return &westcos_drv; + } diff --git a/opensc.spec b/opensc.spec index 158836e24425bc2a71c34c869f3c15d93c404661..670fa82bb3641f69219199aee5b0fe0b2761c217 100644 --- a/opensc.spec +++ b/opensc.spec @@ -3,7 +3,7 @@ Name: opensc Version: 0.21.0 -Release: 7 +Release: 8 License: LGPLv2.1+ Summary: Smart card library and applications URL: https://github.com/OpenSC/OpenSC/wiki @@ -38,6 +38,8 @@ 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 Patch20: backport-0006-CVE-2023-2977-correct_left_length_calculation_to_fix_buffer.patch +Patch21: 0003-opensc-CVE-2023-40660-1of2.patch +Patch22: 0004-opensc-CVE-2023-40660-2of2.patch %description OpenSC provides a set of libraries and utilities to work with smart cards. @@ -156,6 +158,9 @@ make check %{_datadir}/opensc/ %changelog +* Mon Oct 23 2023 dillon chen - 0.21.0-8 +- fix CVE-2023-40660 + * Mon Sep 18 2023 dillon chen - 0.21.0-7 - fix CVE-2023-2977