Fixed the card removed with cached app bug. (Famous last fix).
[gnupg.git] / scd / ccid-driver.c
index 1b04a0a..57e617a 100644 (file)
@@ -1,12 +1,12 @@
 /* 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.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -15,9 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  *
  * ALTERNATIVELY, this file may be distributed under the terms of the
  * following license, in which case the provisions of this license are
@@ -200,7 +198,8 @@ enum {
   VENDOR_CHERRY = 0x046a,
   VENDOR_SCM    = 0x04e6,
   VENDOR_OMNIKEY= 0x076b,
-  VENDOR_GEMPC  = 0x08e6
+  VENDOR_GEMPC  = 0x08e6,
+  VENDOR_KAAN   = 0x0d46
 };
 
 /* A list and a table with special transport descriptions. */
@@ -283,7 +282,7 @@ set_msg_len (unsigned char *msg, unsigned int length)
 
 
 /* Pint an error message for a failed CCID command including a textual
-   error code.  MSG is shall be the CCID message of at least 10 bytes. */
+   error code.  MSG shall be the CCID message at a minimum of 10 bytes. */
 static void
 print_command_failed (const unsigned char *msg)
 {
@@ -347,10 +346,6 @@ prepare_special_transport (ccid_driver_t handle)
     {
     case TRANSPORT_CM4040:
       DEBUGOUT ("setting up transport for CardMan 4040\n");
-      /* Most values are guessed. */
-      handle->nonnull_nad = 1;
-      handle->auto_ifsd = 1;
-      handle->max_ifsd = 254;
       handle->apdu_level = 1;
       break;
 
@@ -877,8 +872,6 @@ scan_or_find_usb_device (int scan_mode,
    The function returns 0 if a reader has been found or when a scan
    returned without error.
 
-   FIXME!!
-
    With READERNO = -1 and READERID is NULL, scan mode is used and
    R_RID should be the address where to store the list of reader_ids
    we found.  If on return this list is empty, no CCID device has been
@@ -994,13 +987,24 @@ scan_or_find_devices (int readerno, const char *readerid,
       char *rid, *p;
 
       fd = open (transports[i].name, O_RDWR);
-      if (fd == -1)
-        continue;
+      if (fd == -1 && scan_mode && errno == EBUSY)
+        {
+          /* Ignore this error in scan mode because it indicates that
+             the device exists but is already open (most likely by us)
+             and thus in general suitable as a reader.  */
+        }
+      else if (fd == -1)
+        {
+          DEBUGOUT_2 ("failed to open `%s': %s\n",
+                     transports[i].name, strerror (errno));
+          continue;
+        }
 
       rid = malloc (strlen (transports[i].name) + 30 + 10);
       if (!rid)
         {
-          close (fd);
+          if (fd != -1)
+            close (fd);
           free (rid_list);
           return -1; /* Error. */
         }
@@ -1011,7 +1015,8 @@ scan_or_find_devices (int readerno, const char *readerid,
           p = malloc ((rid_list? strlen (rid_list):0) + 1 + strlen (rid) + 1);
           if (!p)
             {
-              close (fd);
+              if (fd != -1)
+                close (fd);
               free (rid_list);
               free (rid);
               return -1; /* Error. */
@@ -1037,7 +1042,8 @@ scan_or_find_devices (int readerno, const char *readerid,
             *r_rid = rid;
           else
             free (rid);
-          *r_fd = fd;
+          if (r_fd)
+            *r_fd = fd;
           return 0; /* Okay, found device */
         }
       else /* This is not yet the reader we want. */
@@ -1046,7 +1052,8 @@ scan_or_find_devices (int readerno, const char *readerid,
             --readerno;
         }
       free (rid);
-      close (fd);
+      if (fd != -1)
+        close (fd);
     }
 
   if (scan_mode)
@@ -1332,7 +1339,7 @@ ccid_shutdown_reader (ccid_driver_t handle)
 int 
 ccid_close_reader (ccid_driver_t handle)
 {
-  if (!handle || !handle->idev)
+  if (!handle || (!handle->idev && handle->dev_fd == -1))
     return 0;
 
   do_close_reader (handle);
@@ -1346,7 +1353,7 @@ ccid_close_reader (ccid_driver_t handle)
 int
 ccid_check_card_presence (ccid_driver_t handle)
 {
-
+  (void)handle;  /* Not yet implemented.  */
   return -1;
 }
 
@@ -1458,11 +1465,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 +1477,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 +1489,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"
@@ -1694,6 +1707,8 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits)
 }
 
 
+/* Return the ATR of the card.  This is not a cached value and thus an
+   actual reset is done.  */
 int 
 ccid_get_atr (ccid_driver_t handle,
               unsigned char *atr, size_t maxatrlen, size_t *atrlen)
@@ -1708,6 +1723,7 @@ ccid_get_atr (ccid_driver_t handle,
   unsigned int edc;
   int i;
   int tried_iso = 0;
+  int got_param;
 
   /* First check whether a card is available.  */
   rc = ccid_slot_status (handle, &statusbits);
@@ -1764,6 +1780,44 @@ ccid_get_atr (ccid_driver_t handle,
       *atrlen = n;
     }
 
+  got_param = 0;
+  msg[0] = PC_to_RDR_GetParameters;
+  msg[5] = 0; /* slot */
+  msg[6] = seqno = handle->seqno++;
+  msg[7] = 0; /* RFU */
+  msg[8] = 0; /* RFU */
+  msg[9] = 0; /* RFU */
+  set_msg_len (msg, 0);
+  msglen = 10;
+  rc = bulk_out (handle, msg, msglen);
+  if (!rc)
+    rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters,
+                  seqno, 2000, 0);
+  if (rc)
+    DEBUGOUT ("GetParameters failed\n");
+  else
+    {
+      DEBUGOUT ("GetParametes returned");
+      for (i=0; i < msglen; i++)
+        DEBUGOUT_CONT_1 (" %02X", msg[i]);
+      DEBUGOUT_LF ();
+      if (msglen >= 10)
+        {
+          DEBUGOUT_1 ("  protocol ..........: T=%d\n", msg[9]);
+          if (msglen == 17 && msg[9] == 1)
+            {
+              DEBUGOUT_1 ("  bmFindexDindex ....: %02X\n", msg[10]);
+              DEBUGOUT_1 ("  bmTCCKST1 .........: %02X\n", msg[11]);
+              DEBUGOUT_1 ("  bGuardTimeT1 ......: %02X\n", msg[12]);
+              DEBUGOUT_1 ("  bmWaitingIntegersT1: %02X\n", msg[13]);
+              DEBUGOUT_1 ("  bClockStop ........: %02X\n", msg[14]);
+              DEBUGOUT_1 ("  bIFSC .............: %d\n", msg[15]);
+              DEBUGOUT_1 ("  bNadValue .........: %d\n", msg[16]);
+              got_param = 1;
+            }
+        }
+    }
+
   /* Setup parameters to select T=1. */
   msg[0] = PC_to_RDR_SetParameters;
   msg[5] = 0; /* slot */
@@ -1772,14 +1826,17 @@ ccid_get_atr (ccid_driver_t handle,
   msg[8] = 0; /* RFU */
   msg[9] = 0; /* RFU */
 
-  /* FIXME: Get those values from the ATR. */
-  msg[10]= 0x01; /* Fi/Di */
-  msg[11]= 0x10; /* LRC, direct convention. */
-  msg[12]= 0;    /* Extra guardtime. */
-  msg[13]= 0x41; /* BWI/CWI */
-  msg[14]= 0;    /* No clock stoppping. */
-  msg[15]= 254;  /* IFSC */
-  msg[16]= 0;    /* Does not support non default NAD values. */
+  if (!got_param)
+    {
+      /* FIXME: Get those values from the ATR. */
+      msg[10]= 0x01; /* Fi/Di */
+      msg[11]= 0x10; /* LRC, direct convention. */
+      msg[12]= 0;    /* Extra guardtime. */
+      msg[13]= 0x41; /* BWI/CWI */
+      msg[14]= 0;    /* No clock stoppping. */
+      msg[15]= 254;  /* IFSC */
+      msg[16]= 0;    /* Does not support non default NAD values. */
+    }
   set_msg_len (msg, 7);
   msglen = 10 + 7;
 
@@ -1791,15 +1848,16 @@ ccid_get_atr (ccid_driver_t handle,
   rc = bulk_out (handle, msg, msglen);
   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, 5000, 0);
+  rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters,
+                seqno, 5000, 0);
+  if (rc)
+    DEBUGOUT ("SetParameters failed (ignored)\n");
 
   handle->t1_ns = 0;
   handle->t1_nr = 0;
 
-  /* Send an S-Block with our maximun IFSD to the CCID.  */
-  if (!handle->auto_ifsd)
+  /* Send an S-Block with our maximum IFSD to the CCID.  */
+  if (!handle->apdu_level && !handle->auto_ifsd)
     {
       tpdu = msg+10;
       /* NAD: DAD=1, SAD=0 */
@@ -1900,7 +1958,7 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
                             size_t *nresp)
 {
   int rc;
-  unsigned char send_buffer[10+259], recv_buffer[10+259];
+  unsigned char send_buffer[10+261], recv_buffer[10+261];
   const unsigned char *apdu;
   size_t apdulen;
   unsigned char *msg;
@@ -1914,7 +1972,10 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
   apdulen = apdu_buflen;
   assert (apdulen);
 
-  if (apdulen > 254)
+  /* The maximum length for a short APDU T=1 block is 261.  For an
+     extended APDU T=1 block the maximum length 65544; however
+     extended APDU exchange levele is not yet supported.  */
+  if (apdulen > 261)
     return CCID_DRIVER_ERR_INV_VALUE; /* Invalid length. */
 
   msg[0] = PC_to_RDR_XfrBlock;
@@ -2060,7 +2121,11 @@ ccid_transceive (ccid_driver_t handle,
           assert (apdulen);
 
           /* Construct an I-Block. */
-          if (apdulen > 254)
+          /* Fixme: I am not sure whether limiting the length to 259
+             as per CCID spec is required.  The code blow chops the
+             APDU anyway into 128 byte blocks.  Needs to be addressed
+             when supporting extended length APDUs. */
+          if (apdulen > 259)
             return CCID_DRIVER_ERR_INV_VALUE; /* Invalid length. */
 
           tpdu = msg+10;
@@ -2286,6 +2351,7 @@ ccid_transceive_secure (ccid_driver_t handle,
   int i;
   size_t dummy_nresp;
   int testmode;
+  int cherry_mode = 0;
 
   testmode = !resp && !nresp;
 
@@ -2317,10 +2383,26 @@ ccid_transceive_secure (ccid_driver_t handle,
       || pinlen_min > pinlen_max)
     return CCID_DRIVER_ERR_INV_VALUE;
 
-  /* We have only tested this with an SCM reader so better don't risk
-     anything and do not allow the use with other readers. */
-  if (handle->id_vendor != VENDOR_SCM)
-    return CCID_DRIVER_ERR_NOT_SUPPORTED;
+  /* We have only tested a few readers so better don't risk anything
+     and do not allow the use with other readers. */
+  switch (handle->id_vendor)
+    {
+    case VENDOR_SCM:  /* Tested with SPR 532. */
+    case VENDOR_KAAN: /* Tested with KAAN Advanced (1.02). */
+      break;
+    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;
+    }
 
   if (testmode)
     return 0; /* Success */
@@ -2335,10 +2417,10 @@ 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] = 4; /* bBWI */
+  msg[7] = 0; /* bBWI */
   msg[8] = 0; /* RFU */
   msg[9] = 0; /* RFU */
   msg[10] = 0; /* Perform PIN verification. */
@@ -2347,7 +2429,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;
     }
@@ -2359,8 +2441,11 @@ ccid_transceive_secure (ccid_driver_t handle,
       msg[14] = 0x00; /* bmPINLengthFormat:
                          Units are bytes, position is 0. */
     }
-  msg[15] = pinlen_min;   /* wPINMaxExtraDigit-Minimum.  */
-  msg[16] = pinlen_max;   /* wPINMaxExtraDigit-Maximum.  */
+
+  /* The following is a little endian word. */
+  msg[15] = pinlen_max;   /* wPINMaxExtraDigit-Maximum.  */
+  msg[16] = pinlen_min;   /* wPINMaxExtraDigit-Minimum.  */
+
   msg[17] = 0x02; /* bEntryValidationCondition:
                      Validation key pressed */
   if (pinlen_min && pinlen_max && pinlen_min == pinlen_max)
@@ -2372,13 +2457,16 @@ ccid_transceive_secure (ccid_driver_t handle,
   /* bTeoProlog follows: */
   msg[22] = handle->nonnull_nad? ((1 << 4) | 0): 0;
   msg[23] = ((handle->t1_ns & 1) << 6); /* I-block */
-  msg[24] = 4; /* apdulen.  */
+  msg[24] = 0; /* The apdulen will be filled in by the reader.  */
   /* APDU follows:  */
   msg[25] = apdu_buf[0]; /* CLA */
   msg[26] = apdu_buf[1]; /* INS */
   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);
 
   DEBUGOUT ("sending");
@@ -2392,12 +2480,30 @@ ccid_transceive_secure (ccid_driver_t handle,
   
   msg = recv_buffer;
   rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
-                RDR_to_PC_DataBlock, seqno, 5000, 0);
+                RDR_to_PC_DataBlock, seqno, 30000, 0);
   if (rc)
     return rc;
   
   tpdu = msg + 10;
   tpdulen = msglen - 10;
+
+  if (handle->apdu_level)
+    {
+      if (resp)
+        {
+          if (tpdulen > maxresplen)
+            {
+              DEBUGOUT_2 ("provided buffer too short for received data "
+                          "(%u/%u)\n",
+                          (unsigned int)tpdulen, (unsigned int)maxresplen);
+              return CCID_DRIVER_ERR_INV_VALUE;
+            }
+          
+          memcpy (resp, tpdu, tpdulen); 
+          *nresp = tpdulen;
+        }
+      return 0;
+    }
   
   if (tpdulen < 4) 
     {
@@ -2543,7 +2649,7 @@ main (int argc, char **argv)
 {
   int rc;
   ccid_driver_t ccid;
-  unsigned int slotstat;
+  int slotstat;
   unsigned char result[512];
   size_t resultlen;
   int no_pinpad = 0;
@@ -2571,7 +2677,7 @@ main (int argc, char **argv)
         }
       else if ( !strcmp (*argv, "--debug"))
         {
-          ccid_set_debug_level (1);
+          ccid_set_debug_level (ccid_set_debug_level (-1)+1);
           argc--; argv++;
         }
       else if ( !strcmp (*argv, "--no-poll"))