diff options
Diffstat (limited to 'scd')
-rw-r--r-- | scd/ChangeLog | 11 | ||||
-rw-r--r-- | scd/apdu.c | 2 | ||||
-rw-r--r-- | scd/app-dinsig.c | 62 | ||||
-rw-r--r-- | scd/app-nks.c | 69 | ||||
-rw-r--r-- | scd/ccid-driver.c | 47 |
5 files changed, 136 insertions, 55 deletions
diff --git a/scd/ChangeLog b/scd/ChangeLog index 38ef4f234..571457576 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,14 @@ +2007-03-07 Werner Koch <[email protected]> + + * app-dinsig.c: Include i18n.h. + (verify_pin): Support PIN pads. + * app-nks.c (verify_pin): Ditto. + + * ccid-driver.c (bulk_in): Handle time extension before checking + the message type. + (ccid_transceive_secure): Support the Cherry XX44 keyboard. + Kudos to the nice folks at Cherry for helping with that. + 2007-02-18 Werner Koch <[email protected]> * scdaemon.c (DEFAULT_PCSC_DRIVER): Add a default for OS X. diff --git a/scd/apdu.c b/scd/apdu.c index ac2f3c44b..a45f0a3e9 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -90,7 +90,7 @@ #define MAX_OPEN_FDS 20 #endif -/* Helper to pass patrameters related to keypad based operations. */ +/* Helper to pass parameters related to keypad based operations. */ struct pininfo_s { int mode; diff --git a/scd/app-dinsig.c b/scd/app-dinsig.c index 5cab42805..981568804 100644 --- a/scd/app-dinsig.c +++ b/scd/app-dinsig.c @@ -1,5 +1,5 @@ /* app-dinsig.c - The DINSIG (DIN V 66291-1) card application. - * Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + * Copyright (C) 2002, 2004, 2005, 2007 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -81,6 +81,7 @@ #include "scdaemon.h" +#include "i18n.h" #include "iso7816.h" #include "app-common.h" #include "tlv.h" @@ -279,11 +280,37 @@ verify_pin (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { - if (!app->did_chv1 || app->force_chv1 ) + const char *s; + int rc; + iso7816_pininfo_t pininfo; + + if ( app->did_chv1 && !app->force_chv1 ) + return 0; /* No need to verify it again. */ + + memset (&pininfo, 0, sizeof pininfo); + pininfo.mode = 1; + pininfo.minlen = 6; + pininfo.maxlen = 8; + + if (!opt.disable_keypad + && !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo) ) + { + rc = pincb (pincb_arg, + _("||Please enter your PIN at the reader's keypad"), + NULL); + if (rc) + { + log_info (_("PIN callback returned error: %s\n"), + gpg_strerror (rc)); + return rc; + } + rc = iso7816_verify_kp (app->slot, 0x81, "", 0, &pininfo); + /* Dismiss the prompt. */ + pincb (pincb_arg, NULL, NULL); + } + else /* No Keypad. */ { - const char *s; char *pinvalue; - int rc; rc = pincb (pincb_arg, "PIN", &pinvalue); if (rc) @@ -303,15 +330,17 @@ verify_pin (app_t app, return gpg_error (GPG_ERR_BAD_PIN); } - if (strlen (pinvalue) < 6) + if (strlen (pinvalue) < pininfo.minlen) { - log_error ("PIN is too short; minimum length is 6\n"); + log_error ("PIN is too short; minimum length is %d\n", + pininfo.minlen); xfree (pinvalue); return gpg_error (GPG_ERR_BAD_PIN); } - else if (strlen (pinvalue) > 8) + else if (strlen (pinvalue) > pininfo.maxlen) { - log_error ("PIN is too large; maximum length is 8\n"); + log_error ("PIN is too large; maximum length is %d\n", + pininfo.maxlen); xfree (pinvalue); return gpg_error (GPG_ERR_BAD_PIN); } @@ -326,7 +355,7 @@ verify_pin (app_t app, this. */ char paddedpin[8]; int i, ndigits; - + for (ndigits=0, s=pinvalue; *s; ndigits++, s++) ; i = 0; @@ -336,19 +365,18 @@ verify_pin (app_t app, if (i < sizeof paddedpin && *s) paddedpin[i++] = (((*s - '0') << 4) | 0x0f); while (i < sizeof paddedpin) - paddedpin[i++] = 0xff; + paddedpin[i++] = 0xff; rc = iso7816_verify (app->slot, 0x81, paddedpin, sizeof paddedpin); } - if (rc) - { - log_error ("verify PIN failed\n"); - xfree (pinvalue); - return rc; - } - app->did_chv1 = 1; xfree (pinvalue); } + if (rc) + { + log_error ("verify PIN failed\n"); + return rc; + } + app->did_chv1 = 1; return 0; } diff --git a/scd/app-nks.c b/scd/app-nks.c index 3c64fe45b..5feabc1ec 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -1,5 +1,5 @@ /* app-nks.c - The Telesec NKS 2.0 card application. - * Copyright (C) 2004 Free Software Foundation, Inc. + * Copyright (C) 2004, 2007 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -306,14 +306,43 @@ verify_pin (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { + iso7816_pininfo_t pininfo; + int rc; + /* Note that force_chv1 is never set but we do it here anyway so that other applications may reuse this function. For example it makes sense to set force_chv1 for German signature law cards. NKS is very similar to the DINSIG draft standard. */ - if (!app->did_chv1 || app->force_chv1 ) + if ( app->did_chv1 && !app->force_chv1 ) + return 0; /* No need to verify it again. */ + + memset (&pininfo, 0, sizeof pininfo); + pininfo.mode = 1; + pininfo.minlen = 6; + pininfo.maxlen = 16; + + if (!opt.disable_keypad + && !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo) ) + { + rc = pincb (pincb_arg, + _("||Please enter your PIN at the reader's keypad"), + NULL); + if (rc) + { + log_info (_("PIN callback returned error: %s\n"), + gpg_strerror (rc)); + return rc; + } + + /* Although it is possible to use a local PIN, we use the global + PIN for this application. */ + rc = iso7816_verify_kp (app->slot, 0, "", 0, &pininfo); + /* Dismiss the prompt. */ + pincb (pincb_arg, NULL, NULL); + } + else { char *pinvalue; - int rc; rc = pincb (pincb_arg, "PIN", &pinvalue); if (rc) @@ -324,35 +353,37 @@ verify_pin (app_t app, /* The following limits are due to TCOS but also defined in the NKS specs. */ - if (strlen (pinvalue) < 6) + if (strlen (pinvalue) < pininfo.minlen) { - log_error ("PIN is too short; minimum length is 6\n"); + log_error ("PIN is too short; minimum length is %d\n", + pininfo.minlen); xfree (pinvalue); return gpg_error (GPG_ERR_BAD_PIN); } - else if (strlen (pinvalue) > 16) + else if (strlen (pinvalue) > pininfo.maxlen) { - log_error ("PIN is too large; maximum length is 16\n"); + log_error ("PIN is too large; maximum length is %d\n", + pininfo.maxlen); xfree (pinvalue); return gpg_error (GPG_ERR_BAD_PIN); } - /* Also it is possible to use a local PIN, we use the gloabl + /* Although it is possible to use a local PIN, we use the global PIN for this application. */ rc = iso7816_verify (app->slot, 0, pinvalue, strlen (pinvalue)); - if (rc) - { - if ( gpg_error (rc) == GPG_ERR_USE_CONDITIONS ) - log_error (_("the NullPIN has not yet been changed\n")); - else - log_error ("verify PIN failed\n"); - xfree (pinvalue); - return rc; - } - app->did_chv1 = 1; xfree (pinvalue); } + if (rc) + { + if ( gpg_err_code (rc) == GPG_ERR_USE_CONDITIONS ) + log_error (_("the NullPIN has not yet been changed\n")); + else + log_error ("verify PIN failed\n"); + return rc; + } + app->did_chv1 = 1; + return 0; } @@ -457,7 +488,7 @@ do_decipher (app_t app, const char *keyidstr, if (!keyidstr || !*keyidstr || !indatalen) return gpg_error (GPG_ERR_INV_VALUE); - /* Check that the provided ID is vaid. This is not really needed + /* Check that the provided ID is valid. This is not really needed but we do it to to enforce correct usage by the caller. */ if (strncmp (keyidstr, "NKS-DF01.", 9) ) return gpg_error (GPG_ERR_INV_ID); diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index bbb886239..8ad329d67 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -1,6 +1,6 @@ /* ccid-driver.c - USB ChipCardInterfaceDevices driver - * Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. - * Written by Werner Koch. + * Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + * Written by Werner Koch. * * This file is part of GnuPG. * @@ -1458,11 +1458,6 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, DEBUGOUT_1 ("bulk-in msg too short (%u)\n", (unsigned int)msglen); return CCID_DRIVER_ERR_INV_VALUE; } - if (buffer[0] != expected_type) - { - DEBUGOUT_1 ("unexpected bulk-in msg type (%02x)\n", buffer[0]); - return CCID_DRIVER_ERR_INV_VALUE; - } if (buffer[5] != 0) { DEBUGOUT_1 ("unexpected bulk-in slot (%d)\n", buffer[5]); @@ -1475,6 +1470,10 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, return CCID_DRIVER_ERR_INV_VALUE; } + /* We need to handle the time extension request before we check that + we go the expected message type. This is in particular required + for the Cherry keyboard which sends a time extension request for + each key hit. */ if ( !(buffer[7] & 0x03) && (buffer[7] & 0xC0) == 0x80) { /* Card present and active, time extension requested. */ @@ -1483,6 +1482,13 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, goto retry; } + if (buffer[0] != expected_type) + { + DEBUGOUT_1 ("unexpected bulk-in msg type (%02x)\n", buffer[0]); + return CCID_DRIVER_ERR_INV_VALUE; + } + + if (!no_debug) { DEBUGOUT_3 ("status: %02X error: %02X octet[9]: %02X\n" @@ -2330,6 +2336,7 @@ ccid_transceive_secure (ccid_driver_t handle, int i; size_t dummy_nresp; int testmode; + int cherry_mode = 0; testmode = !resp && !nresp; @@ -2368,14 +2375,16 @@ ccid_transceive_secure (ccid_driver_t handle, case VENDOR_SCM: /* Tested with SPR 532. */ case VENDOR_KAAN: /* Tested with KAAN Advanced (1.02). */ break; - /* The CHERRY XX44 does not yet work. I have not investigated it - closer because there is another problem: It echos a "*" for - each entered character and we somehow need to arrange that it - doesn't get to the tty at all. Given that we are running - without a control terminal there is not much we can do about. - A weird hack using pinentry comes in mind but I doubt that - this is a clean solution. Need to contact Cherry. - */ + case VENDOR_CHERRY: + /* The CHERRY XX44 keyboard echos an asterisk for each entered + character on the keyboard channel. We use a special variant + of PC_to_RDR_Secure which directs these characters to the + smart card's bulk-in channel. We also need to append a zero + Lc byte to the APDU. It seems that it will be replaced with + the actual length instead of being appended before the APDU + is send to the card. */ + cherry_mode = 1; + break; default: return CCID_DRIVER_ERR_NOT_SUPPORTED; } @@ -2393,7 +2402,7 @@ ccid_transceive_secure (ccid_driver_t handle, return rc; } - msg[0] = PC_to_RDR_Secure; + msg[0] = cherry_mode? 0x89 : PC_to_RDR_Secure; msg[5] = 0; /* slot */ msg[6] = seqno = handle->seqno++; msg[7] = 0; /* bBWI */ @@ -2405,7 +2414,7 @@ ccid_transceive_secure (ccid_driver_t handle, if (handle->id_vendor == VENDOR_SCM) { /* For the SPR532 the next 2 bytes need to be zero. We do this - for all SCM product. Kudos to Martin Paljak for this + for all SCM products. Kudos to Martin Paljak for this hint. */ msg[13] = msg[14] = 0; } @@ -2419,7 +2428,7 @@ ccid_transceive_secure (ccid_driver_t handle, } /* The following is a little endian word. */ - msg[15] = pinlen_max; /* wPINMaxExtraDigit-Maximum. */ + msg[15] = pinlen_max; /* wPINMaxExtraDigit-Maximum. */ msg[16] = pinlen_min; /* wPINMaxExtraDigit-Minimum. */ msg[17] = 0x02; /* bEntryValidationCondition: @@ -2440,6 +2449,8 @@ ccid_transceive_secure (ccid_driver_t handle, msg[27] = apdu_buf[2]; /* P1 */ msg[28] = apdu_buf[3]; /* P2 */ msglen = 29; + if (cherry_mode) + msg[msglen++] = 0; /* An EDC is not required. */ set_msg_len (msg, msglen - 10); |