aboutsummaryrefslogtreecommitdiffstats
path: root/scd/ccid-driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'scd/ccid-driver.c')
-rw-r--r--scd/ccid-driver.c242
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);