From 6b002f06026b5555aabb84c194e3f4aa1f8692b2 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 11 Apr 2005 16:20:10 +0000 Subject: [PATCH] * app-openpgp.c (do_check_pin): Add hack to allow verification of CHV3. (get_public_key): Don't use gcry functions to create S-expressions. (do_deinit, do_readkey, do_genkey, send_keypair_info): Adjust for above change. --- scd/ChangeLog | 30 ++++++++++ scd/app-openpgp.c | 144 ++++++++++++++++++++++++++++++++-------------- scd/app.c | 2 +- scd/ccid-driver.c | 89 +++++++++++++++++++--------- scd/command.c | 66 +++++++++++++++------ 5 files changed, 241 insertions(+), 90 deletions(-) diff --git a/scd/ChangeLog b/scd/ChangeLog index ca7358406..f8f8043c1 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,11 @@ +2005-04-07 Werner Koch + + * app-openpgp.c (do_check_pin): Add hack to allow verification of + CHV3. + (get_public_key): Don't use gcry functions to create S-expressions. + (do_deinit, do_readkey, do_genkey, send_keypair_info): Adjust for + above change. + 2005-03-29 Moritz Schulte * app-openpgp.c (retrieve_fpr_from_card): New function. @@ -6,6 +14,19 @@ (get_public_key): Implement retrival of key through expernal helper (gpg) in case the openpgp card is not cooperative enough. +2005-03-16 Werner Koch + + * ccid-driver.c (parse_ccid_descriptor): Make SCM workaround + reader type specific. + (scan_or_find_devices): Do not check the interface subclass in the + SPR532 kludge, as this depends on the firmware version. + (ccid_get_atr): Get the Slot status first. This solves the + problem with readers hanging on recent Linux 2.6.x. + (bulk_in): Add argument TIMEOUT and changed all callers to pass an + appropriate one. Change the standard timeout from 10 to 5 seconds. + (ccid_slot_status): Add a retry code with an initial short timeout. + (do_close_reader): Do an usb_reset before closing the reader. + 2005-02-25 Werner Koch * app-openpgp.c (get_public_key): Make sure not to return negative @@ -42,6 +63,15 @@ (reset_pcsc_reader, pcsc_get_status, pcsc_send_apdu) (open_pcsc_reader): Do proper error code mapping. +2005-03-16 Werner Koch + + * ccid-driver.c (parse_ccid_descriptor): Make SCM workaround + reader type specific. + (scan_or_find_devices): Do not check the interface subclass in the + SPR532 kludge, as this depends on the firmware version. + (ccid_get_atr): Get the Slot status first. This solves the + problem with readers hanging on recent Linux 2.6.x. + 2005-02-22 Werner Koch * app-openpgp.c (app_local_s): New field PK. diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index bae9dde49..1ed057195 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -108,7 +108,14 @@ struct app_local_s { struct { int read_done; /* True if we have at least tried to read them. */ - gcry_sexp_t key; /* Might be NULL if key is not available. */ + unsigned char *key; /* This is a malloced buffer with a canonical + encoded S-expression encoding a public + key. Might be NULL if key is not + available. */ + size_t keylen; /* The length of the above S-expression. Thsi + is usullay only required for corss checks + because the length of an S-expression is + implicitly available. */ } pk[3]; /* Keep track of card capabilities. */ @@ -156,7 +163,7 @@ do_deinit (app_t app) for (i=0; i < DIM (app->app_local->pk); i++) { - gcry_sexp_release (app->app_local->pk[i].key); + xfree (app->app_local->pk[i].key); app->app_local->pk[i].read_done = 0; } xfree (app->app_local); @@ -864,6 +871,10 @@ retrieve_key_material (FILE *fp, const char *fpr, mpi = NULL; ret = 0; +#warning This part should get rewritten for clarity + /* We should use an algorithm similar to the one used by gpgme. + This will reduce the size of the code at least by 50%. [wk] */ + while (1) { /* FIXME? */ @@ -1041,7 +1052,9 @@ retrieve_key_material (FILE *fp, const char *fpr, presence of the app->app_local->pk[KEYNO-1].key field. Note that GnuPG 1.x does not need this and it would be too time - consuming to send it just for the fun of it. */ + consuming to send it just for the fun of it. However, given that we + use the same code in gpg 1.4, we can't use the gcry S-expresion + here but need to open encode it. */ #if GNUPG_MAJOR_VERSION > 1 static gpg_error_t get_public_key (app_t app, int keyno) @@ -1050,9 +1063,10 @@ get_public_key (app_t app, int keyno) unsigned char *buffer; const unsigned char *keydata, *m, *e; size_t buflen, keydatalen, mlen, elen; - gcry_sexp_t sexp; unsigned char *mbuf = NULL; unsigned char *ebuf = NULL; + unsigned char *keybuf = NULL; + unsigned char *keybuf_p; if (keyno < 1 || keyno > 3) return gpg_error (GPG_ERR_INV_ID); @@ -1062,8 +1076,9 @@ get_public_key (app_t app, int keyno) if (app->app_local->pk[keyno].read_done) return 0; - gcry_sexp_release (app->app_local->pk[keyno].key); + xfree (app->app_local->pk[keyno].key); app->app_local->pk[keyno].key = NULL; + app->app_local->pk[keyno].keylen = 0; if (app->card_version > 0x0100) { @@ -1191,16 +1206,29 @@ get_public_key (app_t app, int keyno) buffer = NULL; } - err = gcry_sexp_build (&sexp, NULL, - "(public-key (rsa (n %b) (e %b)))", - (int)mlen, m,(int)elen, e); - if (err) + /* Allocate a buffer to construct the S-expression. */ + /* FIXME: We should provide a generalized S-expression creation + mechanism. */ + keybuf = xtrymalloc (50 + 2*35 + mlen + elen + 1); + if (!keybuf) { - log_error ("error formatting the key into an S-expression: %s\n", - gpg_strerror (err)); + err = gpg_error_from_errno (errno); goto leave; } - app->app_local->pk[keyno].key = sexp; + + sprintf (keybuf, "(10:public-key(3:rsa(1:n%u", (unsigned int) mlen); + keybuf_p = keybuf + strlen (keybuf); + memcpy (keybuf_p, m, mlen); + keybuf_p += mlen; + sprintf (keybuf_p, ")(1:e%u", (unsigned int)elen); + keybuf_p += strlen (keybuf_p); + memcpy (keybuf_p, e, elen); + keybuf_p += elen; + strcpy (keybuf_p, ")))"); + keybuf_p += strlen (keybuf_p); + + app->app_local->pk[keyno].key = keybuf; + app->app_local->pk[keyno].keylen = (keybuf_p - keybuf); leave: /* Set a flag to indicate that we tried to read the key. */ @@ -1224,7 +1252,6 @@ send_keypair_info (app_t app, ctrl_t ctrl, int keyno) /* Note that GnuPG 1.x does not need this and it would be too time consuming to send it just for the fun of it. */ #if GNUPG_MAJOR_VERSION > 1 - gcry_sexp_t sexp; unsigned char grip[20]; char gripstr[41]; char idbuf[50]; @@ -1235,15 +1262,14 @@ send_keypair_info (app_t app, ctrl_t ctrl, int keyno) goto leave; assert (keyno >= 1 && keyno <= 3); - sexp = app->app_local->pk[keyno-1].key; - if (!sexp) - goto leave; /* No such key. */ + if (!app->app_local->pk[keyno-1].key) + goto leave; /* No such key - ignore. */ - if (!gcry_pk_get_keygrip (sexp, grip)) - { - err = gpg_error (GPG_ERR_INTERNAL); - goto leave; - } + err = keygrip_from_canon_sexp (app->app_local->pk[keyno-1].key, + app->app_local->pk[keyno-1].keylen, + grip); + if (err) + goto leave; for (i=0; i < 20; i++) sprintf (gripstr+i*2, "%02X", grip[i]); @@ -1303,9 +1329,7 @@ do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) { gpg_error_t err; int keyno; - size_t n; unsigned char *buf; - gcry_sexp_t sexp; if (!strcmp (keyid, "OPENPGP.1")) keyno = 1; @@ -1320,24 +1344,11 @@ do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) if (err) return err; - sexp = app->app_local->pk[keyno-1].key; - if (!sexp) - return gpg_error (GPG_ERR_NO_PUBKEY); - - n = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0); - if (!n) - return gpg_error (GPG_ERR_BUG); - buf = xtrymalloc (n); + buf = app->app_local->pk[keyno-1].key; if (!buf) - return gpg_error_from_errno (errno); - n = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, buf, n); - if (!n) - { - xfree (buf); - return gpg_error (GPG_ERR_BUG); - } + return gpg_error (GPG_ERR_NO_PUBKEY); *pk = buf; - *pklen = n; + *pklen = app->app_local->pk[keyno-1].keylen;; return 0; } @@ -1590,7 +1601,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode, else app->did_chv1 = app->did_chv2 = 0; - /* Note to translators: Do not translate the "|*|" prefixes but + /* TRANSLATORS: Do not translate the "|*|" prefixes but keep it at the start of the string. We need this elsewhere to get some infos on the string. */ rc = pincb (pincb_arg, chvno == 3? _("|AN|New Admin PIN") : _("|N|New PIN"), @@ -1661,7 +1672,9 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, flush_cache (app); /* Obviously we need to remove the cached public key. */ - gcry_sexp_release (app->app_local->pk[keyno].key); + xfree (app->app_local->pk[keyno].key); + app->app_local->pk[keyno].key = NULL; + app->app_local->pk[keyno].keylen = 0; app->app_local->pk[keyno].read_done = 0; /* Check whether a key already exists. */ @@ -2142,7 +2155,11 @@ do_decipher (app_t app, const char *keyidstr, cheap check on the PIN: If there is something wrong with the PIN entry system, only the regular CHV will get blocked and not the dangerous CHV3. KEYIDSTR is the usual card's serial number; an - optional fingerprint part will be ignored. */ + optional fingerprint part will be ignored. + + There is a special mode if the keyidstr is "[CHV3]" with + the "[CHV3]" being a literal string: The Admin Pin is checked if + and only if the retry counter is still at 3. */ static int do_check_pin (app_t app, const char *keyidstr, int (pincb)(void*, const char *, char **), @@ -2151,6 +2168,7 @@ do_check_pin (app_t app, const char *keyidstr, unsigned char tmp_sn[20]; const char *s; int n; + int admin_pin = 0; if (!keyidstr || !*keyidstr) return gpg_error (GPG_ERR_INV_VALUE); @@ -2167,6 +2185,8 @@ do_check_pin (app_t app, const char *keyidstr, ; /* No fingerprint given: we allow this for now. */ else if (*s == '/') ; /* We ignore a fingerprint. */ + else if (!strcmp (s, "[CHV3]") ) + admin_pin = 1; else return gpg_error (GPG_ERR_INV_ID); @@ -2177,12 +2197,46 @@ do_check_pin (app_t app, const char *keyidstr, return gpg_error (GPG_ERR_INV_CARD); if (memcmp (app->serialno, tmp_sn, 16)) return gpg_error (GPG_ERR_WRONG_CARD); + /* Yes, there is a race conditions: The user might pull the card right here and we won't notice that. However this is not a problem and the check above is merely for a graceful failure between operations. */ - return verify_chv2 (app, pincb, pincb_arg); + if (admin_pin) + { + void *relptr; + unsigned char *value; + size_t valuelen; + int count; + + relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL); + if (!relptr || valuelen < 7) + { + log_error (_("error retrieving CHV status from card\n")); + xfree (relptr); + return gpg_error (GPG_ERR_CARD); + } + count = value[6]; + xfree (relptr); + + if (!count) + { + log_info (_("card is permanently locked!\n")); + return gpg_error (GPG_ERR_BAD_PIN); + } + else if (value[6] < 3) + { + log_info (_("verification of Admin PIN is currently prohibited " + "through this command\n")); + return gpg_error (GPG_ERR_GENERAL); + } + + app->did_chv3 = 0; /* Force verification. */ + return verify_chv3 (app, pincb, pincb_arg); + } + else + return verify_chv2 (app, pincb, pincb_arg); } @@ -2415,7 +2469,9 @@ app_openpgp_storekey (app_t app, int keyno, flush_cache (app); - gcry_sexp_release (app->app_local->pk[keyno].key); + xfree (app->app_local->pk[keyno].key); + app->app_local->pk[keyno].key = NULL; + app->app_local->pk[keyno].keylen = 0; app->app_local->pk[keyno].read_done = 0; rc = iso7816_put_data (app->slot, diff --git a/scd/app.c b/scd/app.c index 0625dc8ef..e035e9b89 100644 --- a/scd/app.c +++ b/scd/app.c @@ -489,7 +489,7 @@ app_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode, /* Perform a VERIFY operation without doing anything lese. This may - be used to initialze a the PION cache for long lasting other + be used to initialze a the PIN cache for long lasting other operations. Its use is highly application dependent. */ int app_check_pin (APP app, const char *keyidstr, diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 459060830..13e11e4bc 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -1,5 +1,5 @@ /* ccid-driver.c - USB ChipCardInterfaceDevices driver - * Copyright (C) 2003, 2004 Free Software Foundation, Inc. + * Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. * Written by Werner Koch. * * This file is part of GnuPG. @@ -52,7 +52,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id$ + * $Date$ */ @@ -223,7 +223,7 @@ static unsigned int compute_edc (const unsigned char *data, size_t datalen, int use_crc); static int bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen); static int bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, - size_t *nread, int expected_type, int seqno); + size_t *nread, int expected_type, int seqno, int timeout); /* Convert a little endian stored 4 byte value into an unsigned integer. */ @@ -446,12 +446,20 @@ parse_ccid_descriptor (ccid_driver_t handle, send a frame of n*wMaxPacketSize back to us. Given that wMaxPacketSize is 64 for these readers we set the IFSD to a value lower than that: - 64 - 10 CCID header - 4 T1frame - 2 reserved = 48 */ + 64 - 10 CCID header - 4 T1frame - 2 reserved = 48 + Product Ids: + 0xe001 - SCR 331 + 0x5111 - SCR 331-DI + 0x5115 - SCR 335 + 0xe003 - SPR 532 + */ if (handle->id_vendor == VENDOR_SCM - /* FIXME: check whether it is the same - firmware version for all drivers. */ - && handle->bcd_device < 0x0519 - && handle->max_ifsd > 48) + && handle->max_ifsd > 48 + && ( (handle->id_product == 0xe001 && handle->bcd_device < 0x0516) + ||(handle->id_product == 0x5111 && handle->bcd_device < 0x0620) + ||(handle->id_product == 0x5115 && handle->bcd_device < 0x0519) + ||(handle->id_product == 0xe003 && handle->bcd_device < 0x0504) + )) { DEBUGOUT ("enabling workaround for buggy SCM readers\n"); handle->max_ifsd = 48; @@ -699,9 +707,7 @@ scan_or_find_devices (int readerno, const char *readerid, && ifcdesc->bInterfaceProtocol == 0) || (ifcdesc->bInterfaceClass == 255 && dev->descriptor.idVendor == 0x04e6 - && dev->descriptor.idProduct == 0xe003 - && ifcdesc->bInterfaceSubClass == 1 - && ifcdesc->bInterfaceProtocol == 1))) + && dev->descriptor.idProduct == 0xe003))) { idev = usb_open (dev); if (!idev) @@ -974,11 +980,13 @@ do_close_reader (ccid_driver_t handle) rc = bulk_out (handle, msg, msglen); if (!rc) - bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,seqno); + bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, + seqno, 2000); handle->powered_off = 1; } if (handle->idev) { + usb_reset (handle->idev); usb_release_interface (handle->idev, handle->ifc_no); usb_close (handle->idev); handle->idev = NULL; @@ -1102,10 +1110,10 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen) BUFFER and return the actual read number if bytes in NREAD. SEQNO is the sequence number used to send the request and EXPECTED_TYPE the type of message we expect. Does checks on the ccid - header. Returns 0 on success. */ + header. TIMEOUT is the timeout value in ms. Returns 0 on success. */ static int bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, - size_t *nread, int expected_type, int seqno) + size_t *nread, int expected_type, int seqno, int timeout) { int i, rc; size_t msglen; @@ -1117,9 +1125,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, rc = usb_bulk_read (handle->idev, handle->ep_bulk_in, buffer, length, - 10000 /* ms timeout */ ); - /* Fixme: instead of using a 10 second timeout we should better - handle the timeout here and retry if appropriate. */ + timeout); if (rc < 0) { DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno)); @@ -1175,7 +1181,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, } -/* Note that this fucntion won't return the error codes NO_CARD or +/* Note that this function won't return the error codes NO_CARD or CARD_INACTIVE */ static int send_escape_cmd (ccid_driver_t handle, @@ -1206,7 +1212,8 @@ send_escape_cmd (ccid_driver_t handle, rc = bulk_out (handle, msg, msglen); if (rc) return rc; - rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape, seqno); + rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape, + seqno, 5000); return rc; } @@ -1276,7 +1283,9 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits) unsigned char msg[100]; size_t msglen; unsigned char seqno; + int retries = 0; + retry: msg[0] = PC_to_RDR_GetSlotStatus; msg[5] = 0; /* slot */ msg[6] = seqno = handle->seqno++; @@ -1288,7 +1297,21 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits) rc = bulk_out (handle, msg, 10); if (rc) return rc; - rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, seqno); + rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, + seqno, retries? 1000 : 200); + if (rc == CCID_DRIVER_ERR_CARD_IO_ERROR && retries < 3) + { + if (!retries) + { + fprintf (stderr, "CALLING USB_CLEAR_HALT\n"); + usb_clear_halt (handle->idev, handle->ep_bulk_in); + usb_clear_halt (handle->idev, handle->ep_bulk_out); + } + else + fprintf (stderr, "RETRYING AGIAN\n"); + retries++; + goto retry; + } if (rc && rc != CCID_DRIVER_ERR_NO_CARD && rc != CCID_DRIVER_ERR_CARD_INACTIVE) return rc; @@ -1303,6 +1326,7 @@ ccid_get_atr (ccid_driver_t handle, unsigned char *atr, size_t maxatrlen, size_t *atrlen) { int rc; + int statusbits; unsigned char msg[100]; unsigned char *tpdu; size_t msglen, tpdulen; @@ -1311,6 +1335,15 @@ ccid_get_atr (ccid_driver_t handle, unsigned int edc; int i; + /* First check whether a card is available. */ + rc = ccid_slot_status (handle, &statusbits); + if (rc) + return rc; + if (statusbits == 2) + return CCID_DRIVER_ERR_NO_CARD; + + /* For an inactive and also for an active card, issue the PowerOn + command to get the ATR. */ msg[0] = PC_to_RDR_IccPowerOn; msg[5] = 0; /* slot */ msg[6] = seqno = handle->seqno++; @@ -1323,7 +1356,8 @@ ccid_get_atr (ccid_driver_t handle, rc = bulk_out (handle, msg, msglen); if (rc) return rc; - rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock, seqno); + rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock, + seqno, 5000); if (rc) return rc; @@ -1367,7 +1401,8 @@ ccid_get_atr (ccid_driver_t handle, if (rc) return rc; /* Note that we ignore the error code on purpose. */ - bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, seqno); + bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, + seqno, 5000); handle->t1_ns = 0; handle->t1_nr = 0; @@ -1414,7 +1449,7 @@ ccid_get_atr (ccid_driver_t handle, rc = bulk_in (handle, msg, sizeof msg, &msglen, - RDR_to_PC_DataBlock, seqno); + RDR_to_PC_DataBlock, seqno, 5000); if (rc) return rc; @@ -1510,7 +1545,7 @@ ccid_transceive_apdu_level (ccid_driver_t handle, msg = recv_buffer; rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen, - RDR_to_PC_DataBlock, seqno); + RDR_to_PC_DataBlock, seqno, 5000); if (rc) return rc; @@ -1683,7 +1718,7 @@ ccid_transceive (ccid_driver_t handle, msg = recv_buffer; rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen, - RDR_to_PC_DataBlock, seqno); + RDR_to_PC_DataBlock, seqno, 5000); if (rc) return rc; @@ -1692,7 +1727,7 @@ ccid_transceive (ccid_driver_t handle, if (tpdulen < 4) { - usb_clear_halt (handle->idev, 0x82); + usb_clear_halt (handle->idev, handle->ep_bulk_in); return CCID_DRIVER_ERR_ABORTED; } #ifdef DEBUG_T1 @@ -1960,7 +1995,7 @@ ccid_transceive_secure (ccid_driver_t handle, msg = recv_buffer; rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen, - RDR_to_PC_DataBlock, seqno); + RDR_to_PC_DataBlock, seqno, 5000); if (rc) return rc; diff --git a/scd/command.c b/scd/command.c index 63e3e28e1..ea296b6fb 100644 --- a/scd/command.c +++ b/scd/command.c @@ -108,7 +108,7 @@ do_reset (ctrl_t ctrl, int do_close) static void -reset_notify (ASSUAN_CONTEXT ctx) +reset_notify (assuan_context_t ctx) { CTRL ctrl = assuan_get_pointer (ctx); @@ -117,7 +117,7 @@ reset_notify (ASSUAN_CONTEXT ctx) static int -option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value) +option_handler (assuan_context_t ctx, const char *key, const char *value) { ctrl_t ctrl = assuan_get_pointer (ctx); @@ -248,6 +248,10 @@ cmd_serialno (assuan_context_t ctx, char *line) time_t stamp; /* Clear the remove flag so that the open_card is able to reread it. */ + + /* FIXME: We can't do that if we are in a locked state. Retrun an + appropriate erro r in that case. IF the card has not been + removed we may very well continue. */ if (ctrl->server_local->card_removed) do_reset (ctrl, 0); @@ -333,9 +337,10 @@ cmd_serialno (assuan_context_t ctx, char *line) The URL to be used for locating the entire public key. + Note, that this function may be even be used on a locked card. */ static int -cmd_learn (ASSUAN_CONTEXT ctx, char *line) +cmd_learn (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc = 0; @@ -481,9 +486,10 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) /* READCERT + Note, that this function may be even be used on a locked card. */ static int -cmd_readcert (ASSUAN_CONTEXT ctx, char *line) +cmd_readcert (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; @@ -524,7 +530,10 @@ cmd_readcert (ASSUAN_CONTEXT ctx, char *line) /* READKEY Return the public key for the given cert or key ID as an standard - S-Expression. */ + S-Expression. + + Note, that this function may be even be used on a locked card. + */ static int cmd_readkey (assuan_context_t ctx, char *line) { @@ -619,14 +628,16 @@ cmd_readkey (assuan_context_t ctx, char *line) The client should use this command to tell us the data he want to sign. */ static int -cmd_setdata (ASSUAN_CONTEXT ctx, char *line) +cmd_setdata (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int n; char *p; unsigned char *buf; - /* parse the hexstring */ + /* FIXME: If we are locked return an error. */ + + /* Parse the hexstring. */ for (p=line,n=0; hexdigitp (p); p++, n++) ; if (*p) @@ -652,7 +663,7 @@ cmd_setdata (ASSUAN_CONTEXT ctx, char *line) static int pin_cb (void *opaque, const char *info, char **retstr) { - ASSUAN_CONTEXT ctx = opaque; + assuan_context_t ctx = opaque; char *command; int rc; unsigned char *value; @@ -687,7 +698,7 @@ pin_cb (void *opaque, const char *info, char **retstr) */ static int -cmd_pksign (ASSUAN_CONTEXT ctx, char *line) +cmd_pksign (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; @@ -695,6 +706,8 @@ cmd_pksign (ASSUAN_CONTEXT ctx, char *line) size_t outdatalen; char *keyidstr; + /* FIXME: If we are locked return an error. */ + if ((rc = open_card (ctrl, NULL))) return rc; @@ -738,7 +751,7 @@ cmd_pksign (ASSUAN_CONTEXT ctx, char *line) */ static int -cmd_pkauth (ASSUAN_CONTEXT ctx, char *line) +cmd_pkauth (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; @@ -746,6 +759,8 @@ cmd_pkauth (ASSUAN_CONTEXT ctx, char *line) size_t outdatalen; char *keyidstr; + /* FIXME: If we are locked return an error. */ + if ((rc = open_card (ctrl, NULL))) return rc; @@ -785,7 +800,7 @@ cmd_pkauth (ASSUAN_CONTEXT ctx, char *line) */ static int -cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line) +cmd_pkdecrypt (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; @@ -793,6 +808,8 @@ cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line) size_t outdatalen; char *keyidstr; + /* FIXME: If we are locked return an error. */ + if ((rc = open_card (ctrl, NULL))) return rc; @@ -834,14 +851,15 @@ cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line) This command is used to retrieve data from a smartcard. The allowed names depend on the currently selected smartcard application. NAME must be percent and '+' escaped. The value is - returned through status message, see the LESRN command for details. + returned through status message, see the LEARN command for details. However, the current implementation assumes that Name is not escaped; this works as long as noone uses arbitrary escaping. + Note, that this function may even be used on a locked card. */ static int -cmd_getattr (ASSUAN_CONTEXT ctx, char *line) +cmd_getattr (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; @@ -858,6 +876,8 @@ cmd_getattr (ASSUAN_CONTEXT ctx, char *line) /* (We ignore any garbage for now.) */ + /* FIXME: Applications should not return sensistive data if the card + is locked. */ rc = app_getattr (ctrl->app_ctx, ctrl, keyword); TEST_CARD_REMOVAL (ctrl, rc); @@ -878,7 +898,7 @@ cmd_getattr (ASSUAN_CONTEXT ctx, char *line) setattr function of the actually used application (app-*.c) for details. */ static int -cmd_setattr (ASSUAN_CONTEXT ctx, char *orig_line) +cmd_setattr (assuan_context_t ctx, char *orig_line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; @@ -887,6 +907,8 @@ cmd_setattr (ASSUAN_CONTEXT ctx, char *orig_line) size_t nbytes; char *line, *linebuf; + /* FIXME: If we are locked return an error. */ + if ((rc = open_card (ctrl, NULL))) return rc; @@ -932,13 +954,15 @@ cmd_setattr (ASSUAN_CONTEXT ctx, char *orig_line) */ static int -cmd_genkey (ASSUAN_CONTEXT ctx, char *line) +cmd_genkey (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; char *keyno; int force = has_option (line, "--force"); + /* FIXME: If we are locked return an error. */ + /* Skip over options. */ while ( *line == '-' && line[1] == '-' ) { @@ -974,9 +998,11 @@ cmd_genkey (ASSUAN_CONTEXT ctx, char *line) /* RANDOM Get NBYTES of random from the card and send them back as data. + + Note, that this function may be even be used on a locked card. */ static int -cmd_random (ASSUAN_CONTEXT ctx, char *line) +cmd_random (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; @@ -1016,13 +1042,15 @@ cmd_random (ASSUAN_CONTEXT ctx, char *line) Change the PIN or reset thye retry counter of the card holder verfication vector CHVNO. */ static int -cmd_passwd (ASSUAN_CONTEXT ctx, char *line) +cmd_passwd (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; char *chvnostr; int reset_mode = has_option (line, "--reset"); + /* FIXME: If we are locked return an error. */ + /* Skip over options. */ while (*line == '-' && line[1] == '-') { @@ -1061,12 +1089,14 @@ cmd_passwd (ASSUAN_CONTEXT ctx, char *line) */ static int -cmd_checkpin (ASSUAN_CONTEXT ctx, char *line) +cmd_checkpin (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; char *keyidstr; + /* FIXME: If we are locked return an error. */ + if ((rc = open_card (ctrl, NULL))) return rc;