From 2b99f2df144e240cb8a4369e25c50dd11809198c Mon Sep 17 00:00:00 2001 From: jey Date: Tue, 25 Dec 2001 20:45:48 +0000 Subject: [PATCH] - added default driver for unidentified cards - added select_file operation in Multiflex driver - added 'list-drivers' command to opensc-tool - moved stuff from opensc.h to sc-internal.h - improved locking behaviour git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@106 c6295689-39f2-0310-b995-f0e70906c6a9 --- src/libopensc/Makefile.am | 6 +- src/libopensc/asn1.c | 2 +- src/libopensc/base64.c | 2 +- src/libopensc/card-default.c | 115 +++++++++++++++++++++++++++++++ src/libopensc/card-multiflex.c | 117 ++++++++++++++++++++++++++++++- src/libopensc/card-setcos.c | 2 +- src/libopensc/card.c | 121 ++++++++++++++++++++++++++------- src/libopensc/defaults.c | 2 +- src/libopensc/iso7816.c | 4 +- src/libopensc/opensc.h | 48 +++++-------- src/libopensc/pkcs15-cert.c | 23 +++++-- src/libopensc/pkcs15-pin.c | 26 +++++-- src/libopensc/pkcs15-prkey.c | 10 ++- src/libopensc/pkcs15-sec.c | 10 +-- src/libopensc/pkcs15.c | 29 ++++++-- src/libopensc/sc.c | 27 ++++++-- src/libopensc/sec.c | 15 ++-- src/pam/Makefile.am | 8 +-- src/pkcs11/Makefile.am | 2 +- src/tools/opensc-crypt.c | 12 +++- src/tools/opensc-tool.c | 88 +++++++++++++++++++++--- 21 files changed, 554 insertions(+), 115 deletions(-) create mode 100644 src/libopensc/card-default.c diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am index d629907f..5fd51ed1 100644 --- a/src/libopensc/Makefile.am +++ b/src/libopensc/Makefile.am @@ -6,10 +6,12 @@ libopensc_la_SOURCES = sc-asn1.c sc-base64.c sc-defaults.c \ sc-pkcs15.c sc-pkcs15-cert.c \ sc-pkcs15-pin.c sc-pkcs15-prkey.c \ sc-pkcs15-defaults.c sc-pkcs15-sec.c \ - sc-card-setec.c sc-card-multiflex.c + sc-card-setec.c sc-card-multiflex.c \ + sc-card-default.c libopensc_la_LDFLAGS = -version-info 0:4:0 libopensc_la_LIBADD = @LIBPCSCLITE@ libopensc_la_CFLAGS = $(AM_CFLAGS) -Werror include_HEADERS = opensc.h opensc-pkcs15.h -noinst_HEADERS = sc-asn1.h sc-log.h +noinst_HEADERS = sc-asn1.h sc-log.h sc-internal.h + diff --git a/src/libopensc/asn1.c b/src/libopensc/asn1.c index a66abf6c..3851f51d 100644 --- a/src/libopensc/asn1.c +++ b/src/libopensc/asn1.c @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "opensc.h" +#include "sc-internal.h" #include "sc-asn1.h" #include "sc-log.h" #include diff --git a/src/libopensc/base64.c b/src/libopensc/base64.c index 2f52b1bc..585ede08 100644 --- a/src/libopensc/base64.c +++ b/src/libopensc/base64.c @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "opensc.h" +#include "sc-internal.h" #include #include #include diff --git a/src/libopensc/card-default.c b/src/libopensc/card-default.c new file mode 100644 index 00000000..3e30b23e --- /dev/null +++ b/src/libopensc/card-default.c @@ -0,0 +1,115 @@ +/* + * sc-card-unknown.c: Support for cards with no driver + * + * Copyright (C) 2001 Juha Yrjölä + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "sc-internal.h" +#include "sc-log.h" + +static struct sc_card_operations default_ops; +static const struct sc_card_driver default_drv = { + NULL, + "Default driver for unknown cards", + &default_ops +}; + +static int default_finish(struct sc_card *card) +{ + return 0; +} + +static int default_match_card(struct sc_card *card) +{ + return 1; /* always match */ +} + +static int autodetect_class(struct sc_card *card) +{ + int classes[] = { 0x00, 0xC0, 0xB0, 0xA0 }; + int class_count = sizeof(classes)/sizeof(int); + u8 buf[2]; + struct sc_apdu apdu; + int i, r; + + if (card->ctx->debug >= 2) + debug(card->ctx, "autodetecting CLA byte\n"); + for (i = 0; i < class_count; i++) { + if (card->ctx->debug >= 2) + debug(card->ctx, "trying with 0x%02X\n", classes[i]); + apdu.cla = classes[i]; + apdu.cse = SC_APDU_CASE_3_SHORT; + apdu.no_response = 1; + memcpy(buf, "\x3F\x00", 2); + apdu.data = buf; + apdu.datalen = 2; + apdu.lc = 2; + apdu.resplen = 0; + apdu.ins = 0xA4; + apdu.p1 = apdu.p2 = 0; + r = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, r, "APDU transmit failed"); + if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) + break; + if (apdu.sw1 == 0x61) + break; + if (apdu.sw1 == 0x6E) + continue; + if (card->ctx->debug >= 2) + debug(card->ctx, "got strange SWs: 0x%02X 0x%02X\n", + apdu.sw1, apdu.sw2); + } + if (i == class_count) + return -1; + card->cla = classes[i]; + if (card->ctx->debug >= 2) + debug(card->ctx, "detected CLA byte as 0x%02X\n", card->cla); + return 0; +} + +static int default_init(struct sc_card *card) +{ + int r; + + card->ops_data = NULL; + r = autodetect_class(card); + if (r) { + error(card->ctx, "unable to determine the right class byte\n"); + return SC_ERROR_INVALID_CARD; + } + + return 0; +} + +static const struct sc_card_driver * sc_get_driver(void) +{ + const struct sc_card_driver *iso_drv = sc_get_iso7816_driver(); + + default_ops = *iso_drv->ops; + default_ops.match_card = default_match_card; + default_ops.init = default_init; + default_ops.finish = default_finish; + + return &default_drv; +} + +#if 1 +const struct sc_card_driver * sc_get_default_driver(void) +{ + return sc_get_driver(); +} +#endif diff --git a/src/libopensc/card-multiflex.c b/src/libopensc/card-multiflex.c index 584309e2..ee3b0079 100644 --- a/src/libopensc/card-multiflex.c +++ b/src/libopensc/card-multiflex.c @@ -18,7 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "opensc.h" +#include "sc-internal.h" +#include "sc-log.h" static const char *mflex_atrs[] = { "3B:19:14:55:90:01:02:02:00:05:04:B0", @@ -28,7 +29,7 @@ static const char *mflex_atrs[] = { static struct sc_card_operations mflex_ops; static const struct sc_card_driver mflex_drv = { NULL, - "Schlumberger/Multiflex", + "Multiflex/Schlumberger", &mflex_ops }; @@ -69,10 +70,120 @@ static int mflex_init(struct sc_card *card) return 0; } +static int parse_flex_sf_reply(struct sc_context *ctx, const u8 *buf, int buflen, + struct sc_file *file) +{ + const u8 *p = buf + 2; + int left; + + file->size = (*p++ << 8) + *p++; + file->id = (*p++ << 8) + *p++; + switch (*p) { + case 0x01: + file->type = SC_FILE_TYPE_WORKING_EF; + file->ef_structure = SC_FILE_EF_TRANSPARENT; + break; + case 0x02: + file->type = SC_FILE_TYPE_WORKING_EF; + file->ef_structure = SC_FILE_EF_LINEAR_FIXED; + break; + case 0x04: + file->type = SC_FILE_TYPE_WORKING_EF; + file->ef_structure = SC_FILE_EF_LINEAR_VARIABLE; + break; + case 0x06: + file->type = SC_FILE_TYPE_WORKING_EF; + file->ef_structure = SC_FILE_EF_CYCLIC; + break; + case 0x38: + file->type = SC_FILE_TYPE_DF; + break; + default: + error(ctx, "invalid file type: 0x%02X\n", *p); + return SC_ERROR_UNKNOWN_REPLY; + } + p++; + p += 3; /* skip ACs */ + if (*p++) + file->status = SC_FILE_STATUS_ACTIVATED; + else + file->status = SC_FILE_STATUS_INVALIDATED; + left = *p++; + + return 0; +} + static int mflex_select_file(struct sc_card *card, const struct sc_path *path, struct sc_file *file) { - return SC_ERROR_NOT_SUPPORTED; + int r; + struct sc_apdu apdu; + u8 rbuf[MAX_BUFFER_SIZE]; + u8 *pathptr = path->value; + size_t pathlen = path->len; + + SC_FUNC_CALLED(card->ctx, 3); + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0, 0); + apdu.resp = rbuf; + apdu.resplen = sizeof(rbuf); + apdu.p1 = apdu.p2 = 0; + + switch (path->type) { + case SC_PATH_TYPE_PATH: + if ((pathlen & 1) != 0) /* not divisible by 2 */ + return SC_ERROR_INVALID_ARGUMENTS; + if (pathlen != 2 || memcmp(pathptr, "\x3F\x00", 2) != 0) { + struct sc_path tmppath; + + if (memcmp(pathptr, "\x3F\x00", 2) != 0) { + sc_format_path("I3F00", &tmppath); + r = mflex_select_file(card, &tmppath, NULL); + SC_TEST_RET(card->ctx, r, "Unable to select Master File (MF)"); + pathptr += 2; + pathlen -= 2; + } + while (pathlen > 2) { + memcpy(tmppath.value, pathptr, 2); + tmppath.len = 2; + r = mflex_select_file(card, &tmppath, NULL); + SC_TEST_RET(card->ctx, r, "Unable to select DF"); + pathptr += 2; + pathlen -= 2; + } + } + break; + case SC_PATH_TYPE_DF_NAME: + apdu.p1 = 0x04; + break; + case SC_PATH_TYPE_FILE_ID: + if ((pathlen & 1) != 0) + return SC_ERROR_INVALID_ARGUMENTS; + break; + } + apdu.datalen = pathlen; + apdu.data = pathptr; + apdu.lc = pathlen; + + /* No need to get file information, if file is NULL or already + * valid. */ + if (file == NULL || sc_file_valid(file)) + apdu.no_response = 1; + r = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, r, "APDU transmit failed"); + r = sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2); + SC_TEST_RET(card->ctx, r, "Card returned error"); + if (apdu.no_response) + return 0; + + if (apdu.resplen < 14) + return SC_ERROR_UNKNOWN_REPLY; + + if (apdu.resp[0] == 0x6F) { + error(card->ctx, "unsupported: Multiflex returned FCI\n"); + return SC_ERROR_UNKNOWN_REPLY; /* FIXME */ + } + + return parse_flex_sf_reply(card->ctx, apdu.resp, apdu.resplen, file); } static const struct sc_card_driver * sc_get_driver(void) diff --git a/src/libopensc/card-setcos.c b/src/libopensc/card-setcos.c index 68536933..1656b76b 100644 --- a/src/libopensc/card-setcos.c +++ b/src/libopensc/card-setcos.c @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "opensc.h" +#include "sc-internal.h" static const char *setec_atrs[] = { /* the current FINEID card has this ATR: */ diff --git a/src/libopensc/card.c b/src/libopensc/card.c index ba3cc9ff..07be5a85 100644 --- a/src/libopensc/card.c +++ b/src/libopensc/card.c @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "opensc.h" +#include "sc-internal.h" #include "sc-log.h" #include "sc-asn1.h" #include @@ -61,6 +61,21 @@ int sc_sw_to_errorcode(struct sc_card *card, int sw1, int sw2) return SC_ERROR_UNKNOWN_REPLY; } +static int _sc_pcscret_to_error(long rv) +{ + switch (rv) { + case SCARD_W_REMOVED_CARD: + return SC_ERROR_CARD_REMOVED; + case SCARD_W_RESET_CARD: + return SC_ERROR_CARD_RESET; + case SCARD_E_NOT_TRANSACTED: + return SC_ERROR_TRANSMIT_FAILED; + default: + return SC_ERROR_UNKNOWN; + } +} + + static int sc_check_apdu(struct sc_context *ctx, const struct sc_apdu *apdu) { switch (apdu->cse) { @@ -190,8 +205,13 @@ int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu) SC_FUNC_CALLED(card->ctx, 4); r = sc_check_apdu(card->ctx, apdu); SC_TEST_RET(card->ctx, r, "APDU sanity check failed"); + r = sc_lock(card); + SC_TEST_RET(card->ctx, r, "sc_lock() failed"); r = sc_transceive_t0(card, apdu); - SC_TEST_RET(card->ctx, r, "transceive_t0() failed"); + if (r != 0) { + sc_unlock(card); + SC_TEST_RET(card->ctx, r, "transceive_t0() failed"); + } if (card->ctx->debug >= 5) { char buf[2048]; @@ -207,9 +227,13 @@ int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu) struct sc_apdu rspapdu; BYTE rsp[SC_MAX_APDU_BUFFER_SIZE]; - if (apdu->no_response != 0) + if (apdu->no_response != 0) { + apdu->sw1 = 0x90; + apdu->sw2 = 0; + sc_unlock(card); return 0; - + } + sc_format_apdu(card, &rspapdu, SC_APDU_CASE_2_SHORT, 0xC0, 0, 0); rspapdu.le = (size_t) apdu->sw2; @@ -219,6 +243,7 @@ int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu) if (r != 0) { error(card->ctx, "error while getting response: %s\n", sc_strerror(r)); + sc_unlock(card); return r; } if (card->ctx->debug >= 5) { @@ -238,6 +263,7 @@ int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu) apdu->sw1 = rspapdu.sw1; apdu->sw2 = rspapdu.sw2; } + sc_unlock(card); return 0; } @@ -296,6 +322,7 @@ int sc_connect_card(struct sc_context *ctx, card->reader = reader; card->ctx = ctx; card->pcsc_card = card_handle; + card->lock_count = 0; i = rgReaderStates[0].cbAtr; if (i >= SC_MAX_ATR_SIZE) i = SC_MAX_ATR_SIZE; @@ -305,15 +332,27 @@ int sc_connect_card(struct sc_context *ctx, for (i = 0; ctx->card_drivers[i] != NULL; i++) { const struct sc_card_driver *drv = ctx->card_drivers[i]; const struct sc_card_operations *ops = drv->ops; + int r; + if (ctx->debug >= 3) debug(ctx, "trying driver: %s\n", drv->name); if (ops == NULL || ops->match_card == NULL) continue; - if (ops->match_card(card) == 1) { - if (ctx->debug >= 3) - debug(ctx, "matched\n"); - card->ops = ops; + if (ops->match_card(card) != 1) + continue; + if (ctx->debug >= 3) + debug(ctx, "matched: %s\n", drv->name); + card->ops = ops; + r = card->ops->init(card); + if (r) { + error(ctx, "driver '%s' init() failed: %s\n", drv->name, + sc_strerror(r)); + if (r == SC_ERROR_INVALID_CARD) + continue; + free(card); + return r; } + break; } if (card->ops == NULL) { error(ctx, "unable to find driver for inserted card\n"); @@ -321,6 +360,7 @@ int sc_connect_card(struct sc_context *ctx, return SC_ERROR_INVALID_CARD; } pthread_mutex_init(&card->mutex, NULL); + card->magic = SC_CARD_MAGIC; *card_out = card; SC_FUNC_RETURN(ctx, 1, 0); @@ -328,15 +368,25 @@ int sc_connect_card(struct sc_context *ctx, int sc_disconnect_card(struct sc_card *card) { - struct sc_context *ctx = card->ctx; - assert(card != NULL); + struct sc_context *ctx; + assert(sc_card_valid(card)); + ctx = card->ctx; SC_FUNC_CALLED(ctx, 1); + assert(card->lock_count == 0); + if (card->ops->finish) { + int r = card->ops->finish(card); + if (r) + error(card->ctx, "driver finish() failed: %s\n", + sc_strerror(r)); + } SCardDisconnect(card->pcsc_card, SCARD_LEAVE_CARD); pthread_mutex_destroy(&card->mutex); free(card); SC_FUNC_RETURN(ctx, 1, 0); } +/* internal lock function -- should make sure that the card is exclusively + * in our use */ static int _sc_lock_int(struct sc_card *card) { long rv; @@ -345,18 +395,27 @@ static int _sc_lock_int(struct sc_card *card) if (rv != SCARD_S_SUCCESS) { error(card->ctx, "SCardBeginTransaction failed: %s\n", pcsc_stringify_error(rv)); - return -1; + return _sc_pcscret_to_error(rv); } return 0; } int sc_lock(struct sc_card *card) { + int r = 0; + + assert(card != NULL); SC_FUNC_CALLED(card->ctx, 2); pthread_mutex_lock(&card->mutex); - SC_FUNC_RETURN(card->ctx, 2, _sc_lock_int(card)); + if (card->lock_count == 0) + r = _sc_lock_int(card); + if (r == 0) + card->lock_count++; + pthread_mutex_unlock(&card->mutex); + SC_FUNC_RETURN(card->ctx, 2, r); } +/* internal unlock function */ static int _sc_unlock_int(struct sc_card *card) { long rv; @@ -371,9 +430,17 @@ static int _sc_unlock_int(struct sc_card *card) int sc_unlock(struct sc_card *card) { + int r = 0; + + assert(card != NULL); SC_FUNC_CALLED(card->ctx, 2); + pthread_mutex_lock(&card->mutex); + card->lock_count--; + assert(card->lock_count >= 0); + if (card->lock_count == 0) + r = _sc_unlock_int(card); pthread_mutex_unlock(&card->mutex); - SC_FUNC_RETURN(card->ctx, 2, _sc_unlock_int(card)); + SC_FUNC_RETURN(card->ctx, 2, r); } int sc_list_files(struct sc_card *card, u8 *buf, int buflen) @@ -475,13 +542,6 @@ int sc_delete_file(struct sc_card *card, int file_id) SC_FUNC_RETURN(card->ctx, 1, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2)); } -int sc_file_valid(const struct sc_file *file) -{ - assert(file != NULL); - - return file->magic == SC_FILE_MAGIC; -} - int sc_read_binary(struct sc_card *card, unsigned int idx, unsigned char *buf, size_t count) { @@ -500,17 +560,25 @@ int sc_read_binary(struct sc_card *card, unsigned int idx, SC_FUNC_RETURN(card->ctx, 2, r); } /* no read_binary_large support... */ + r = sc_lock(card); + SC_TEST_RET(card->ctx, r, "sc_lock() failed"); while (count > 0) { int n = count > RB_BUF_SIZE ? RB_BUF_SIZE : count; r = sc_read_binary(card, idx, p, n); - SC_TEST_RET(card->ctx, r, "sc_read_binary() failed"); + if (r < 0) { + sc_unlock(card); + SC_TEST_RET(card->ctx, r, "sc_read_binary() failed"); + } p += r; idx += r; bytes_read += r; count -= r; - if (r == 0) + if (r == 0) { + sc_unlock(card); SC_FUNC_RETURN(card->ctx, 2, bytes_read); + } } + sc_unlock(card); SC_FUNC_RETURN(card->ctx, 2, bytes_read); } if (card->ops->read_binary == NULL) @@ -528,7 +596,7 @@ int sc_select_file(struct sc_card *card, assert(card != NULL && in_path != NULL); if (card->ctx->debug >= 2) { char line[128], *linep = line; - + linep += sprintf(linep, "called with type %d, path ", in_path->type); for (r = 0; r < in_path->len; r++) { sprintf(linep, "%02X", in_path->value[r]); @@ -556,3 +624,10 @@ int sc_get_challenge(struct sc_card *card, u8 *rnd, size_t len) r = card->ops->get_challenge(card, rnd, len); SC_FUNC_RETURN(card->ctx, 2, r); } + +inline int sc_card_valid(const struct sc_card *card) { +#ifndef NDEBUG + assert(card != NULL); +#endif + return card->magic == SC_CARD_MAGIC; +} diff --git a/src/libopensc/defaults.c b/src/libopensc/defaults.c index 3c2c2f05..bf2bffea 100644 --- a/src/libopensc/defaults.c +++ b/src/libopensc/defaults.c @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "opensc.h" +#include "sc-internal.h" #include "opensc-pkcs15.h" #include #include diff --git a/src/libopensc/iso7816.c b/src/libopensc/iso7816.c index 2c1cb44b..dd9ce6f2 100644 --- a/src/libopensc/iso7816.c +++ b/src/libopensc/iso7816.c @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "opensc.h" +#include "sc-internal.h" #include "sc-asn1.h" #include "sc-log.h" @@ -178,7 +178,7 @@ static int iso7816_select_file(struct sc_card *card, default: SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS); } - apdu.p2 = 0; /* record */ + apdu.p2 = 0; /* first record */ apdu.lc = pathlen; apdu.data = path; apdu.datalen = pathlen; diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index 22340d2f..a9748e46 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -23,6 +23,9 @@ #include #include +#ifndef NDEBUG +#include +#endif #include #ifdef __cplusplus @@ -70,31 +73,18 @@ extern "C" { #define SC_APDU_CASE_3_EXT 6 #define SC_APDU_CASE_4_EXT 7 -#define SC_ISO7816_4_SELECT_FILE 0xA4 -#define SC_ISO7816_4_GET_RESPONSE 0xC0 -#define SC_ISO7616_4_READ_BINARY 0xB0 -#define SC_ISO7616_4_VERIFY 0x20 -#define SC_ISO7616_4_UPDATE_BINARY 0xD6 -#define SC_ISO7616_4_ERASE_BINARY 0x0E - -#define SC_SELECT_FILE_RECORD_FIRST 0x00 -#define SC_SELECT_FILE_RECORD_LAST 0x01 -#define SC_SELECT_FILE_RECORD_NEXT 0x02 -#define SC_SELECT_FILE_RECORD_PREVIOUS 0x03 - -#define SC_SELECT_FILE_BY_FILE_ID 0x00 -#define SC_SELECT_FILE_BY_DF_NAME 0x01 -#define SC_SELECT_FILE_BY_PATH 0x02 - -#define SC_FILE_MAGIC 0x10203040 - -#define SC_FILE_TYPE_DF 0x03 +#define SC_FILE_TYPE_DF 0x02 #define SC_FILE_TYPE_INTERNAL_EF 0x01 #define SC_FILE_TYPE_WORKING_EF 0x00 #define SC_FILE_EF_TRANSPARENT 0x01 #define SC_FILE_EF_LINEAR_FIXED 0x02 #define SC_FILE_EF_LINEAR_FIXED_TLV 0x03 +#define SC_FILE_EF_LINEAR_VARIABLE 0x04 +#define SC_FILE_EF_CYCLIC 0x06 + +#define SC_FILE_STATUS_ACTIVATED 0x00 +#define SC_FILE_STATUS_INVALIDATED 0x01 #define SC_MAX_CARD_DRIVERS 16 #define SC_MAX_READERS 4 @@ -132,10 +122,10 @@ struct sc_file { int type, shareable, ef_structure; size_t size; - int id; + int id, status; u8 sec_attr[SC_MAX_SEC_ATTR_SIZE]; size_t sec_attr_len; - u8 prop_attr[SC_MAX_SEC_ATTR_SIZE]; + u8 prop_attr[SC_MAX_PROP_ATTR_SIZE]; size_t prop_attr_len; unsigned int magic; }; @@ -146,7 +136,6 @@ struct sc_file { struct sc_security_env { int algorithm_ref; struct sc_path key_file_id; - /* operation=1 ==> digital signing, signature=0 ==> decipher */ int operation; int key_ref; }; @@ -161,8 +150,11 @@ struct sc_card { size_t atr_len; pthread_mutex_t mutex; + int lock_count; const struct sc_card_operations *ops; void *ops_data; + + unsigned int magic; }; struct sc_card_operations { @@ -250,7 +242,7 @@ struct sc_context { int debug; int use_std_output, use_cache; - const struct sc_card_driver *card_drivers[SC_MAX_CARD_DRIVERS]; + const struct sc_card_driver *card_drivers[SC_MAX_CARD_DRIVERS+1]; }; struct sc_apdu { @@ -295,7 +287,6 @@ int sc_wait_for_card(struct sc_context *ctx, int reader, int timeout); int sc_lock(struct sc_card *card); int sc_unlock(struct sc_card *card); - /* ISO 7816-4 related functions */ int sc_select_file(struct sc_card *card, const struct sc_path *path, struct sc_file *file); @@ -327,17 +318,12 @@ int sc_list_files(struct sc_card *card, u8 * buf, int buflen); const char *sc_strerror(int error); -/* Internal use only */ -int sc_file_valid(const struct sc_file *file); -void sc_print_binary(FILE *f, const u8 *buf, int len); -int sc_hex_to_bin(const char *in, u8 *out, size_t *outlen); -int sc_sw_to_errorcode(struct sc_card *card, int sw1, int sw2); -void sc_format_path(const char *path_in, struct sc_path *path_out); - extern const char *sc_version; extern const struct sc_card_driver *sc_get_iso7816_driver(void); extern const struct sc_card_driver *sc_get_setec_driver(void); +extern const struct sc_card_driver *sc_get_mflex_driver(void); +extern const struct sc_card_driver *sc_get_default_driver(void); #ifdef __cplusplus } diff --git a/src/libopensc/pkcs15-cert.c b/src/libopensc/pkcs15-cert.c index 9354300e..4c2a1e10 100644 --- a/src/libopensc/pkcs15-cert.c +++ b/src/libopensc/pkcs15-cert.c @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "opensc.h" +#include "sc-internal.h" #include "opensc-pkcs15.h" #include "sc-log.h" #include "sc-asn1.h" @@ -229,14 +229,21 @@ int sc_pkcs15_read_certificate(struct sc_pkcs15_card *p15card, SC_FUNC_CALLED(p15card->card->ctx, 1); r = find_cached_cert(p15card, info, &data, &len); if (r) { + r = sc_lock(p15card->card); + SC_TEST_RET(p15card->card->ctx, r, "sc_lock() failed"); r = sc_select_file(p15card->card, &info->path, &file); - if (r) + if (r) { + sc_unlock(p15card->card); return r; + } data = malloc(file.size); - if (data == NULL) + if (data == NULL) { + sc_unlock(p15card->card); return SC_ERROR_OUT_OF_MEMORY; + } r = sc_read_binary(p15card->card, 0, data, file.size); if (r < 0) { + sc_unlock(p15card->card); free(data); return r; } @@ -244,6 +251,7 @@ int sc_pkcs15_read_certificate(struct sc_pkcs15_card *p15card, #ifdef CACHE_CERTS store_cert_to_cache(p15card, info, data, len); #endif + sc_unlock(p15card->card); } cert = malloc(sizeof(struct sc_pkcs15_cert)); if (cert == NULL) { @@ -351,16 +359,21 @@ static int get_certs_from_file(struct sc_pkcs15_card *card, int sc_pkcs15_enum_certificates(struct sc_pkcs15_card *card) { - int r, i; + int r = 0, i; assert(card != NULL); if (card->cert_count) return card->cert_count; /* already enumerated */ + r = sc_lock(card->card); + SC_TEST_RET(card->card->ctx, r, "sc_lock() failed"); for (i = 0; i < card->cdf_count; i++) { r = get_certs_from_file(card, &card->file_cdf[i]); if (r != 0) - return r; + break; } + sc_unlock(card->card); + if (r != 0) + return r; return card->cert_count; } diff --git a/src/libopensc/pkcs15-pin.c b/src/libopensc/pkcs15-pin.c index cbeecc7c..a8de3bde 100644 --- a/src/libopensc/pkcs15-pin.c +++ b/src/libopensc/pkcs15-pin.c @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "opensc.h" +#include "sc-internal.h" #include "opensc-pkcs15.h" #include "sc-asn1.h" #include "sc-log.h" @@ -147,10 +147,16 @@ int sc_pkcs15_enum_pins(struct sc_pkcs15_card *p15card) return i; /* Already enumerated */ } p15card->pin_count = 0; + r = sc_lock(p15card->card); + SC_TEST_RET(p15card->card->ctx, r, "sc_lock() failed"); for (i = 0; i < p15card->aodf_count; i++) { r = get_pins_from_file(p15card, &p15card->file_aodf[i]); - SC_TEST_RET(ctx, r, "Failed to read PINs from AODF"); + if (r != 0) + break; } + sc_unlock(p15card->card); + if (r != 0) + return r; return p15card->pin_count; } @@ -169,15 +175,19 @@ int sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card, if (pinlen > pin->stored_length || pinlen < pin->min_length) return SC_ERROR_INVALID_PIN_LENGTH; card = p15card->card; + r = sc_lock(card); + SC_TEST_RET(card->ctx, r, "sc_lock() failed"); r = sc_select_file(card, &pin->path, &file); - if (r) + if (r) { + sc_unlock(card); return r; - + } memset(pinbuf, pin->pad_char, pin->stored_length); memcpy(pinbuf, pincode, pinlen); r = sc_verify(card, pin->auth_id.value[0], pinbuf, pin->stored_length, &pin->tries_left); memset(pinbuf, 0, pinlen); + sc_unlock(card); if (r) return r; @@ -203,10 +213,13 @@ int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card, if ((oldpinlen < pin->min_length) || (newpinlen < pin->min_length)) return SC_ERROR_INVALID_ARGUMENTS; card = p15card->card; + r = sc_lock(card); + SC_TEST_RET(card->ctx, r, "sc_lock() failed"); r = sc_select_file(card, &pin->path, &file); - if (r) + if (r) { + sc_unlock(card); return r; - + } memset(pinbuf, pin->pad_char, pin->stored_length * 2); memcpy(pinbuf, oldpin, oldpinlen); memcpy(pinbuf + pin->stored_length, newpin, newpinlen); @@ -214,6 +227,7 @@ int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card, pin->stored_length, pinbuf+pin->stored_length, pin->stored_length, &pin->tries_left); memset(pinbuf, 0, pin->stored_length * 2); + sc_unlock(card); return r; } diff --git a/src/libopensc/pkcs15-prkey.c b/src/libopensc/pkcs15-prkey.c index 555bc9f2..9d17949e 100644 --- a/src/libopensc/pkcs15-prkey.c +++ b/src/libopensc/pkcs15-prkey.c @@ -18,9 +18,10 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "opensc.h" +#include "sc-internal.h" #include "opensc-pkcs15.h" #include "sc-asn1.h" +#include "sc-log.h" #include #include #include @@ -133,11 +134,16 @@ int sc_pkcs15_enum_private_keys(struct sc_pkcs15_card *card) if (card->prkey_count) return card->prkey_count; /* already enumerated */ + r = sc_lock(card->card); + SC_TEST_RET(card->card->ctx, r, "sc_lock() failed"); for (i = 0; i < 1; i++) { r = get_prkeys_from_file(card, &card->file_prkdf); if (r != 0) - return r; + break; } + sc_unlock(card->card); + if (r != 0) + return r; return card->prkey_count; } diff --git a/src/libopensc/pkcs15-sec.c b/src/libopensc/pkcs15-sec.c index a61f6625..41bb133c 100644 --- a/src/libopensc/pkcs15-sec.c +++ b/src/libopensc/pkcs15-sec.c @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "opensc.h" +#include "sc-internal.h" #include "opensc-pkcs15.h" #include "sc-log.h" #include @@ -37,12 +37,12 @@ int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card, senv.algorithm_ref = 0x02; senv.key_file_id = prkey->file_id; - senv.operation = 0; + senv.operation = SC_SEC_OPERATION_DECIPHER; senv.key_ref = prkey->key_reference; SC_FUNC_CALLED(ctx, 1); r = sc_select_file(p15card->card, &p15card->file_app.path, - &p15card->file_app); + NULL); SC_TEST_RET(ctx, r, "sc_select_file() failed"); #if 0 /* FIXME! */ @@ -75,12 +75,12 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card, break; } senv.key_file_id = prkey->file_id; - senv.operation = 1; + senv.operation = SC_SEC_OPERATION_SIGN; senv.key_ref = prkey->key_reference; SC_FUNC_CALLED(ctx, 1); r = sc_select_file(p15card->card, &p15card->file_app.path, - &p15card->file_app); + NULL); SC_TEST_RET(ctx, r, "sc_select_file() failed"); #if 0 /* FIXME! */ diff --git a/src/libopensc/pkcs15.c b/src/libopensc/pkcs15.c index 8d71b7b5..c8499557 100644 --- a/src/libopensc/pkcs15.c +++ b/src/libopensc/pkcs15.c @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "opensc.h" +#include "sc-internal.h" #include "opensc-pkcs15.h" #include "sc-asn1.h" #include "sc-log.h" @@ -252,9 +252,11 @@ int sc_pkcs15_bind(struct sc_card *card, struct sc_pkcs15_card *p15card = NULL; struct sc_path tmppath; const struct sc_pkcs15_defaults *defaults = NULL; + struct sc_context *ctx; - assert(card != NULL && p15card_out != NULL); - SC_FUNC_CALLED(card->ctx, 1); + assert(sc_card_valid(card) && p15card_out != NULL); + ctx = card->ctx; + SC_FUNC_CALLED(ctx, 1); p15card = malloc(sizeof(struct sc_pkcs15_card)); if (p15card == NULL) return SC_ERROR_OUT_OF_MEMORY; @@ -262,19 +264,30 @@ int sc_pkcs15_bind(struct sc_card *card, p15card->card = card; sc_format_path("2F00", &tmppath); + err = sc_lock(card); + if (err) { + error(ctx, "sc_lock() failed: %s\n", sc_strerror(err)); + goto error; + } err = sc_select_file(card, &tmppath, &p15card->file_dir); - if (err) + if (err) { + error(ctx, "Error selecting EF(DIR): %s\n", sc_strerror(err)); goto error; + } err = sc_read_binary(card, 0, buf, p15card->file_dir.size); - if (err < 0) + if (err < 0) { + error(ctx, "Error reading EF(DIR): %s\n", sc_strerror(err)); goto error; + } if (err <= 2) { err = SC_ERROR_PKCS15_CARD_NOT_FOUND; + error(ctx, "Error reading EF(DIR): too few bytes read\n"); goto error; } len = err; if (parse_dir(buf, len, p15card)) { err = SC_ERROR_PKCS15_CARD_NOT_FOUND; + error(ctx, "Error parsing EF(DIR)\n"); goto error; } if (p15card->use_cache) @@ -288,7 +301,7 @@ int sc_pkcs15_bind(struct sc_card *card, tmppath = p15card->file_odf.path; err = sc_select_file(card, &tmppath, &p15card->file_odf); - if (err) + if (err) /* FIXME: finish writing error stuff */ goto error; err = sc_read_binary(card, 0, buf, p15card->file_odf.size); if (err < 0) @@ -327,10 +340,12 @@ int sc_pkcs15_bind(struct sc_card *card, p15card->use_cache = card->ctx->use_cache; *p15card_out = p15card; + sc_unlock(card); return 0; error: free(p15card); - return err; + sc_unlock(card); + SC_FUNC_RETURN(ctx, 1, err); } int sc_pkcs15_unbind(struct sc_pkcs15_card *p15card) diff --git a/src/libopensc/sc.c b/src/libopensc/sc.c index 55120f8b..887eefd8 100644 --- a/src/libopensc/sc.c +++ b/src/libopensc/sc.c @@ -21,7 +21,7 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include "opensc.h" +#include "sc-internal.h" #include "sc-log.h" #include "sc-asn1.h" #include @@ -187,14 +187,21 @@ int sc_establish_context(struct sc_context **ctx_out) break; } while (p < (reader_buf + reader_buf_size - 1)); free(reader_buf); - for (i = 0; i < SC_MAX_CARD_DRIVERS; i++) + for (i = 0; i < SC_MAX_CARD_DRIVERS+1; i++) ctx->card_drivers[i] = NULL; i = 0; +#if 1 + ctx->card_drivers[i++] = sc_get_setec_driver(); +#endif +#if 1 + ctx->card_drivers[i++] = sc_get_mflex_driver(); +#endif #if 1 ctx->card_drivers[i++] = sc_get_iso7816_driver(); #endif #if 1 - ctx->card_drivers[i++] = sc_get_setec_driver(); + /* this should be last in line */ + ctx->card_drivers[i++] = sc_get_default_driver(); #endif *ctx_out = ctx; @@ -216,8 +223,13 @@ int sc_destroy_context(struct sc_context *ctx) void sc_format_path(const char *str, struct sc_path *path) { int len = 0; + int type = SC_PATH_TYPE_PATH; u8 *p = path->value; + if (*p == 'i' || *p == 'I') { + type = SC_PATH_TYPE_FILE_ID; + p++; + } while (str) { int byte; @@ -228,7 +240,7 @@ void sc_format_path(const char *str, struct sc_path *path) str += 2; } path->len = len; - path->type = SC_PATH_TYPE_PATH; + path->type = type; return; } @@ -275,3 +287,10 @@ const char *sc_strerror(int error) return errors[0]; return errors[error]; } + +inline int sc_file_valid(const struct sc_file *file) { +#ifndef NDEBUG + assert(file != NULL); +#endif + return file->magic == SC_FILE_MAGIC; +} diff --git a/src/libopensc/sec.c b/src/libopensc/sec.c index c4114898..fdbe2e44 100644 --- a/src/libopensc/sec.c +++ b/src/libopensc/sec.c @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "opensc.h" +#include "sc-internal.h" #include "sc-log.h" #include #include @@ -35,12 +35,17 @@ int sc_set_security_env(struct sc_card *card, assert(card != NULL && env != NULL); SC_FUNC_CALLED(card->ctx, 2); sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0, 0); - if (env->operation == 1) { - apdu.p1 = 0x81; - apdu.p2 = 0xB6; - } else { + switch (env->operation) { + case SC_SEC_OPERATION_DECIPHER: apdu.p1 = 0x41; apdu.p2 = 0xB8; + break; + case SC_SEC_OPERATION_SIGN: + apdu.p1 = 0x81; + apdu.p2 = 0xB6; + break; + default: + return SC_ERROR_INVALID_ARGUMENTS; } apdu.le = 0; p = sbuf; diff --git a/src/pam/Makefile.am b/src/pam/Makefile.am index bd2e725b..70640716 100644 --- a/src/pam/Makefile.am +++ b/src/pam/Makefile.am @@ -10,15 +10,15 @@ SRC = pam_pkcs15.c INC = if HAVE_PAM_AND_SSL -lib_LTLIBRARIES = libpam_pkcs15.la +lib_LTLIBRARIES = pam_pkcs15.la noinst_PROGRAMS = pam_pkcs15-test else lib_LTLIBRARIES = noinst_PROGRAMS = endif -libpam_pkcs15_la_SOURCES = $(SRC) $(INC) -libpam_pkcs15_la_LDFLAGS = -module -avoid-version +pam_pkcs15_la_SOURCES = $(SRC) $(INC) +pam_pkcs15_la_LDFLAGS = -module -avoid-version pam_pkcs15_test_SOURCES = $(SRC) $(INC) pam_pkcs15_test_CFLAGS = -DTEST @@ -27,7 +27,5 @@ if HAVE_PAM_AND_SSL install-exec-local: install-libLTLIBRARIES @$(NORMAL_INSTALL) - -rm -f $(DESTDIR)$(libdir)/pam_pkcs15.so - -cd $(DESTDIR)$(libdir) && ln -s libpam_pkcs15.so pam_pkcs15.so endif diff --git a/src/pkcs11/Makefile.am b/src/pkcs11/Makefile.am index 6d76f263..6972e11b 100644 --- a/src/pkcs11/Makefile.am +++ b/src/pkcs11/Makefile.am @@ -16,4 +16,4 @@ INC = sc-pkcs11.h lib_LTLIBRARIES = libopensc-pkcs11.la libopensc_pkcs11_la_SOURCES = $(SRC) $(INC) -libopensc_pkcs11_la_LDFLAGS = -module +libopensc_pkcs11_la_LDFLAGS = -module -version-info 1:0:0 diff --git a/src/tools/opensc-crypt.c b/src/tools/opensc-crypt.c index 431d0038..5854b496 100644 --- a/src/tools/opensc-crypt.c +++ b/src/tools/opensc-crypt.c @@ -292,7 +292,15 @@ int main(int argc, char * const argv[]) goto end; } - sc_lock(card); +#if 0 + r = sc_lock(card); + if (r) { + fprintf(stderr, "Unable to lock card: %s\n", sc_strerror(r)); + err = 1; + goto end; + } +#endif + if (!quiet) fprintf(stderr, "Trying to find a PKCS#15 compatible card...\n"); r = sc_pkcs15_bind(card, &p15card); @@ -358,7 +366,9 @@ end: if (p15card) sc_pkcs15_unbind(p15card); if (card) { +#if 0 sc_unlock(card); +#endif sc_disconnect_card(card); } if (ctx) diff --git a/src/tools/opensc-tool.c b/src/tools/opensc-tool.c index ff4209ff..0be6ca98 100644 --- a/src/tools/opensc-tool.c +++ b/src/tools/opensc-tool.c @@ -27,6 +27,7 @@ #include #include #include +#include #define OPT_CHANGE_PIN 0x100 #define OPT_LIST_PINS 0x101 @@ -44,6 +45,7 @@ int quiet = 0; const struct option options[] = { { "list-readers", 0, 0, 'l' }, + { "list-drivers", 0, 0, 'D' }, { "list-files", 0, 0, 'f' }, { "learn-card", 0, 0, 'L' }, { "send-apdu", 1, 0, 's' }, @@ -63,6 +65,7 @@ const struct option options[] = { const char *option_help[] = { "Lists all configured readers", + "Lists all installed card drivers", "Recursively lists files stored on card", "Stores card info to cache [P15]", "Sends an APDU in format AA:BB:CC:DD:EE:FF...", @@ -126,6 +129,10 @@ int list_readers() { int i; + if (ctx->reader_count == 0) { + printf("No readers configured!\n"); + return 0; + } printf("Configured readers:\n"); for (i = 0; i < ctx->reader_count; i++) { printf("\t%d - %s\n", i, ctx->readers[i]); @@ -133,6 +140,21 @@ int list_readers() return 0; } +int list_drivers() +{ + int i; + + if (ctx->card_drivers[0] == NULL) { + printf("No card drivers installed!\n"); + return 0; + } + printf("Configured card drivers:\n"); + for (i = 0; ctx->card_drivers[i] != NULL; i++) { + printf("\t%s\n", ctx->card_drivers[i]->name); + } + return 0; +} + int list_certificates() { int r, i; @@ -359,7 +381,7 @@ int enum_dir(struct sc_path path, int depth) u8 buf[2048]; const char *tmps; - r = sc_select_file(card, &file, &path); + r = sc_select_file(card, &path, &file); if (r) { fprintf(stderr, "SELECT FILE failed: %s\n", sc_strerror(r)); return 1; @@ -528,18 +550,44 @@ int learn_card() return 0; } +void hex_dump_asc(const u8 *in, size_t count) +{ + int lines = 0; + + while (count) { + char ascbuf[17]; + int i; + + for (i = 0; i < count && i < 16; i++) { + printf("%02X ", *in); + if (isprint(*in)) + ascbuf[i] = *in; + else + ascbuf[i] = '.'; + in++; + } + count -= i; + ascbuf[i] = 0; + for (; i < 16 && lines; i++) + printf(" "); + printf("%s\n", ascbuf); + lines++; + } +} + int send_apdu() { struct sc_apdu apdu; u8 buf[MAX_BUFFER_SIZE], sbuf[MAX_BUFFER_SIZE], rbuf[MAX_BUFFER_SIZE], *p = buf; - int len = sizeof(buf), r; + int len = sizeof(buf), len0, r; - sc_hex_to_bin(opt_apdu, buf, &len); + sc_hex_to_bin(opt_apdu, buf, &len0); if (len < 4) { fprintf(stderr, "APDU too short (must be at least 4 bytes).\n"); return 2; } + len = len0; apdu.cla = *p++; apdu.ins = *p++; apdu.p1 = *p++; @@ -548,6 +596,7 @@ int send_apdu() apdu.resplen = sizeof(rbuf); apdu.data = NULL; apdu.datalen = 0; + apdu.no_response = 0; len -= 4; if (len > 1) { apdu.lc = *p++; @@ -577,15 +626,21 @@ int send_apdu() apdu.cse = SC_APDU_CASE_2_SHORT; } else apdu.cse = SC_APDU_CASE_1; - - ctx->debug = 5; + printf("Sending: "); + for (r = 0; r < len0; r++) + printf("%02X ", buf[r]); + printf("\n"); +// ctx->debug = 5; r = sc_transmit_apdu(card, &apdu); - ctx->debug = opt_debug; +// ctx->debug = opt_debug; if (r) { fprintf(stderr, "APDU transmit failed: %s\n", sc_strerror(r)); return 1; } - + printf("Received (SW1=0x%02X, SW2=0x%02X)%s\n", apdu.sw1, apdu.sw2, + apdu.resplen ? ":" : ""); + if (apdu.resplen) + hex_dump_asc(apdu.resp, apdu.resplen); return 0; } @@ -593,6 +648,7 @@ int main(int argc, char * const argv[]) { int err = 0, r, c, long_optind = 0; int do_list_readers = 0; + int do_list_drivers = 0; int do_read_cert = 0; int do_list_certs = 0; int do_list_pins = 0; @@ -604,7 +660,7 @@ int main(int argc, char * const argv[]) int action_count = 0; while (1) { - c = getopt_long(argc, argv, "lfr:kco:qdp:s:L", options, &long_optind); + c = getopt_long(argc, argv, "lfr:kco:qdp:s:LD", options, &long_optind); if (c == -1) break; if (c == '?') @@ -619,6 +675,10 @@ int main(int argc, char * const argv[]) do_list_readers = 1; action_count++; break; + case 'D': + do_list_drivers = 1; + action_count++; + break; case 'f': do_list_files = 1; action_count++; @@ -684,6 +744,11 @@ int main(int argc, char * const argv[]) goto end; action_count--; } + if (do_list_drivers) { + if ((err = list_drivers())) + goto end; + action_count--; + } if (action_count <= 0) goto end; if (opt_reader >= ctx->reader_count || opt_reader < 0) { @@ -704,7 +769,12 @@ int main(int argc, char * const argv[]) goto end; } - sc_lock(card); + r = sc_lock(card); + if (r) { + fprintf(stderr, "Unable to lock card: %s\n", sc_strerror(r)); + err = 1; + goto end; + } if (do_send_apdu) { if ((err = send_apdu()))