gpg: Print ownertrust in TOFU+PGP trust model.
[gnupg.git] / scd / apdu.c
index 476723a..268a2c6 100644 (file)
@@ -59,6 +59,7 @@
 #include "scdaemon.h"
 #include "exechelp.h"
 #endif /* GNUPG_MAJOR_VERSION != 1 */
+#include "host2net.h"
 
 #include "iso7816.h"
 #include "apdu.h"
@@ -243,6 +244,7 @@ static char (* DLSTDCALL CT_close) (unsigned short ctn);
 #define PCSC_E_NOT_TRANSACTED          0x80100016
 #define PCSC_E_READER_UNAVAILABLE      0x80100017
 #define PCSC_E_NO_SERVICE              0x8010001D
+#define PCSC_E_SERVICE_STOPPED         0x8010001E
 #define PCSC_W_REMOVED_CARD            0x80100069
 
 /* Fix pcsc-lite ABI incompatibilty.  */
@@ -685,7 +687,7 @@ static int
 ct_get_status (int slot, unsigned int *status)
 {
   (void)slot;
-  /* The status we returned is wrong but we don't care becuase ctAPI
+  /* The status we returned is wrong but we don't care because ctAPI
      is not anymore required.  */
   *status = APDU_CARD_USABLE|APDU_CARD_PRESENT|APDU_CARD_ACTIVE;
   return 0;
@@ -906,6 +908,8 @@ pcsc_error_to_sw (long ec)
     case PCSC_E_CANCELLED:           rc = SW_HOST_ABORTED; break;
     case PCSC_E_NO_MEMORY:           rc = SW_HOST_OUT_OF_CORE; break;
     case PCSC_E_TIMEOUT:             rc = SW_HOST_CARD_IO_ERROR; break;
+    case PCSC_E_NO_SERVICE:
+    case PCSC_E_SERVICE_STOPPED:
     case PCSC_E_UNKNOWN_READER:      rc = SW_HOST_NO_READER; break;
     case PCSC_E_SHARING_VIOLATION:   rc = SW_HOST_LOCKING_FAILED; break;
     case PCSC_E_NO_SMARTCARD:        rc = SW_HOST_NO_CARD; break;
@@ -1047,15 +1051,14 @@ pcsc_get_status_wrapped (int slot, unsigned int *status)
                  i? strerror (errno) : "premature EOF");
       goto command_failed;
     }
-  len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
+  len = buf_to_size_t (msgbuf+1);
   if (msgbuf[0] != 0x81 || len < 4)
     {
       log_error ("invalid response header from PC/SC received\n");
       goto command_failed;
     }
   len -= 4; /* Already read the error code. */
