diff options
author | Werner Koch <wk@gnupg.org> | 2003-08-18 19:34:28 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2003-08-18 19:34:28 +0200 |
commit | 0506e4ebec8db4f4b2f5ecdb3122abca8f70b670 (patch) | |
tree | debc0b339fb8fd0c97f9c219eea1dbdf3782f476 /scd | |
parent | Add 'dynload.h' to Makefile.am. (diff) | |
download | gnupg2-0506e4ebec8db4f4b2f5ecdb3122abca8f70b670.tar.xz gnupg2-0506e4ebec8db4f4b2f5ecdb3122abca8f70b670.zip |
* Makefile.am: Add OPENSC_LIBS to all programs.
* scdaemon.c, scdaemon.h: New option --disable-opensc.
* card.c (card_open): Implement it.
* apdu.c (open_osc_reader, osc_send_apdu): New.
(apdu_open_reader) [HAVE_OPENSC]: Use the opensc driver if not
disabled.
(error_string) [HAVE_OPENSC]: Use sc_strerror.
(send_apdu) [HAVE_OPENSC]: Call osc_apdu_send.
Diffstat (limited to 'scd')
-rw-r--r-- | scd/ChangeLog | 17 | ||||
-rw-r--r-- | scd/Makefile.am | 4 | ||||
-rw-r--r-- | scd/apdu.c | 237 | ||||
-rw-r--r-- | scd/scdaemon.c | 12 | ||||
-rw-r--r-- | scd/scdaemon.h | 1 |
5 files changed, 261 insertions, 10 deletions
diff --git a/scd/ChangeLog b/scd/ChangeLog index d78c4aa16..a1cb11e0b 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,9 +1,24 @@ +2003-08-18 Werner Koch <wk@gnupg.org> + + * Makefile.am: Add OPENSC_LIBS to all programs. + + * scdaemon.c, scdaemon.h: New option --disable-opensc. + * card.c (card_open): Implement it. + * apdu.c (open_osc_reader, osc_send_apdu): New. + (apdu_open_reader) [HAVE_OPENSC]: Use the opensc driver if not + disabled. + (error_string) [HAVE_OPENSC]: Use sc_strerror. + (send_apdu) [HAVE_OPENSC]: Call osc_apdu_send. + + * card-p15.c (p15_enum_keypairs, p15_prepare_key): Adjusted for + libgpg-error. + 2003-08-14 Timo Schulz <twoaday@freakmail.de> * apdu.c (ct_activate_card): Change the code a little to avoid problems with other readers. * Always use 'dynload.h' instead of 'dlfcn.h'. - + 2003-08-05 Werner Koch <wk@gnupg.org> * app-openpgp.c (dump_all_do): Don't analyze constructed DOs after diff --git a/scd/Makefile.am b/scd/Makefile.am index 0771beb60..5ecadd2e8 100644 --- a/scd/Makefile.am +++ b/scd/Makefile.am @@ -50,7 +50,7 @@ sc_investigate_SOURCES = \ sc_investigate_LDADD = \ ../jnlib/libjnlib.a ../common/libcommon.a \ - $(LIBGCRYPT_LIBS) @INTLLIBS@ -lgpg-error -ldl + $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) @INTLLIBS@ -lgpg-error -ldl sc_copykeys_SOURCES = \ @@ -64,7 +64,7 @@ sc_copykeys_SOURCES = \ sc_copykeys_LDADD = \ ../jnlib/libjnlib.a ../common/libcommon.a \ ../common/libsimple-pwquery.a \ - $(LIBGCRYPT_LIBS) -lgpg-error @INTLLIBS@ -ldl + $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) -lgpg-error @INTLLIBS@ -ldl diff --git a/scd/apdu.c b/scd/apdu.c index 6afcd6711..978d9ae3d 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -24,6 +24,9 @@ #include <stdlib.h> #include <string.h> #include <assert.h> +#ifdef HAVE_OPENSC +# include <opensc/opensc.h> +#endif #include "scdaemon.h" #include "apdu.h" @@ -34,9 +37,9 @@ insertion of the card (1 = don't wait). */ - -/* A global table to keep track of active readers. */ -static struct { +/* A structure to collect information pertaining to one reader + slot. */ +struct reader_table_s { int used; /* True if slot is used. */ unsigned short port; /* Port number: 0 = unused, 1 - dev/tty */ int is_ctapi; /* This is a ctAPI driver. */ @@ -45,10 +48,21 @@ static struct { unsigned long card; unsigned long protocol; } pcsc; +#ifdef HAVE_OPENSC + int is_osc; /* We are using the OpenSC driver layer. */ + struct { + struct sc_context *ctx; + struct sc_card *scard; + } osc; +#endif /*HAVE_OPENSC*/ int status; unsigned char atr[33]; size_t atrlen; -} reader_table[MAX_READER]; +}; +typedef struct reader_table_s *reader_table_t; + +/* A global table to keep track of active readers. */ +static struct reader_table_s reader_table[MAX_READER]; /* ct API function pointer. */ @@ -142,6 +156,7 @@ new_reader_slot (void) } reader_table[reader].used = 1; reader_table[reader].is_ctapi = 0; + reader_table[reader].is_osc = 0; return reader; } @@ -513,7 +528,7 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen, unsigned long recv_len; if (DBG_CARD_IO) - log_printhex (" CT_data:", apdu, apdulen); + log_printhex (" PCSC_data:", apdu, apdulen); if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1)) send_pci.protocol = PCSC_PROTOCOL_T1; @@ -529,10 +544,199 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen, log_error ("pcsc_transmit failed: %s (0x%lx)\n", pcsc_error_string (err), err); - return err? -1:0; + return err? -1:0; /* FIXME: Return appropriate error code. */ +} + + +#ifdef HAVE_OPENSC +/* + OpenSC Interface. + + This uses the OpenSC primitives to send APDUs. We need this + because we can't mix OpenSC and native (i.e. ctAPI or PC/SC) + access to a card for resource conflict reasons. + */ + +static int +open_osc_reader (int portno) +{ + int err; + int slot; + reader_table_t slotp; + + slot = new_reader_slot (); + if (slot == -1) + return -1; + slotp = reader_table + slot; + + err = sc_establish_context (&slotp->osc.ctx, "scdaemon"); + if (err) + { + log_error ("failed to establish SC context: %s\n", sc_strerror (err)); + slotp->used = 0; + return -1; + } + if (portno < 0 || portno >= slotp->osc.ctx->reader_count) + { + log_error ("no card reader available\n"); + sc_release_context (slotp->osc.ctx); + slotp->used = 0; + return -1; + } + + /* Redirect to our logging facility. */ + slotp->osc.ctx->error_file = log_get_stream (); + slotp->osc.ctx->debug = opt.debug_sc; + slotp->osc.ctx->debug_file = log_get_stream (); + + if (sc_detect_card_presence (slotp->osc.ctx->reader[portno], 0) != 1) + { + log_error ("no card present\n"); + sc_release_context (slotp->osc.ctx); + slotp->used = 0; + return -1; + } + + /* We want the standard ISO driver. */ + /*FIXME: OpenSC does not like "iso7816", so we use EMV for now. */ + err = sc_set_card_driver(slotp->osc.ctx, "emv"); + if (err) + { + log_error ("failed to select the iso7816 driver: %s\n", + sc_strerror (err)); + sc_release_context (slotp->osc.ctx); + slotp->used = 0; + return -1; + } + + /* Now connect the card and hope that OpenSC won't try to be too + smart. */ + err = sc_connect_card (slotp->osc.ctx->reader[portno], 0, + &slotp->osc.scard); + if (err) + { + log_error ("failed to connect card in reader %d: %s\n", + portno, sc_strerror (err)); + sc_release_context (slotp->osc.ctx); + slotp->used = 0; + return -1; + } + if (opt.verbose) + log_info ("connected to card in opensc reader %d using driver `%s'\n", + portno, slotp->osc.scard->driver->name); + + err = sc_lock (slotp->osc.scard); + if (err) + { + log_error ("can't lock card in reader %d: %s\n", + portno, sc_strerror (err)); + sc_disconnect_card (slotp->osc.scard, 0); + sc_release_context (slotp->osc.ctx); + slotp->used = 0; + return -1; + } + + if (slotp->osc.scard->atr_len >= DIM (slotp->atr)) + log_bug ("ATR returned by opensc is too large\n"); + slotp->atrlen = slotp->osc.scard->atr_len; + memcpy (slotp->atr, slotp->osc.scard->atr, slotp->atrlen); + + slotp->is_osc = 1; + + dump_reader_status (slot); + return slot; } +/* Actually send the APDU of length APDULEN to SLOT and return a + maximum of *BUFLEN data in BUFFER, the actual returned size will be + set to BUFLEN. Returns: OpenSC error code. */ +static int +osc_send_apdu (int slot, unsigned char *apdu, size_t apdulen, + unsigned char *buffer, size_t *buflen) +{ + long err; + struct sc_apdu a; + unsigned char data[SC_MAX_APDU_BUFFER_SIZE]; + unsigned char result[SC_MAX_APDU_BUFFER_SIZE]; + + if (DBG_CARD_IO) + log_printhex (" APDU_data:", apdu, apdulen); + + if (apdulen < 4) + { + log_error ("osc_send_apdu: APDU is too short\n"); + return SC_ERROR_CMD_TOO_SHORT; + } + + memset(&a, 0, sizeof a); + a.cla = *apdu++; + a.ins = *apdu++; + a.p1 = *apdu++; + a.p2 = *apdu++; + apdulen -= 4; + + if (!apdulen) + a.cse = SC_APDU_CASE_1; + else if (apdulen == 1) + { + a.le = *apdu? *apdu : 256; + apdu++; apdulen--; + a.cse = SC_APDU_CASE_2_SHORT; + } + else + { + a.lc = *apdu++; apdulen--; + if (apdulen < a.lc) + { + log_error ("osc_send_apdu: APDU shorter than specified in Lc\n"); + return SC_ERROR_CMD_TOO_SHORT; + + } + memcpy(data, apdu, a.lc); + apdu += a.lc; apdulen -= a.lc; + + a.data = data; + a.datalen = a.lc; + + if (!apdulen) + a.cse = SC_APDU_CASE_3_SHORT; + else + { + a.le = *apdu? *apdu : 256; + apdu++; apdulen--; + if (apdulen) + { + log_error ("osc_send_apdu: APDU larger than specified\n"); + return SC_ERROR_CMD_TOO_LONG; + } + a.cse = SC_APDU_CASE_4_SHORT; + } + } + + a.resp = result; + a.resplen = DIM(result); + + err = sc_transmit_apdu (reader_table[slot].osc.scard, &a); + if (err) + { + log_error ("sc_apdu_transmit failed: %s\n", sc_strerror (err)); + return err; + } + + if (*buflen < 2 || a.resplen > *buflen - 2) + { + log_error ("osc_send_apdu: provided buffer too short to store result\n"); + return SC_ERROR_BUFFER_TOO_SMALL; + } + memcpy (buffer, a.resp, a.resplen); + buffer[a.resplen] = a.sw1; + buffer[a.resplen+1] = a.sw2; + *buflen = a.resplen + 2; + return 0; +} + +#endif /* HAVE_OPENSC */ @@ -542,12 +746,23 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen, /* Open the reader and return an internal slot number or -1 on error. If PORTSTR is NULL we default to a suitable port (for ctAPI: - the first USB reader. For PCSC/ the first listed reader. */ + the first USB reader. For PC/SC the first listed reader). IF + OpenSC support is cmpiled in, we first try to use OpenSC. */ int apdu_open_reader (const char *portstr) { static int pcsc_api_loaded, ct_api_loaded; +#ifdef HAVE_OPENSC + if (!opt.disable_opensc) + { + int port = portstr? atoi (portstr) : 0; + + return open_osc_reader (port); + } +#endif /* HAVE_OPENSC */ + + if (opt.ctapi_driver && *opt.ctapi_driver) { int port = portstr? atoi (portstr) : 32768; @@ -648,6 +863,10 @@ error_string (int slot, long rc) return "[invalid slot]"; if (reader_table[slot].is_ctapi) return ct_error_string (rc); +#ifdef HAVE_OPENSC + else if (reader_table[slot].is_osc) + return sc_strerror (rc); +#endif else return pcsc_error_string (rc); } @@ -662,6 +881,10 @@ send_apdu (int slot, unsigned char *apdu, size_t apdulen, return SW_HOST_NO_DRIVER; if (reader_table[slot].is_ctapi) return ct_send_apdu (slot, apdu, apdulen, buffer, buflen); +#ifdef HAVE_OPENSC + else if (reader_table[slot].is_osc) + return osc_send_apdu (slot, apdu, apdulen, buffer, buflen); +#endif else return pcsc_send_apdu (slot, apdu, apdulen, buffer, buflen); } diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 11952615d..af813b57d 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -70,6 +70,7 @@ enum cmd_and_opt_values oBatch, oReaderPort, octapiDriver, + oDisableOpenSC, aTest }; @@ -94,6 +95,16 @@ static ARGPARSE_OPTS opts[] = { { oLogFile, "log-file" ,2, N_("use a log file for the server")}, { oReaderPort, "reader-port", 2, N_("|N|connect to reader at port N")}, { octapiDriver, "ctapi-driver", 2, N_("NAME|use NAME as ctAPI driver")}, + { oDisableOpenSC, "disable-opensc", 0, +#ifdef HAVE_OPENSC + N_("Do not use the OpenSC layer") +#else + "@" +#endif + /* end --disable-opensc */}, + + + {0} }; @@ -368,6 +379,7 @@ main (int argc, char **argv ) case oReaderPort: app_set_default_reader_port (pargs.r.ret_str); break; case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break; + case oDisableOpenSC: opt.disable_opensc = 1; break; default : pargs.err = configfp? 1:2; break; } diff --git a/scd/scdaemon.h b/scd/scdaemon.h index bdc4c21b3..20e2fa768 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -54,6 +54,7 @@ struct { int batch; /* batch mode */ const char *homedir; /* configuration directory name */ const char *ctapi_driver; /* Library to access the ctAPI. */ + int disable_opensc; /* Disable the sue of the OpenSC framework. */ } opt; |