diff options
Diffstat (limited to 'scd/ccid-driver.c')
-rw-r--r-- | scd/ccid-driver.c | 242 |
1 files changed, 137 insertions, 105 deletions
diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 5b3bcaf9a..e9f39f48c 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, 2007 - * 2008, 2009 Free Software Foundation, Inc. + * 2008, 2009, 2013 Free Software Foundation, Inc. * Written by Werner Koch. * * This file is part of GnuPG. @@ -89,6 +89,8 @@ #include <usb.h> +#include "scdaemon.h" +#include "iso7816.h" #include "ccid-driver.h" #define DRVNAME "ccid-driver: " @@ -207,6 +209,7 @@ enum { VENDOR_SCM = 0x04e6, VENDOR_OMNIKEY= 0x076b, VENDOR_GEMPC = 0x08e6, + VENDOR_VEGA = 0x0982, VENDOR_KAAN = 0x0d46, VENDOR_FSIJ = 0x234b, VENDOR_VASCO = 0x1a44 @@ -220,6 +223,8 @@ enum { #define SCM_SPR532 0xe003 #define CHERRY_ST2000 0x003e #define VASCO_920 0x0920 +#define GEMPC_PINPAD 0x3478 +#define VEGA_ALPHA 0x0008 /* A list and a table with special transport descriptions. */ enum { @@ -2379,7 +2384,7 @@ update_param_by_atr (unsigned char *param, unsigned char *atr, size_t atrlen) NEXTBYTE (); if (atr[i] == 0x3F) - param[1] |= 0x02; /* Convention is inverse. */ + param[1] |= 0x02; /* Convention is inverse. */ NEXTBYTE (); y = (atr[i] >> 4); @@ -2388,91 +2393,91 @@ update_param_by_atr (unsigned char *param, unsigned char *atr, size_t atrlen) if ((y & 1)) { - param[0] = atr[i]; /* TA1 - Fi & Di */ + param[0] = atr[i]; /* TA1 - Fi & Di */ NEXTBYTE (); } if ((y & 2)) - NEXTBYTE (); /* TB1 - ignore */ + NEXTBYTE (); /* TB1 - ignore */ if ((y & 4)) { - param[2] = atr[i]; /* TC1 - Guard Time */ + param[2] = atr[i]; /* TC1 - Guard Time */ NEXTBYTE (); } if ((y & 8)) { - y = (atr[i] >> 4); /* TD1 */ + y = (atr[i] >> 4); /* TD1 */ t = atr[i] & 0x0f; NEXTBYTE (); if ((y & 1)) - { /* TA2 - PPS mode */ - if ((atr[i] & 0x0f) != 1) - return -2; /* Wrong card protocol (!= 1). */ + { /* TA2 - PPS mode */ + if ((atr[i] & 0x0f) != 1) + return -2; /* Wrong card protocol (!= 1). */ - if ((atr[i] & 0x10) != 0x10) - return -3; /* Transmission parameters are implicitly defined. */ + if ((atr[i] & 0x10) != 0x10) + return -3; /* Transmission parameters are implicitly defined. */ - negotiable = 0; /* TA2 means specific mode. */ - NEXTBYTE (); - } + negotiable = 0; /* TA2 means specific mode. */ + NEXTBYTE (); + } if ((y & 2)) - NEXTBYTE (); /* TB2 - ignore */ + NEXTBYTE (); /* TB2 - ignore */ if ((y & 4)) - NEXTBYTE (); /* TC2 - ignore */ + NEXTBYTE (); /* TC2 - ignore */ if ((y & 8)) - { - y = (atr[i] >> 4); /* TD2 */ - t = atr[i] & 0x0f; - NEXTBYTE (); - } + { + y = (atr[i] >> 4); /* TD2 */ + t = atr[i] & 0x0f; + NEXTBYTE (); + } else - y = 0; + y = 0; while (y) - { - if ((y & 1)) - { /* TAx */ - if (t == 1) - param[5] = atr[i]; /* IFSC */ - else if (t == 15) - /* XXX: check voltage? */ - param[4] = (atr[i] >> 6); /* ClockStop */ - - NEXTBYTE (); - } - - if ((y & 2)) - { - if (t == 1) - param[3] = atr[i]; /* TBx - BWI & CWI */ - NEXTBYTE (); - } - - if ((y & 4)) - { - if (t == 1) - param[1] |= (atr[i] & 0x01); /* TCx - LRC/CRC */ - NEXTBYTE (); - - if (param[1] & 0x01) - return -4; /* CRC not supported yet. */ - } - - if ((y & 8)) - { - y = (atr[i] >> 4); /* TDx */ - t = atr[i] & 0x0f; - NEXTBYTE (); - } - else - y = 0; - } + { + if ((y & 1)) + { /* TAx */ + if (t == 1) + param[5] = atr[i]; /* IFSC */ + else if (t == 15) + /* XXX: check voltage? */ + param[4] = (atr[i] >> 6); /* ClockStop */ + + NEXTBYTE (); + } + + if ((y & 2)) + { + if (t == 1) + param[3] = atr[i]; /* TBx - BWI & CWI */ + NEXTBYTE (); + } + + if ((y & 4)) + { + if (t == 1) + param[1] |= (atr[i] & 0x01); /* TCx - LRC/CRC */ + NEXTBYTE (); + + if (param[1] & 0x01) + return -4; /* CRC not supported yet. */ + } + + if ((y & 8)) + { + y = (atr[i] >> 4); /* TDx */ + t = atr[i] & 0x0f; + NEXTBYTE (); + } + else + y = 0; + } } i += historical_bytes_num - 1; @@ -2601,16 +2606,16 @@ ccid_get_atr (ccid_driver_t handle, msglen = 10; rc = bulk_out (handle, msg, msglen, 0); if (!rc) - rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, - seqno, 2000, 0); + rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, + seqno, 2000, 0); if (rc) - DEBUGOUT ("GetParameters failed\n"); + DEBUGOUT ("GetParameters failed\n"); else if (msglen == 17 && msg[9] == 1) - got_param = 1; + got_param = 1; } else if (handle->auto_pps) ; - else if (rc == 1) /* It's negotiable, send PPS. */ + else if (rc == 1) /* It's negotiable, send PPS. */ { msg[0] = PC_to_RDR_XfrBlock; msg[5] = 0; /* slot */ @@ -2618,33 +2623,33 @@ ccid_get_atr (ccid_driver_t handle, msg[7] = 0; msg[8] = 0; msg[9] = 0; - msg[10] = 0xff; /* PPSS */ - msg[11] = 0x11; /* PPS0: PPS1, Protocol T=1 */ - msg[12] = param[0]; /* PPS1: Fi / Di */ + msg[10] = 0xff; /* PPSS */ + msg[11] = 0x11; /* PPS0: PPS1, Protocol T=1 */ + msg[12] = param[0]; /* PPS1: Fi / Di */ msg[13] = 0xff ^ 0x11 ^ param[0]; /* PCK */ set_msg_len (msg, 4); msglen = 10 + 4; rc = bulk_out (handle, msg, msglen, 0); if (rc) - return rc; + return rc; rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock, - seqno, 5000, 0); + seqno, 5000, 0); if (rc) - return rc; + return rc; if (msglen != 10 + 4) - { - DEBUGOUT_1 ("Setting PPS failed: %d\n", msglen); - return CCID_DRIVER_ERR_CARD_IO_ERROR; - } + { + DEBUGOUT_1 ("Setting PPS failed: %d\n", msglen); + return CCID_DRIVER_ERR_CARD_IO_ERROR; + } if (msg[10] != 0xff || msg[11] != 0x11 || msg[12] != param[0]) - { - DEBUGOUT_1 ("Setting PPS failed: 0x%02x\n", param[0]); - return CCID_DRIVER_ERR_CARD_IO_ERROR; - } + { + DEBUGOUT_1 ("Setting PPS failed: 0x%02x\n", param[0]); + return CCID_DRIVER_ERR_CARD_IO_ERROR; + } } /* Setup parameters to select T=1. */ @@ -3287,7 +3292,7 @@ ccid_transceive (ccid_driver_t handle, The APDU should me made up of 4 bytes without Lc. PINLEN_MIN and PINLEN_MAX define the limits for the pin length. 0 - may be used t enable reasonable defaults. PIN_PADLEN should be 0. + may be used t enable reasonable defaults. When called with RESP and NRESP set to NULL, the function will merely check whether the reader supports the secure command for the @@ -3295,8 +3300,7 @@ ccid_transceive (ccid_driver_t handle, int ccid_transceive_secure (ccid_driver_t handle, const unsigned char *apdu_buf, size_t apdu_buflen, - int pin_mode, int pinlen_min, int pinlen_max, - int pin_padlen, + pininfo_t *pininfo, unsigned char *resp, size_t maxresplen, size_t *nresp) { int rc; @@ -3307,6 +3311,7 @@ ccid_transceive_secure (ccid_driver_t handle, size_t dummy_nresp; int testmode; int cherry_mode = 0; + int enable_varlen = 0; testmode = !resp && !nresp; @@ -3321,21 +3326,15 @@ ccid_transceive_secure (ccid_driver_t handle, else return CCID_DRIVER_ERR_NO_KEYPAD; - if (pin_mode != 1) - return CCID_DRIVER_ERR_NOT_SUPPORTED; - - if (pin_padlen != 0) - return CCID_DRIVER_ERR_NOT_SUPPORTED; - - if (!pinlen_min) - pinlen_min = 1; - if (!pinlen_max) - pinlen_max = 25; + if (!pininfo->minlen) + pininfo->minlen = 1; + if (!pininfo->maxlen) + pininfo->maxlen = 25; /* Note that the 25 is the maximum value the SPR532 allows. */ - if (pinlen_min < 1 || pinlen_min > 25 - || pinlen_max < 1 || pinlen_max > 25 - || pinlen_min > pinlen_max) + if (pininfo->minlen < 1 || pininfo->minlen > 25 + || pininfo->maxlen < 1 || pininfo->maxlen > 25 + || pininfo->minlen > pininfo->maxlen) return CCID_DRIVER_ERR_INV_VALUE; /* We have only tested a few readers so better don't risk anything @@ -3345,11 +3344,14 @@ ccid_transceive_secure (ccid_driver_t handle, case VENDOR_SCM: /* Tested with SPR 532. */ case VENDOR_KAAN: /* Tested with KAAN Advanced (1.02). */ case VENDOR_FSIJ: /* Tested with the gnuk code (2011-01-05). */ + enable_varlen = 1; break; case VENDOR_VASCO: /* Tested with DIGIPASS 920 */ - pinlen_max = 15; + enable_varlen = 1; + pininfo->maxlen = 15; break; case VENDOR_CHERRY: + enable_varlen = 1; /* 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 @@ -3361,12 +3363,28 @@ ccid_transceive_secure (ccid_driver_t handle, cherry_mode = 1; break; default: + if ((handle->id_vendor == VENDOR_GEMPC && + handle->id_product == GEMPC_PINPAD) + || (handle->id_vendor == VENDOR_VEGA && + handle->id_product == VEGA_ALPHA)) + { + enable_varlen = 0; + pininfo->minlen = 4; + pininfo->maxlen = 8; + break; + } return CCID_DRIVER_ERR_NOT_SUPPORTED; } + if (enable_varlen) + pininfo->fixedlen = 0; + if (testmode) return 0; /* Success */ + if (pininfo->fixedlen < 0 || pininfo->fixedlen >= 16) + return CCID_DRIVER_ERR_NOT_SUPPORTED; + msg = send_buffer; if (handle->id_vendor == VENDOR_SCM) { @@ -3396,9 +3414,9 @@ ccid_transceive_secure (ccid_driver_t handle, } else { - msg[13] = 0x00; /* bmPINBlockString: - 0 bits of pin length to insert. - 0 bytes of PIN block size. */ + msg[13] = pininfo->fixedlen; /* bmPINBlockString: + 0 bits of pin length to insert. + PIN block size by fixedlen. */ msg[14] = 0x00; /* bmPINLengthFormat: Units are bytes, position is 0. */ } @@ -3407,12 +3425,12 @@ ccid_transceive_secure (ccid_driver_t handle, if (apdu_buf[1] == 0x24) { msg[msglen++] = 0; /* bInsertionOffsetOld */ - msg[msglen++] = 0; /* bInsertionOffsetNew */ + msg[msglen++] = pininfo->fixedlen; /* bInsertionOffsetNew */ } /* The following is a little endian word. */ - msg[msglen++] = pinlen_max; /* wPINMaxExtraDigit-Maximum. */ - msg[msglen++] = pinlen_min; /* wPINMaxExtraDigit-Minimum. */ + msg[msglen++] = pininfo->maxlen; /* wPINMaxExtraDigit-Maximum. */ + msg[msglen++] = pininfo->minlen; /* wPINMaxExtraDigit-Minimum. */ if (apdu_buf[1] == 0x24) msg[msglen++] = apdu_buf[2] == 0 ? 0x03 : 0x01; @@ -3425,12 +3443,12 @@ ccid_transceive_secure (ccid_driver_t handle, msg[msglen] = 0x02; /* bEntryValidationCondition: Validation key pressed */ - if (pinlen_min && pinlen_max && pinlen_min == pinlen_max) + if (pininfo->minlen && pininfo->maxlen && pininfo->minlen == pininfo->maxlen) msg[msglen] |= 0x01; /* Max size reached. */ msglen++; if (apdu_buf[1] == 0x20) - msg[msglen++] = 0xff; /* bNumberMessage: Default. */ + msg[msglen++] = 0x01; /* bNumberMessage. */ else msg[msglen++] = 0x03; /* bNumberMessage. */ @@ -3446,10 +3464,18 @@ ccid_transceive_secure (ccid_driver_t handle, msg[msglen++] = 2; /* bMsgIndex3. */ } + /* Calculate Lc. */ + n = pininfo->fixedlen; + if (apdu_buf[1] == 0x24) + n += pininfo->fixedlen; + /* bTeoProlog follows: */ msg[msglen++] = handle->nonnull_nad? ((1 << 4) | 0): 0; msg[msglen++] = ((handle->t1_ns & 1) << 6); /* I-block */ - msg[msglen++] = 0; /* The apdulen will be filled in by the reader. */ + if (n) + msg[msglen++] = n + 5; /* apdulen should be filled for fixed length. */ + else + msg[msglen++] = 0; /* The apdulen will be filled in by the reader. */ /* APDU follows: */ msg[msglen++] = apdu_buf[0]; /* CLA */ msg[msglen++] = apdu_buf[1]; /* INS */ @@ -3457,6 +3483,12 @@ ccid_transceive_secure (ccid_driver_t handle, msg[msglen++] = apdu_buf[3]; /* P2 */ if (cherry_mode) msg[msglen++] = 0; + else if (pininfo->fixedlen != 0) + { + msg[msglen++] = n; + memset (&msg[msglen], 0xff, n); + msglen += n; + } /* An EDC is not required. */ set_msg_len (msg, msglen - 10); |