-  err = PCSC_ERR_MASK ((msgbuf[5] << 24) | (msgbuf[6] << 16)
-                       | (msgbuf[7] << 8 ) | msgbuf[8]);
+  err = PCSC_ERR_MASK (buf32_to_ulong (msgbuf+5));
   if (err)
     {
       log_error ("pcsc_status failed: %s (0x%lx)\n",
@@ -1218,15 +1221,14 @@ pcsc_send_apdu_wrapped (int slot, unsigned char *apdu, size_t apdulen,
                  i? strerror (errno) : "premature EOF");
       goto command_failed;
     }
-  len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
+  len = buf_to_size_t (msgbuf+1);
   if (msgbuf[0] != 0x81 || len < 4)
     {
       log_error ("invalid response header from PC/SC received\n");
       goto command_failed;
     }
   len -= 4; /* Already read the error code. */
-  err = PCSC_ERR_MASK ((msgbuf[5] << 24) | (msgbuf[6] << 16)
-                       | (msgbuf[7] << 8 ) | msgbuf[8]);
+  err = PCSC_ERR_MASK (buf32_to_ulong (msgbuf+5));
   if (err)
     {
       log_error ("pcsc_transmit failed: %s (0x%lx)\n",
@@ -1308,7 +1310,7 @@ control_pcsc_direct (int slot, pcsc_dword_t ioctl_code,
   long err;
 
   err = pcsc_control (reader_table[slot].pcsc.card, ioctl_code,
-                      cntlbuf, len, buffer, *buflen, buflen);
+                      cntlbuf, len, buffer, buflen? *buflen:0, buflen);
   if (err)
     {
       log_error ("pcsc_control failed: %s (0x%lx)\n",
@@ -1359,15 +1361,14 @@ control_pcsc_wrapped (int slot, pcsc_dword_t ioctl_code,
                  i? strerror (errno) : "premature EOF");
       goto command_failed;
     }
-  len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
+  len = buf32_to_size_t (msgbuf+1);
   if (msgbuf[0] != 0x81 || len < 4)
     {
       log_error ("invalid response header from PC/SC received\n");
       goto command_failed;
     }
   len -= 4; /* Already read the error code. */
-  err = PCSC_ERR_MASK ((msgbuf[5] << 24) | (msgbuf[6] << 16)
-                       | (msgbuf[7] << 8 ) | msgbuf[8]);
+  err = PCSC_ERR_MASK (buf32_to_ulong (msgbuf+5));
   if (err)
     {
       log_error ("pcsc_control failed: %s (0x%lx)\n",
@@ -1377,14 +1378,18 @@ control_pcsc_wrapped (int slot, pcsc_dword_t ioctl_code,
 
   full_len = len;
 
-  n = *buflen < len ? *buflen : len;
+  if (buflen)
+    n = *buflen < len ? *buflen : len;
+  else
+    n = 0;
   if ((i=readn (slotp->pcsc.rsp_fd, buffer, n, &len)) || len != n)
     {
       log_error ("error receiving PC/SC CONTROL response: %s\n",
                  i? strerror (errno) : "premature EOF");
       goto command_failed;
     }
-  *buflen = n;
+  if (buflen)
+    *buflen = n;
 
   full_len -= len;
   if (full_len)
@@ -1497,15 +1502,14 @@ close_pcsc_reader_wrapped (int slot)
                  i? strerror (errno) : "premature EOF");
       goto command_failed;
     }
-  len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
+  len = buf32_to_size_t (msgbuf+1);
   if (msgbuf[0] != 0x81 || len < 4)
     {
       log_error ("invalid response header from PC/SC received\n");
       goto command_failed;
     }
   len -= 4; /* Already read the error code. */
-  err = PCSC_ERR_MASK ((msgbuf[5] << 24) | (msgbuf[6] << 16)
-                       | (msgbuf[7] << 8 ) | msgbuf[8]);
+  err = PCSC_ERR_MASK (buf32_to_ulong (msgbuf+5));
   if (err)
     log_error ("pcsc_close failed: %s (0x%lx)\n",
                pcsc_error_string (err), err);
@@ -1687,7 +1691,7 @@ reset_pcsc_reader_wrapped (int slot)
                  i? strerror (errno) : "premature EOF");
       goto command_failed;
     }
-  len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
+  len = buf32_to_size_t (msgbuf+1);
   if (msgbuf[0] != 0x81 || len < 4)
     {
       log_error ("invalid response header from PC/SC received\n");
@@ -1701,8 +1705,7 @@ reset_pcsc_reader_wrapped (int slot)
       sw = SW_HOST_GENERAL_ERROR;
       goto command_failed;
     }
-  err = PCSC_ERR_MASK ((msgbuf[5] << 24) | (msgbuf[6] << 16)
-                       | (msgbuf[7] << 8 ) | msgbuf[8]);
+  err = PCSC_ERR_MASK (buf32_to_ulong (msgbuf+5));
   if (err)
     {
       log_error ("PC/SC RESET failed: %s (0x%lx)\n",
@@ -1794,9 +1797,9 @@ pcsc_vendor_specific_init (int slot)
           if (l == 1)
             v = p[0];
           else if (l == 2)
-            v = ((p[0] << 8) | p[1]);
+            v = buf16_to_uint (p);
           else if (l == 4)
-            v = ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+            v = buf32_to_uint (p);
 
           if (code == FEATURE_VERIFY_PIN_DIRECT)
             reader_table[slot].pcsc.verify_ioctl = v;
@@ -1825,8 +1828,12 @@ pcsc_vendor_specific_init (int slot)
               reader_table[slot].is_spr532 = 1;
               reader_table[slot].pinpad_varlen_supported = 1;
             }
-          else if (strstr (reader_table[slot].rdrname, "ST-2xxx")
-                   || strstr (reader_table[slot].rdrname, "cyberJack")
+          else if (strstr (reader_table[slot].rdrname, "ST-2xxx"))
+            {
+              reader_table[slot].pcsc.pinmax = 15;
+              reader_table[slot].pinpad_varlen_supported = 1;
+            }
+          else if (strstr (reader_table[slot].rdrname, "cyberJack")
                    || strstr (reader_table[slot].rdrname, "DIGIPASS")
                    || strstr (reader_table[slot].rdrname, "Gnuk")
                    || strstr (reader_table[slot].rdrname, "KAAN"))
@@ -1855,9 +1862,9 @@ pcsc_vendor_specific_init (int slot)
       if (l == 1)
         v = p[0];
       else if (l == 2)
-        v = ((p[1] << 8) | p[0]);
+        v = (((unsigned int)p[1] << 8) | p[0]);
       else if (l == 4)
-        v = ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
+        v = (((unsigned int)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
 
       if (tag == PCSCv2_PART10_PROPERTY_bMinPINSize)
         reader_table[slot].pcsc.pinmin = v;
@@ -1891,8 +1898,12 @@ pcsc_vendor_specific_init (int slot)
       reader_table[slot].is_spr532 = 1;
       reader_table[slot].pinpad_varlen_supported = 1;
     }
-  else if ((vendor == 0x046a && product == 0x003e)  /* Cherry ST-2xxx */
-           || vendor == 0x0c4b /* Tested with Reiner cyberJack GO */
+  else if (vendor == 0x046a && product == 0x003e) /* Cherry ST-2xxx */
+    {
+      reader_table[slot].pcsc.pinmax = 15;
+      reader_table[slot].pinpad_varlen_supported = 1;
+    }
+  else if (vendor == 0x0c4b /* Tested with Reiner cyberJack GO */
            || vendor == 0x1a44 /* Tested with Vasco DIGIPASS 920 */
            || vendor == 0x234b /* Tested with FSIJ Gnuk Token */
            || vendor == 0x0d46 /* Tested with KAAN Advanced??? */)
@@ -1911,6 +1922,7 @@ open_pcsc_reader_direct (const char *portstr)
   long err;
   int slot;
   char *list = NULL;
+  char *rdrname = NULL;
   pcsc_dword_t nreader;
   char *p;
 
@@ -1963,18 +1975,22 @@ open_pcsc_reader_direct (const char *portstr)
     {
       if (!*p && !p[1])
         break;
-      if (*p)
-        log_info ("detected reader '%s'\n", p);
+      log_info ("detected reader '%s'\n", p);
       if (nreader < (strlen (p)+1))
         {
           log_error ("invalid response from pcsc_list_readers\n");
           break;
         }
+      if (!rdrname && portstr && !strncmp (p, portstr, strlen (portstr)))
+        rdrname = p;
       nreader -= strlen (p)+1;
       p += strlen (p) + 1;
     }
 
-  reader_table[slot].rdrname = xtrymalloc (strlen (portstr? portstr : list)+1);
+  if (!rdrname)
+    rdrname = list;
+
+  reader_table[slot].rdrname = xtrystrdup (rdrname);
   if (!reader_table[slot].rdrname)
     {
       log_error ("error allocating memory for reader name\n");
@@ -1983,7 +1999,6 @@ open_pcsc_reader_direct (const char *portstr)
       unlock_slot (slot);
       return -1;
     }
-  strcpy (reader_table[slot].rdrname, portstr? portstr : list);
   xfree (list);
   list = NULL;
 
@@ -2023,7 +2038,7 @@ open_pcsc_reader_wrapped (const char *portstr)
   int err;
   unsigned int dummy_status;
 
-  /* Note that we use the constant and not the fucntion because this
+  /* Note that we use the constant and not the function because this
      code won't be be used under Windows.  */
   const char *wrapperpgm = GNUPG_LIBEXECDIR "/gnupg-pcsc-wrapper";
 
@@ -2151,7 +2166,7 @@ open_pcsc_reader_wrapped (const char *portstr)
                  i? strerror (errno) : "premature EOF");
       goto command_failed;
     }
-  len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
+  len = buf32_to_size_t (msgbuf+1);
   if (msgbuf[0] != 0x81 || len < 4)
     {
       log_error ("invalid response header from PC/SC received\n");
@@ -2164,9 +2179,7 @@ open_pcsc_reader_wrapped (const char *portstr)
                  (unsigned long)len);
       goto command_failed;
     }
-  err = PCSC_ERR_MASK ((msgbuf[5] << 24) | (msgbuf[6] << 16)
-                       | (msgbuf[7] << 8 ) | msgbuf[8]);
-
+  err = PCSC_ERR_MASK (buf32_to_ulong (msgbuf+5));
   if (err)
     {
       log_error ("PC/SC OPEN failed: %s\n", pcsc_error_string (err));
@@ -2280,8 +2293,16 @@ pcsc_pinpad_verify (int slot, int class, int ins, int p0, int p1,
   int sw;
   unsigned char *pin_verify;
   int len = PIN_VERIFY_STRUCTURE_SIZE + pininfo->fixedlen;
-  unsigned char result[2];
-  pcsc_dword_t resultlen = 2;
+  /*
+   * The result buffer is only expected to have two-byte result on
+   * return.  However, some implementation uses this buffer for lower
+   * layer too and it assumes that there is enough space for lower
+   * layer communication.  Such an implementation fails for TPDU
+   * readers with "insufficient buffer", as it needs header and
+   * trailer.  Six is the number for header + result + trailer (TPDU).
+   */
+  unsigned char result[6];
+  pcsc_dword_t resultlen = 6;
   int no_lc;
 
   if (!reader_table[slot].atrlen
@@ -2336,8 +2357,6 @@ pcsc_pinpad_verify (int slot, int class, int ins, int p0, int p1,
                      pin_verify, len, result, &resultlen);
   xfree (pin_verify);
   if (sw || resultlen < 2)
-    return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE;
-  sw = (result[resultlen-2] << 8) | result[resultlen-1];
     {
       log_error ("control_pcsc failed: %d\n", sw);
       return sw? sw: SW_HOST_INCOMPLETE_CARD_RESPONSE;
@@ -2357,8 +2376,8 @@ pcsc_pinpad_modify (int slot, int class, int ins, int p0, int p1,
   int sw;
   unsigned char *pin_modify;
   int len = PIN_MODIFY_STRUCTURE_SIZE + 2 * pininfo->fixedlen;
-  unsigned char result[2];
-  pcsc_dword_t resultlen = 2;
+  unsigned char result[6];      /* See the comment at pinpad_verify.  */
+  pcsc_dword_t resultlen = 6;
   int no_lc;
 
   if (!reader_table[slot].atrlen
@@ -2450,6 +2469,7 @@ static int
 close_ccid_reader (int slot)
 {
   ccid_close_reader (reader_table[slot].ccid.handle);
+  reader_table[slot].rdrname = NULL;
   reader_table[slot].used = 0;
   return 0;
 }
@@ -2603,7 +2623,8 @@ open_ccid_reader (const char *portstr)
     return -1;
   slotp = reader_table + slot;
 
-  err = ccid_open_reader (&slotp->ccid.handle, portstr);
+  err = ccid_open_reader (&slotp->ccid.handle, portstr,
+                          (const char **)&slotp->rdrname);
   if (err)
     {
       slotp->used = 0;
@@ -3140,7 +3161,7 @@ apdu_open_reader (const char *portstr)
    with remote readers only.  Note that the supplied CLOSEFNC will
    only be called once and the slot will not be valid afther this.
 
-   If PORTSTR is NULL we default to the first availabe port.
+   If PORTSTR is NULL we default to the first available port.
 */
 int
 apdu_open_remote_reader (const char *portstr,
@@ -3197,9 +3218,12 @@ apdu_close_reader (int slot)
   sw = apdu_disconnect (slot);
   if (sw)
     {
+      /*
+       * When the reader/token was removed it might come here.
+       * It should go through to call CLOSE_READER even if we got an error.
+       */
       if (DBG_READER)
-        log_debug ("leave: apdu_close_reader => 0x%x (apdu_disconnect)\n", sw);
-      return sw;
+        log_debug ("apdu_close_reader => 0x%x (apdu_disconnect)\n", sw);
     }
   if (reader_table[slot].close_reader)
     {
@@ -3297,8 +3321,8 @@ apdu_enum_reader (int slot, int *used)
 int
 apdu_connect (int slot)
 {
-  int sw;
-  unsigned int status;
+  int sw = 0;
+  unsigned int status = 0;
 
   if (DBG_READER)
     log_debug ("enter: apdu_connect: slot=%d\n", slot);
@@ -3322,15 +3346,15 @@ apdu_connect (int slot)
           unlock_slot (slot);
         }
     }
-  else
-    sw = 0;
 
   /* We need to call apdu_get_status_internal, so that the last-status
      machinery gets setup properly even if a card is inserted while
      scdaemon is fired up and apdu_get_status has not yet been called.
      Without that we would force a reset of the card with the next
      call to apdu_get_status.  */
-  apdu_get_status_internal (slot, 1, 1, &status, NULL);
+  if (!sw)
+    sw = apdu_get_status_internal (slot, 1, 1, &status, NULL);
+
   if (sw)
     ;
   else if (!(status & APDU_CARD_PRESENT))
@@ -3810,9 +3834,9 @@ send_le (int slot, int class, int ins, int p0, int p1,
           apdu[apdulen++] = ins;
           apdu[apdulen++] = p0;
           apdu[apdulen++] = p1;
-          apdu[apdulen++] = 0;  /* Z byte: Extended length marker.  */
-          if (lc >= 0)
+          if (lc > 0)
             {
+              apdu[apdulen++] = 0;  /* Z byte: Extended length marker.  */
               apdu[apdulen++] = ((lc >> 8) & 0xff);
               apdu[apdulen++] = (lc & 0xff);
               memcpy (apdu+apdulen, data, lc);
@@ -3821,6 +3845,8 @@ send_le (int slot, int class, int ins, int p0, int p1,
             }
           if (le != -1)
             {
+              if (lc <= 0)
+                apdu[apdulen++] = 0;  /* Z byte: Extended length marker.  */
               apdu[apdulen++] = ((le >> 8) & 0xff);
               apdu[apdulen++] = (le & 0xff);
             }
@@ -4032,7 +4058,7 @@ send_le (int slot, int class, int ins, int p0, int p1,
    The return value is the status word or -1 for an invalid SLOT or
    other non card related error.  If RETBUF is not NULL, it will
    receive an allocated buffer with the returned data.  The length of
-   that data will be put into *RETBUFLEN.  The caller is reponsible
+   that data will be put into *RETBUFLEN.  The caller is responsible
    for releasing the buffer even in case of errors.  */
 int
 apdu_send_le(int slot, int extended_mode,
@@ -4055,7 +4081,7 @@ apdu_send_le(int slot, int extended_mode,
    return value is the status word or -1 for an invalid SLOT or other
    non card related error.  If RETBUF is not NULL, it will receive an
    allocated buffer with the returned data.  The length of that data
-   will be put into *RETBUFLEN.  The caller is reponsible for
+   will be put into *RETBUFLEN.  The caller is responsible for
    releasing the buffer even in case of errors.  */
 int
 apdu_send (int slot, int extended_mode,
@@ -4308,3 +4334,10 @@ apdu_send_direct (int slot, size_t extended_length,
 
   return 0;
 }
+
+
+const char *
+apdu_get_reader_name (int slot)
+{
+  return reader_table[slot].rdrname;
+}