scd: Make SPRx32 pinpad work with PC/SC on Windows.
authorWerner Koch <wk@gnupg.org>
Wed, 21 Aug 2013 14:45:48 +0000 (16:45 +0200)
committerWerner Koch <wk@gnupg.org>
Wed, 21 Aug 2013 14:47:44 +0000 (16:47 +0200)
* scd/apdu.c (CM_IOCTL_GET_FEATURE_REQUEST): Use SCARD_CTL_CODE.
(SCARD_CTL_CODE): Define if not defined.
(reader_table_s): Add is_spr532.
(new_reader_slot): Clear it.
(check_pcsc_pinpad): Set it.
(pcsc_pinpad_verify, pcsc_pinpad_modify): Add fix for SPR532.

Signed-off-by: Werner Koch <wk@gnupg.org>
(cherry picked from commit 5c5e52df4b92e23045ac87abac09357de58920d4)

scd/apdu.c

index 4b3509e..ecb3e82 100644 (file)
@@ -133,6 +133,7 @@ struct reader_table_s {
   int last_status;
   int status;
   int is_t0;         /* True if we know that we are running T=0. */
+  int is_spr532;     /* True if we know that the reader is a SPR532.  */
   unsigned char atr[33];
   size_t atrlen;           /* A zero length indicates that the ATR has
                               not yet been read; i.e. the card is not
@@ -219,7 +220,12 @@ static char (* DLSTDCALL CT_close) (unsigned short ctn);
 #define PCSC_E_NO_SERVICE              0x8010001D
 #define PCSC_W_REMOVED_CARD            0x80100069
 
-#define CM_IOCTL_GET_FEATURE_REQUEST (0x42000000 + 3400)
+/* Fix pcsc-lite ABI incompatibilty.  */
+#ifndef SCARD_CTL_CODE
+# define SCARD_CTL_CODE(code) (0x42000000 + (code))
+#endif
+
+#define CM_IOCTL_GET_FEATURE_REQUEST     SCARD_CTL_CODE(3400)
 #define FEATURE_VERIFY_PIN_DIRECT        0x06
 #define FEATURE_MODIFY_PIN_DIRECT        0x07
 
@@ -417,6 +423,7 @@ new_reader_slot (void)
   reader_table[reader].any_status = 0;
   reader_table[reader].last_status = 0;
   reader_table[reader].is_t0 = 1;
+  reader_table[reader].is_spr532 = 0;
 #ifdef NEED_PCSC_WRAPPER
   reader_table[reader].pcsc.req_fd = -1;
   reader_table[reader].pcsc.rsp_fd = -1;
@@ -2038,7 +2045,10 @@ check_pcsc_pinpad (int slot, int command, pininfo_t *pininfo)
      Alternatively use the USB ids to detect known readers.  */
   if (reader_table[slot].rdrname
       && strstr (reader_table[slot].rdrname, "SPRx32"))
-    pininfo->fixedlen = 0;
+    {
+      reader_table[slot].is_spr532 = 1;
+      pininfo->fixedlen = 0;
+    }
 
  check_again:
   if (command == ISO7816_VERIFY)
@@ -2097,6 +2107,7 @@ pcsc_pinpad_verify (int slot, int class, int ins, int p0, int p1,
   int len = PIN_VERIFY_STRUCTURE_SIZE + pininfo->fixedlen;
   unsigned char result[2];
   pcsc_dword_t resultlen = 2;
+  int no_lc;
 
   if (!reader_table[slot].atrlen
       && (sw = reset_pcsc_reader (slot)))
@@ -2120,6 +2131,8 @@ pcsc_pinpad_verify (int slot, int class, int ins, int p0, int p1,
   if (!pin_verify)
     return SW_HOST_OUT_OF_CORE;
 
+  no_lc = (!pininfo->fixedlen && reader_table[slot].is_spr532);
+
   pin_verify[0] = 0x00; /* bTimerOut */
   pin_verify[1] = 0x00; /* bTimerOut2 */
   pin_verify[2] = 0x82; /* bmFormatString: Byte, pos=0, left, ASCII. */
@@ -2136,8 +2149,8 @@ pcsc_pinpad_verify (int slot, int class, int ins, int p0, int p1,
   pin_verify[11] = 0x00; /* bMsgIndex */
   pin_verify[12] = 0x00; /* bTeoPrologue[0] */
   pin_verify[13] = 0x00; /* bTeoPrologue[1] */
-  pin_verify[14] = pininfo->fixedlen + 0x05; /* bTeoPrologue[2] */
-  pin_verify[15] = pininfo->fixedlen + 0x05; /* ulDataLength */
+  pin_verify[14] = pininfo->fixedlen + 0x05 - no_lc; /* bTeoPrologue[2] */
+  pin_verify[15] = pininfo->fixedlen + 0x05 - no_lc; /* ulDataLength */
   pin_verify[16] = 0x00; /* ulDataLength */
   pin_verify[17] = 0x00; /* ulDataLength */
   pin_verify[18] = 0x00; /* ulDataLength */
@@ -2148,6 +2161,8 @@ pcsc_pinpad_verify (int slot, int class, int ins, int p0, int p1,
   pin_verify[23] = pininfo->fixedlen; /* abData[4] */
   if (pininfo->fixedlen)
     memset (&pin_verify[24], 0xff, pininfo->fixedlen);
+  else if (no_lc)
+    len--;
 
   if (DBG_CARD_IO)
     log_debug ("send secure: c=%02X i=%02X p1=%02X p2=%02X len=%d pinmax=%d\n",
@@ -2178,6 +2193,7 @@ pcsc_pinpad_modify (int slot, int class, int ins, int p0, int p1,
   int len = PIN_MODIFY_STRUCTURE_SIZE + 2 * pininfo->fixedlen;
   unsigned char result[2];
   pcsc_dword_t resultlen = 2;
+  int no_lc;
 
   if (!reader_table[slot].atrlen
       && (sw = reset_pcsc_reader (slot)))
@@ -2201,6 +2217,8 @@ pcsc_pinpad_modify (int slot, int class, int ins, int p0, int p1,
   if (!pin_modify)
     return SW_HOST_OUT_OF_CORE;
 
+  no_lc = (!pininfo->fixedlen && reader_table[slot].is_spr532);
+
   pin_modify[0] = 0x00; /* bTimerOut */
   pin_modify[1] = 0x00; /* bTimerOut2 */
   pin_modify[2] = 0x82; /* bmFormatString: Byte, pos=0, left, ASCII. */
@@ -2221,15 +2239,15 @@ pcsc_pinpad_modify (int slot, int class, int ins, int p0, int p1,
   if (pininfo->minlen && pininfo->maxlen && pininfo->minlen == pininfo->maxlen)
     pin_modify[10] |= 0x01; /* Max size reached.  */
   pin_modify[11] = 0xff; /* bNumberMessage: Default */
-  pin_modify[12] =  0x09; /* wLangId: 0x0409: US English */
+  pin_modify[12] = 0x09; /* wLangId: 0x0409: US English */
   pin_modify[13] = 0x04; /* wLangId: 0x0409: US English */
   pin_modify[14] = 0x00; /* bMsgIndex1 */
   pin_modify[15] = 0x00; /* bMsgIndex2 */
   pin_modify[16] = 0x00; /* bMsgIndex3 */
   pin_modify[17] = 0x00; /* bTeoPrologue[0] */
   pin_modify[18] = 0x00; /* bTeoPrologue[1] */
-  pin_modify[19] = 2 * pininfo->fixedlen + 0x05; /* bTeoPrologue[2] */
-  pin_modify[20] = 2 * pininfo->fixedlen + 0x05; /* ulDataLength */
+  pin_modify[19] = 2 * pininfo->fixedlen + 0x05 - no_lc; /* bTeoPrologue[2] */
+  pin_modify[20] = 2 * pininfo->fixedlen + 0x05 - no_lc; /* ulDataLength */
   pin_modify[21] = 0x00; /* ulDataLength */
   pin_modify[22] = 0x00; /* ulDataLength */
   pin_modify[23] = 0x00; /* ulDataLength */
@@ -2240,6 +2258,8 @@ pcsc_pinpad_modify (int slot, int class, int ins, int p0, int p1,
   pin_modify[28] = 2 * pininfo->fixedlen; /* abData[4] */
   if (pininfo->fixedlen)
     memset (&pin_modify[29], 0xff, 2 * pininfo->fixedlen);
+  else if (no_lc)
+    len--;
 
   if (DBG_CARD_IO)
     log_debug ("send secure: c=%02X i=%02X p1=%02X p2=%02X len=%d pinmax=%d\n",