From 5b1eb43b933e66743f0792098e6394d215cc38e4 Mon Sep 17 00:00:00 2001 From: okir Date: Sun, 19 Jan 2003 17:47:07 +0000 Subject: [PATCH] - add some support for card removal in pkcs11 git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@867 c6295689-39f2-0310-b995-f0e70906c6a9 --- TODO | 1 + src/libopensc/opensc.h | 12 +++++--- src/libopensc/reader-ctapi.c | 4 +-- src/libopensc/reader-pcsc.c | 57 +++++++++++++++++++++--------------- src/pkcs11/Makefile.am | 3 +- src/pkcs11/slot.c | 36 +++++++++++++++++------ src/scam/scam.c | 2 +- src/tests/sc-test.c | 2 +- src/tools/cryptoflex-tool.c | 2 +- src/tools/pkcs11-tool.c | 43 ++++++++++++++++++--------- src/tools/util.c | 2 +- 11 files changed, 106 insertions(+), 58 deletions(-) diff --git a/TODO b/TODO index da2ca5bb..9d1d0956 100644 --- a/TODO +++ b/TODO @@ -18,5 +18,6 @@ Nitty gritty details: * pkcs15-init: when using an unblock PIN, write an AODF entry for it (alternatively: set unblockDisabled flag for those PINs that have no PUK?) * pkcs15: fix sc_pkcs15_change_reference_data; add unblock function +* pkcs11: make sure all PIN ops work through pkcs11 diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index dc6f2e88..e44d0445 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -252,6 +252,7 @@ struct sc_reader_driver { /* slot flags */ #define SC_SLOT_CARD_PRESENT 0x00000001 +#define SC_SLOT_CARD_CHANGED 0x00000002 /* slot capabilities */ #define SC_SLOT_CAP_DISPLAY 0x00000001 #define SC_SLOT_CAP_PIN_PAD 0x00000002 @@ -629,10 +630,13 @@ inline int sc_card_valid(const struct sc_card *card); /** * Checks if a card is present in a reader * @param reader Reader structure - * @param reader Slot ID - * @retval 1 if a card is present - * @retval 0 card absent - * @retval < 0 if an error occured + * @param slot_id Slot ID + * @retval If an error occured, the return value is a (negative) + * OpenSC error code. If no card is present, 0 is returned. + * Otherwise, a positive value is returned, which is a + * combination of flags. The flag SC_SLOT_CARD_PRESENT is + * always set. In addition, if the card was exchanged, + * the SC_SLOT_CARD_CHANGED flag is set. */ int sc_detect_card_presence(struct sc_reader *reader, int slot_id); diff --git a/src/libopensc/reader-ctapi.c b/src/libopensc/reader-ctapi.c index dfab266b..881c7abd 100644 --- a/src/libopensc/reader-ctapi.c +++ b/src/libopensc/reader-ctapi.c @@ -120,9 +120,7 @@ static int ctapi_detect_card_presence(struct sc_reader *reader, struct sc_slot_i r = refresh_slot_attributes(reader, slot); if (r) return r; - if (slot->flags & SC_SLOT_CARD_PRESENT) - return 1; - return 0; + return slot->flags; } static int ctapi_connect(struct sc_reader *reader, struct sc_slot_info *slot) diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index 714e9173..e93894a4 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -76,6 +76,7 @@ struct pcsc_private_data { struct pcsc_slot_data { SCARDHANDLE pcsc_card; + SCARD_READERSTATE_A readerState; }; static int pcsc_ret_to_error(long rv) @@ -203,25 +204,40 @@ static int pcsc_transmit(struct sc_reader *reader, struct sc_slot_info *slot, static int refresh_slot_attributes(struct sc_reader *reader, struct sc_slot_info *slot) { struct pcsc_private_data *priv = GET_PRIV_DATA(reader); + struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot); LONG ret; - SCARD_READERSTATE_A rgReaderStates[SC_MAX_READERS]; - rgReaderStates[0].szReader = priv->reader_name; - rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE; - rgReaderStates[0].dwEventState = SCARD_STATE_UNAWARE; - ret = SCardGetStatusChange(priv->pcsc_ctx, SC_STATUS_TIMEOUT, rgReaderStates, 1); + if (pslot->readerState.szReader == NULL) { + pslot->readerState.szReader = priv->reader_name; + pslot->readerState.dwCurrentState = SCARD_STATE_UNAWARE; + pslot->readerState.dwEventState = SCARD_STATE_UNAWARE; + } else { + pslot->readerState.dwCurrentState = pslot->readerState.dwEventState; + } + + ret = SCardGetStatusChange(priv->pcsc_ctx, SC_STATUS_TIMEOUT, &pslot->readerState, 1); if (ret != 0) { PCSC_ERROR(reader->ctx, "SCardGetStatusChange failed", ret); return pcsc_ret_to_error(ret); } - if (rgReaderStates[0].dwEventState & SCARD_STATE_PRESENT) { + if (pslot->readerState.dwEventState & SCARD_STATE_PRESENT) { + int old_flags = slot->flags; + slot->flags |= SC_SLOT_CARD_PRESENT; - slot->atr_len = rgReaderStates[0].cbAtr; + slot->atr_len = pslot->readerState.cbAtr; if (slot->atr_len > SC_MAX_ATR_SIZE) slot->atr_len = SC_MAX_ATR_SIZE; - memcpy(slot->atr, rgReaderStates[0].rgbAtr, slot->atr_len); + memcpy(slot->atr, pslot->readerState.rgbAtr, slot->atr_len); + + /* If there was a card in the slot previously, and the + * PCSC driver reports a state change, we assume the + * user removed the old card and inserted a new one in the + * meantime. */ + if ((pslot->readerState.dwEventState & SCARD_STATE_CHANGED) + && (old_flags & SC_SLOT_CARD_PRESENT)) + slot->flags |= SC_SLOT_CARD_CHANGED; } else { - slot->flags &= ~SC_SLOT_CARD_PRESENT; + slot->flags &= ~(SC_SLOT_CARD_PRESENT|SC_SLOT_CARD_CHANGED); } return 0; @@ -233,7 +249,7 @@ static int pcsc_detect_card_presence(struct sc_reader *reader, struct sc_slot_in if ((rv = refresh_slot_attributes(reader, slot)) < 0) return rv; - return (slot->flags & SC_SLOT_CARD_PRESENT)? 1 : 0; + return slot->flags; } /* Wait for an event to occur. @@ -355,16 +371,11 @@ static int pcsc_connect(struct sc_reader *reader, struct sc_slot_info *slot) struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot); int r; - if (pslot != NULL) - return SC_ERROR_SLOT_ALREADY_CONNECTED; r = refresh_slot_attributes(reader, slot); if (r) return r; if (!(slot->flags & SC_SLOT_CARD_PRESENT)) return SC_ERROR_CARD_NOT_PRESENT; - pslot = (struct pcsc_slot_data *) malloc(sizeof(struct pcsc_slot_data)); - if (pslot == NULL) - return SC_ERROR_OUT_OF_MEMORY; rv = SCardConnect(priv->pcsc_ctx, priv->reader_name, SCARD_SHARE_SHARED, SCARD_PROTOCOL_ANY, &card_handle, &active_proto); @@ -374,7 +385,6 @@ static int pcsc_connect(struct sc_reader *reader, struct sc_slot_info *slot) return pcsc_ret_to_error(rv); } slot->active_protocol = pcsc_proto_to_opensc(active_proto); - slot->drv_data = pslot; pslot->pcsc_card = card_handle; return 0; @@ -387,8 +397,8 @@ static int pcsc_disconnect(struct sc_reader *reader, struct sc_slot_info *slot, /* FIXME: check action */ SCardDisconnect(pslot->pcsc_card, SCARD_LEAVE_CARD); - free(pslot); - slot->drv_data = NULL; + memset(pslot, 0, sizeof(*pslot)); + slot->flags = 0; return 0; } @@ -476,15 +486,17 @@ static int pcsc_init(struct sc_context *ctx, void **reader_data) do { struct sc_reader *reader = (struct sc_reader *) malloc(sizeof(struct sc_reader)); struct pcsc_private_data *priv = (struct pcsc_private_data *) malloc(sizeof(struct pcsc_private_data)); + struct pcsc_slot_data *pslot = (struct pcsc_slot_data *) malloc(sizeof(struct pcsc_slot_data)); struct sc_slot_info *slot; - if (reader == NULL || priv == NULL) { + if (reader == NULL || priv == NULL || pslot == NULL) { if (reader) free(reader); if (priv) free(priv); break; } + memset(reader, 0, sizeof(*reader)); reader->drv_data = priv; reader->ops = &pcsc_ops; @@ -503,11 +515,10 @@ static int pcsc_init(struct sc_context *ctx, void **reader_data) break; } slot = &reader->slot[0]; - slot->id = 0; + memset(slot, 0, sizeof(*slot)); + slot->drv_data = pslot; + memset(pslot, 0, sizeof(*pslot)); refresh_slot_attributes(reader, slot); - slot->capabilities = 0; - slot->atr_len = 0; - slot->drv_data = NULL; while (*p++ != 0); } while (p < (reader_buf + reader_buf_size - 1)); diff --git a/src/pkcs11/Makefile.am b/src/pkcs11/Makefile.am index 1dfeca8f..a75044e4 100644 --- a/src/pkcs11/Makefile.am +++ b/src/pkcs11/Makefile.am @@ -8,7 +8,8 @@ SUBDIRS = . rsaref INCLUDES = @CFLAGS_OPENSC@ -I../pkcs15init -LDFLAGS = @LDFLAGS@ @LIBDL@ @LIBOPENSC@ ../pkcs15init/libpkcs15init.la +LDFLAGS = @LDFLAGS@ @LIBDL@ @LIBOPENSC@ ../pkcs15init/libpkcs15init.la \ + ../scrandom/libscrandom.la SRC = pkcs11-global.c pkcs11-session.c pkcs11-object.c misc.c slot.c \ mechanism.c openssl.c \ diff --git a/src/pkcs11/slot.c b/src/pkcs11/slot.c index c8c543f0..5ae7ab03 100644 --- a/src/pkcs11/slot.c +++ b/src/pkcs11/slot.c @@ -52,21 +52,39 @@ CK_RV card_initialize(int reader) CK_RV card_detect(int reader) { struct sc_pkcs11_card *card; - int rc, rv, i; + int rc, rv, i, retry = 1; rv = CKR_OK; debug(context, "%d: Detecting SmartCard\n", reader); - /* Already known to be present? */ - if (card_table[reader].card == NULL) { - /* Check if someone inserted a card */ - if (sc_detect_card_presence(context->reader[reader], 0) != 1) { - debug(context, "%d: Card absent\n", reader); - return CKR_TOKEN_NOT_PRESENT; - } + /* Check if someone inserted a card */ +again: rc = sc_detect_card_presence(context->reader[reader], 0); + if (rc < 0) { + debug(context, "Card detection failed for reader %d: %s\n", + reader, sc_strerror(rc)); + return sc_to_cryptoki_error(rc, reader); + } + if (rc == 0) { + debug(context, "%d: Card absent\n", reader); + card_removed(reader); /* Release all resources */ + return CKR_TOKEN_NOT_PRESENT; + } - /* Detect the card */ + /* If the card was changed, disconnect the current one */ + if (rc & SC_SLOT_CARD_CHANGED) { + debug(context, "%d: Card changed\n", reader); + /* The following should never happen - but if it + * does we'll be stuck in an endless loop. + * So better be fussy. */ + if (!retry--) + return CKR_TOKEN_NOT_PRESENT; + card_removed(reader); + goto again; + } + + /* Detect the card if it's not known already */ + if (card_table[reader].card == NULL) { debug(context, "%d: Connecting to SmartCard\n", reader); rc = sc_connect_card(context->reader[reader], 0, &card_table[reader].card); if (rc != SC_SUCCESS) diff --git a/src/scam/scam.c b/src/scam/scam.c index 5080ad17..f4098222 100644 --- a/src/scam/scam.c +++ b/src/scam/scam.c @@ -96,7 +96,7 @@ const char *scam_get_atr(unsigned int readernum) sc_release_context(ctx); return NULL; } - if (sc_detect_card_presence(ctx->reader[readernum], 0) != 1) { + if (sc_detect_card_presence(ctx->reader[readernum], 0) <= 0) { sc_release_context(ctx); return NULL; } diff --git a/src/tests/sc-test.c b/src/tests/sc-test.c index a35c1825..3cdeda5f 100644 --- a/src/tests/sc-test.c +++ b/src/tests/sc-test.c @@ -94,7 +94,7 @@ int sc_test_init(int *argc, char *argv[]) opt_reader = i - 1; } - if (rc == 1) { + if (rc > 0) { printf("Card detected in reader '%s'\n", ctx->reader[opt_reader]->name); break; diff --git a/src/tools/cryptoflex-tool.c b/src/tools/cryptoflex-tool.c index a04a7249..6e54e86e 100644 --- a/src/tools/cryptoflex-tool.c +++ b/src/tools/cryptoflex-tool.c @@ -1156,7 +1156,7 @@ int main(int argc, char * const argv[]) err = 1; goto end; } - if (sc_detect_card_presence(ctx->reader[opt_reader], 0) != 1) { + if (sc_detect_card_presence(ctx->reader[opt_reader], 0) <= 0) { fprintf(stderr, "Card not present.\n"); err = 3; goto end; diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c index afee2197..b39895f2 100644 --- a/src/tools/pkcs11-tool.c +++ b/src/tools/pkcs11-tool.c @@ -892,11 +892,7 @@ test_digest(CK_SLOT_ID slot) data[10 * i + j] = (unsigned char) (0x30 + j); - i = 0xffffff; - while (1) { - if (mechTypes[++i] == 0xffffff) - break; - + for (i = 0; mechTypes[i] != 0xffffff; i++) { ck_mech.mechanism = mechTypes[i]; rv = p11->C_DigestInit(session, &ck_mech); @@ -1298,23 +1294,42 @@ test_random(CK_SESSION_HANDLE session) return 0; } +static int +test_card_detection(void) +{ + char buffer[256]; + + while (1) { + printf("Please press return or x to exit: "); + fflush(stdout); + if (fgets(buffer, sizeof(buffer), stdin) == NULL + || buffer[0] == 'x') + break; + list_slots(); + } + + return 0; +} + static int p11_test(CK_SLOT_ID slot, CK_SESSION_HANDLE session) { - int errors = 0; + int errors = 0; - errors += test_random(session); + errors += test_random(session); - errors += test_digest(slot); + errors += test_digest(slot); - errors += test_signature(slot, session); + errors += test_signature(slot, session); - if (errors == 0) - printf("No errors\n"); - else - printf("%d errors\n", errors); + errors += test_card_detection(); - return errors; + if (errors == 0) + printf("No errors\n"); + else + printf("%d errors\n", errors); + + return errors; } const char * diff --git a/src/tools/util.c b/src/tools/util.c index dc55838b..08ff5f14 100644 --- a/src/tools/util.c +++ b/src/tools/util.c @@ -60,7 +60,7 @@ int connect_card(struct sc_context *ctx, struct sc_card **cardp, reader = ctx->reader[reader_id]; slot_id = 0; - if (sc_detect_card_presence(reader, 0) != 1) { + if (sc_detect_card_presence(reader, 0) <= 0) { fprintf(stderr, "Card not present.\n"); return 3; }