[git] GnuPG - branch, master, updated. post-nuke-of-trailing-ws-121-g26b4a01

by NIIBE Yutaka cvs at cvs.gnupg.org
Mon Nov 28 09:11:35 CET 2011


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  26b4a012e3eb3a6ce79a1e53f7cdfbbdf8c8e8f5 (commit)
      from  0689f0fc32cc9a8e431d33ee3431d23f3fd1f258 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 26b4a012e3eb3a6ce79a1e53f7cdfbbdf8c8e8f5
Author: NIIBE Yutaka <gniibe at fsij.org>
Date:   Mon Nov 28 16:16:38 2011 +0900

    PC/SC pinpad support.
    
    Before this change, it is layered like following:
    
    	iso7816_verify
            iso7816_verify_kp
    	apdu_send_simple, apdu_send_simple_kp
    	...
    
    After this change, it will be layered like:
    
    	iso7816_verify      iso7816_verify_kp
            apdu_send_simple    apdu_keypad_verify
    	...
    
    and apdu_send_simple_kp will be deprecated.
    
    For PC/SC API, we use:
      SCardControl API to compose CCID PC_to_RDR_Secure message
      SCardTransmit API to compose CCID PC_to_RDR_XfrBlock message
    
    Considering the support of PC/SC, we have nothing to share between _kp
    version of iso7816_* and no _kp version.

diff --git a/scd/ChangeLog b/scd/ChangeLog
index 45c9c7c..9f991ce 100644
--- a/scd/ChangeLog
+++ b/scd/ChangeLog
@@ -1,3 +1,38 @@
+2011-11-28  Niibe Yutaka  <gniibe at fsij.org>
+
+	* iso7816.h (iso7816_verify_kp): Remove arguments of CHV and CHVLEN.
+
+	* iso7816.c (iso7816_verify_kp): Call apdu_keypad_verify. Only
+	handle thecase with PININFO.
+	(iso7816_verify): Call apdu_send_simple.
+
+	* app-openpgp.c (verify_a_chv, verify_chv3): Follow the change of
+	iso7816_verify_kp.
+
+	* app-nks.c (verify_pin): Likewise.
+
+	* app-dinsig.c (verify_pin): Likewise.
+
+	* apdu.c: Include "iso7816.h".
+	(struct reader_table_s): New memeber function keypad_verify.
+	Add fields verify_ioctl and modify_ioctl in pcsc.
+	(CM_IOCTL_GET_FEATURE_REQUEST, FEATURE_VERIFY_PIN_DIRECT)
+	(FEATURE_MODIFY_PIN_DIRECT): New.
+	(pcsc_control): New.
+	(control_pcsc_direct, control_pcsc_wrapped, control_pcsc)
+	(check_pcsc_keypad, pcsc_keypad_verify): New.
+	(ccid_keypad_verify, apdu_keypad_verify): New.
+	(new_reader_slot): Initialize with check_pcsc_keypad,
+	pcsc_keypad_verify, verify_ioctl and modify_ioctl.
+	(open_ct_reader): Initialize keypad_verify with NULL.
+	(open_ccid_reader): Initialize keypad_verify.
+	(open_rapdu_reader): Initialize keypad_verify with NULL.
+	(apdu_open_reader): Initialize pcsc_control.
+
+	* pcsc-wrapper.c (load_pcsc_driver): Initialize pcsc_control.
+	(handle_control): New.
+	(main): Handle the case 6 of handle_control.
+
 2011-08-10  Werner Koch  <wk at g10code.com>
 
 	* command.c (cmd_killscd): Use the new assuan force close flag
diff --git a/scd/apdu.c b/scd/apdu.c
index ac563ad..866ebb9 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -62,6 +62,7 @@
 
 #include "apdu.h"
 #include "ccid-driver.h"
+#include "iso7816.h"
 
 
 /* Due to conflicting use of threading libraries we usually can't link
@@ -110,6 +111,7 @@ struct reader_table_s {
   int (*check_keypad)(int, int, int, int, int, int);
   void (*dump_status_reader)(int);
   int (*set_progress_cb)(int, gcry_handler_progress_t, void*);
+  int (*keypad_verify)(int, int, int, int, int, struct pininfo_s *);
 
   struct {
     ccid_driver_t handle;
@@ -118,6 +120,8 @@ struct reader_table_s {
     unsigned long context;
     unsigned long card;
     unsigned long protocol;
+    unsigned long verify_ioctl;
+    unsigned long modify_ioctl;
 #ifdef NEED_PCSC_WRAPPER
     int req_fd;
     int rsp_fd;
@@ -236,6 +240,11 @@ static char (* DLSTDCALL CT_close) (unsigned short ctn);
 #define PCSC_E_READER_UNAVAILABLE      0x80100017
 #define PCSC_W_REMOVED_CARD            0x80100069
 
+#define CM_IOCTL_GET_FEATURE_REQUEST (0x42000000 + 3400)
+#define FEATURE_VERIFY_PIN_DIRECT        0x06
+#define FEATURE_MODIFY_PIN_DIRECT        0x07
+
+
 /* The PC/SC error is defined as a long as per specs.  Due to left
    shifts bit 31 will get sign extended.  We use this mask to fix
    it. */
@@ -304,6 +313,13 @@ long (* DLSTDCALL pcsc_transmit) (unsigned long card,
                                   unsigned long *recv_len);
 long (* DLSTDCALL pcsc_set_timeout) (unsigned long context,
                                      unsigned long timeout);
+long (* DLSTDCALL pcsc_control) (unsigned long card,
+                                 unsigned long control_code,
+                                 const void *send_buffer,
+                                 unsigned long send_len,
+                                 void *recv_buffer,
+                                 unsigned long recv_len,
+                                 unsigned long *bytes_returned);
 
 /* Flag set if PC/SC returned the no-service error.  */
 static int pcsc_no_service;
@@ -315,6 +331,10 @@ static int reset_pcsc_reader (int slot);
 static int apdu_get_status_internal (int slot, int hang, int no_atr_reset,
                                      unsigned int *status,
                                      unsigned int *changed);
+static int check_pcsc_keypad (int slot, int command, int pin_mode,
+                              int pinlen_min, int pinlen_max, int pin_padlen);
+static int pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
+                               struct pininfo_s *pininfo);
 
 
 
@@ -358,9 +378,10 @@ new_reader_slot (void)
   reader_table[reader].reset_reader = NULL;
   reader_table[reader].get_status_reader = NULL;
   reader_table[reader].send_apdu_reader = NULL;
-  reader_table[reader].check_keypad = NULL;
+  reader_table[reader].check_keypad = check_pcsc_keypad;
   reader_table[reader].dump_status_reader = NULL;
   reader_table[reader].set_progress_cb = NULL;
+  reader_table[reader].keypad_verify = pcsc_keypad_verify;
 
   reader_table[reader].used = 1;
   reader_table[reader].any_status = 0;
@@ -371,6 +392,8 @@ new_reader_slot (void)
   reader_table[reader].pcsc.rsp_fd = -1;
   reader_table[reader].pcsc.pid = (pid_t)(-1);
 #endif
+  reader_table[reader].pcsc.verify_ioctl = 0;
+  reader_table[reader].pcsc.modify_ioctl = 0;
 
   return reader;
 }
@@ -645,6 +668,7 @@ open_ct_reader (int port)
   reader_table[reader].send_apdu_reader = ct_send_apdu;
   reader_table[reader].check_keypad = NULL;
   reader_table[reader].dump_status_reader = ct_dump_reader_status;
+  reader_table[reader].keypad_verify = NULL;
 
   dump_reader_status (reader);
   return reader;
@@ -1172,6 +1196,150 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
 
 #ifndef NEED_PCSC_WRAPPER
 static int
+control_pcsc_direct (int slot, unsigned long ioctl_code,
+                     const unsigned char *cntlbuf, size_t len,
+                     unsigned char *buffer, size_t *buflen)
+{
+  long err;
+
+  err = pcsc_control (reader_table[slot].pcsc.card, ioctl_code,
+                      cntlbuf, len, buffer, *buflen, buflen);
+  if (err)
+    {
+      log_error ("pcsc_control failed: %s (0x%lx)\n",
+                 pcsc_error_string (err), err);
+      return pcsc_error_to_sw (err);
+    }
+
+  return 0;
+}
+#endif /*!NEED_PCSC_WRAPPER*/
+
+
+#ifdef NEED_PCSC_WRAPPER
+static int
+control_pcsc_wrapped (int slot, unsigned long ioctl_code,
+                      const unsigned char *cntlbuf, size_t len,
+                      unsigned char *buffer, size_t *buflen)
+{
+  long err = PCSC_E_NOT_TRANSACTED;
+  reader_table_t slotp;
+  unsigned char msgbuf[9];
+  int i, n;
+  size_t full_len;
+
+  slotp = reader_table + slot;
+
+  msgbuf[0] = 0x06; /* CONTROL command. */
+  msgbuf[1] = ((len + 4) >> 24);
+  msgbuf[2] = ((len + 4) >> 16);
+  msgbuf[3] = ((len + 4) >>  8);
+  msgbuf[4] = ((len + 4)      );
+  msgbuf[5] = (ioctl_code >> 24);
+  msgbuf[6] = (ioctl_code >> 16);
+  msgbuf[7] = (ioctl_code >>  8);
+  msgbuf[8] = (ioctl_code      );
+  if ( writen (slotp->pcsc.req_fd, msgbuf, 9)
+       || writen (slotp->pcsc.req_fd, cntlbuf, len))
+    {
+      log_error ("error sending PC/SC CONTROL request: %s\n",
+                 strerror (errno));
+      goto command_failed;
+    }
+
+  /* Read the response. */
+  if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
+    {
+      log_error ("error receiving PC/SC CONTROL response: %s\n",
+                 i? strerror (errno) : "premature EOF");
+      goto command_failed;
+    }
+  len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
+  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]);
+  if (err)
+    {
+      log_error ("pcsc_control failed: %s (0x%lx)\n",
+                 pcsc_error_string (err), err);
+      return pcsc_error_to_sw (err);
+    }
+
+  full_len = len;
+
+  n = *buflen < len ? *buflen : len;
+  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;
+
+  full_len -= len;
+  if (full_len)
+    {
+      log_error ("pcsc_send_apdu: provided buffer too short - truncated\n");
+      err = PCSC_E_INVALID_VALUE;
+    }
+  /* We need to read any rest of the response, to keep the
+     protocol running.  */
+  while (full_len)
+    {
+      unsigned char dummybuf[128];
+
+      n = full_len < DIM (dummybuf) ? full_len : DIM (dummybuf);
+      if ((i=readn (slotp->pcsc.rsp_fd, dummybuf, n, &len)) || len != n)
+        {
+          log_error ("error receiving PC/SC CONTROL response: %s\n",
+                     i? strerror (errno) : "premature EOF");
+          goto command_failed;
+        }
+      full_len -= n;
+    }
+
+  if (!err)
+    return 0;
+
+ command_failed:
+  close (slotp->pcsc.req_fd);
+  close (slotp->pcsc.rsp_fd);
+  slotp->pcsc.req_fd = -1;
+  slotp->pcsc.rsp_fd = -1;
+  kill (slotp->pcsc.pid, SIGTERM);
+  slotp->pcsc.pid = (pid_t)(-1);
+  slotp->used = 0;
+  return pcsc_error_to_sw (err);
+}
+#endif /*NEED_PCSC_WRAPPER*/
+
+
+
+/* Do some control with the value of IOCTL_CODE to the card inserted
+   to SLOT.  Input buffer is specified by CNTLBUF of length LEN.
+   Output buffer is specified by BUFFER of length *BUFLEN, and the
+   actual output size will be stored at BUFLEN.  Returns: A status word.
+   This routine is used for PIN pad input support.  */
+static int
+control_pcsc (int slot, unsigned long ioctl_code,
+              const unsigned char *cntlbuf, size_t len,
+              unsigned char *buffer, size_t *buflen)
+{
+#ifdef NEED_PCSC_WRAPPER
+  return control_pcsc_wrapped (slot, ioctl_code, cntlbuf, len, buffer, buflen);
+#else
+  return control_pcsc_direct (slot, ioctl_code, cntlbuf, len, buffer, buflen);
+#endif
+}
+
+
+#ifndef NEED_PCSC_WRAPPER
+static int
 close_pcsc_reader_direct (int slot)
 {
   pcsc_release_context (reader_table[slot].pcsc.context);
@@ -1808,6 +1976,138 @@ open_pcsc_reader (const char *portstr)
 }
 
 
+/* Check whether the reader supports the ISO command code COMMAND
+   on the keypad.  Return 0 on success.  */
+static int
+check_pcsc_keypad (int slot, int command, int pin_mode,
+                   int pinlen_min, int pinlen_max, int pin_padlen)
+{
+  unsigned char buf[256];
+  size_t len = 256;
+  int sw;
+
+  (void)pin_mode;
+  (void)pinlen_min;
+  (void)pinlen_max;
+  (void)pin_padlen;
+
+ check_again:
+  if (command == ISO7816_VERIFY)
+    {
+      if (reader_table[slot].pcsc.verify_ioctl == (unsigned long)-1)
+        return SW_NOT_SUPPORTED;
+      else if (reader_table[slot].pcsc.verify_ioctl != 0)
+        return 0;                       /* Success */
+    }
+  else if (command == ISO7816_CHANGE_REFERENCE_DATA)
+    {
+      if (reader_table[slot].pcsc.modify_ioctl == (unsigned long)-1)
+        return SW_NOT_SUPPORTED;
+      else if (reader_table[slot].pcsc.modify_ioctl != 0)
+        return 0;                       /* Success */
+    }
+  else
+    return SW_NOT_SUPPORTED;
+
+  reader_table[slot].pcsc.verify_ioctl = (unsigned long)-1;
+  reader_table[slot].pcsc.modify_ioctl = (unsigned long)-1;
+
+  sw = control_pcsc (slot, CM_IOCTL_GET_FEATURE_REQUEST, NULL, 0, buf, &len);
+  if (sw)
+    return SW_NOT_SUPPORTED;
+  else
+    {
+      unsigned char *p = buf;
+
+      while (p < buf + len)
+        {
+          unsigned char code = *p++;
+
+          p++;                  /* Skip length */
+          if (code == FEATURE_VERIFY_PIN_DIRECT)
+            reader_table[slot].pcsc.verify_ioctl
+              = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+          else if (code == FEATURE_MODIFY_PIN_DIRECT)
+            reader_table[slot].pcsc.modify_ioctl
+              = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+          p += 4;
+        }
+    }
+
+  goto check_again;
+}
+
+
+#define PIN_VERIFY_STRUCTURE_SIZE 23
+static int
+pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
+                    struct pininfo_s *pininfo)
+{
+  int sw;
+  unsigned char *pin_verify;
+  unsigned long len = PIN_VERIFY_STRUCTURE_SIZE;
+  unsigned char result[2];
+  size_t resultlen = 2;
+
+  if (!reader_table[slot].atrlen
+      && (sw = reset_pcsc_reader (slot)))
+    return sw;
+
+  if (pininfo->mode != 1)
+    return SW_NOT_SUPPORTED;
+
+  if (pininfo->padlen != 0)
+    return SW_NOT_SUPPORTED;
+
+  if (!pininfo->minlen)
+    pininfo->minlen = 1;
+  if (!pininfo->maxlen)
+    pininfo->maxlen = 25;
+
+  /* Note that the 25 is the maximum value the SPR532 allows.  */
+  if (pininfo->minlen < 1 || pininfo->minlen > 25
+      || pininfo->maxlen < 1 || pininfo->maxlen > 25
+      || pininfo->minlen > pininfo->maxlen)
+    return SW_HOST_INV_VALUE;
+
+  pin_verify = xtrymalloc (len);
+  if (!pin_verify)
+    return SW_HOST_OUT_OF_CORE;
+
+  pin_verify[0] = 0x00; /* bTimerOut */
+  pin_verify[1] = 0x00; /* bTimerOut2 */
+  pin_verify[2] = 0x82; /* bmFormatString: Byte, pos=0, left, ASCII. */
+  pin_verify[3] = 0x00; /* bmPINBlockString */
+  pin_verify[4] = 0x00; /* bmPINLengthFormat */
+  pin_verify[5] = pininfo->maxlen; /* wPINMaxExtraDigit */
+  pin_verify[6] = pininfo->minlen; /* wPINMaxExtraDigit */
+  pin_verify[7] = 0x02; /* bEntryValidationCondition: Validation key pressed */
+  if (pininfo->minlen && pininfo->maxlen && pininfo->minlen == pininfo->maxlen)
+    pin_verify[7] |= 0x01; /* Max size reached.  */
+  pin_verify[8] = 0xff; /* bNumberMessage: Default */
+  pin_verify[9] =  0x09; /* wLangId: 0x0409: US English */
+  pin_verify[10] = 0x04; /* wLangId: 0x0409: US English */
+  pin_verify[11] = 0x00; /* bMsgIndex */
+  pin_verify[12] = 0x00; /* bTeoPrologue[0] */
+  pin_verify[13] = 0x00; /* bTeoPrologue[1] */
+  pin_verify[14] = 0x00; /* bTeoPrologue[2] */
+  pin_verify[15] = 0x04; /* ulDataLength */
+  pin_verify[16] = 0x00; /* ulDataLength */
+  pin_verify[17] = 0x00; /* ulDataLength */
+  pin_verify[18] = 0x00; /* ulDataLength */
+  pin_verify[19] = class; /* abData[0] */
+  pin_verify[20] = ins; /* abData[1] */
+  pin_verify[21] = p0; /* abData[2] */
+  pin_verify[22] = p1; /* abData[3] */
+
+  sw = control_pcsc (slot, reader_table[slot].pcsc.verify_ioctl,
+                     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];
+  return sw;
+}
 
 #ifdef HAVE_LIBUSB
 /*
@@ -1945,6 +2245,35 @@ check_ccid_keypad (int slot, int command, int pin_mode,
 }
 
 
+static int
+ccid_keypad_verify (int slot, int class, int ins, int p0, int p1,
+                    struct pininfo_s *pininfo)
+{
+  unsigned char apdu[4];
+  int err, sw;
+  unsigned char result[2];
+  size_t resultlen = 2;
+
+  apdu[0] = class;
+  apdu[1] = ins;
+  apdu[2] = p0;
+  apdu[3] = p1;
+  err = ccid_transceive_secure (reader_table[slot].ccid.handle,
+                                apdu, sizeof apdu,
+                                pininfo->mode, pininfo->minlen, pininfo->maxlen,
+                                pininfo->padlen,
+                                result, 2, &resultlen);
+  if (err)
+    return err;
+
+  if (resultlen < 2)
+    return SW_HOST_INCOMPLETE_CARD_RESPONSE;
+
+  sw = (result[resultlen-2] << 8) | result[resultlen-1];
+  return sw;
+}
+
+
 /* Open the reader and try to read an ATR.  */
 static int
 open_ccid_reader (const char *portstr)
@@ -1989,6 +2318,7 @@ open_ccid_reader (const char *portstr)
   reader_table[slot].check_keypad = check_ccid_keypad;
   reader_table[slot].dump_status_reader = dump_ccid_reader_status;
   reader_table[slot].set_progress_cb = set_progress_cb_ccid_reader;
+  reader_table[slot].keypad_verify = ccid_keypad_verify;
   /* Our CCID reader code does not support T=0 at all, thus reset the
      flag.  */
   reader_table[slot].is_t0 = 0;
@@ -2281,6 +2611,7 @@ open_rapdu_reader (int portno,
   reader_table[slot].send_apdu_reader = my_rapdu_send_apdu;
   reader_table[slot].check_keypad = NULL;
   reader_table[slot].dump_status_reader = NULL;
+  reader_table[slot].keypad_verify = NULL;
 
   dump_reader_status (slot);
   rapdu_msg_release (msg);
@@ -2461,6 +2792,7 @@ apdu_open_reader (const char *portstr, int *r_no_service)
       pcsc_end_transaction   = dlsym (handle, "SCardEndTransaction");
       pcsc_transmit          = dlsym (handle, "SCardTransmit");
       pcsc_set_timeout       = dlsym (handle, "SCardSetTimeout");
+      pcsc_control           = dlsym (handle, "SCardControl");
 
       if (!pcsc_establish_context
           || !pcsc_release_context
@@ -2473,12 +2805,13 @@ apdu_open_reader (const char *portstr, int *r_no_service)
           || !pcsc_begin_transaction
           || !pcsc_end_transaction
           || !pcsc_transmit
+          || !pcsc_control
           /* || !pcsc_set_timeout */)
         {
           /* Note that set_timeout is currently not used and also not
              available under Windows. */
           log_error ("apdu_open_reader: invalid PC/SC driver "
-                     "(%d%d%d%d%d%d%d%d%d%d%d%d)\n",
+                     "(%d%d%d%d%d%d%d%d%d%d%d%d%d)\n",
                      !!pcsc_establish_context,
                      !!pcsc_release_context,
                      !!pcsc_list_readers,
@@ -2490,7 +2823,8 @@ apdu_open_reader (const char *portstr, int *r_no_service)
                      !!pcsc_begin_transaction,
                      !!pcsc_end_transaction,
                      !!pcsc_transmit,
-                     !!pcsc_set_timeout );
+                     !!pcsc_set_timeout,
+                     !!pcsc_control );
           dlclose (handle);
           return -1;
         }
@@ -2894,6 +3228,28 @@ apdu_check_keypad (int slot, int command, int pin_mode,
 }
 
 
+int
+apdu_keypad_verify (int slot, int class, int ins, int p0, int p1, int pin_mode,
+                    int pinlen_min, int pinlen_max, int pin_padlen)
+{
+  struct pininfo_s pininfo;
+
+  pininfo.mode = pin_mode;
+  pininfo.minlen = pinlen_min;
+  pininfo.maxlen = pinlen_max;
+  pininfo.padlen = pin_padlen;
+
+  if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
+    return SW_HOST_NO_DRIVER;
+
+  if (reader_table[slot].keypad_verify)
+    return reader_table[slot].keypad_verify (slot, class, ins, p0, p1,
+                                             &pininfo);
+  else
+    return SW_HOST_NOT_SUPPORTED;
+}
+
+
 /* Dispatcher for the actual send_apdu function. Note, that this
    function should be called in locked state. */
 static int
diff --git a/scd/apdu.h b/scd/apdu.h
index 7c01887..4dff9eb 100644
--- a/scd/apdu.h
+++ b/scd/apdu.h
@@ -114,6 +114,9 @@ int apdu_get_status (int slot, int hang,
                      unsigned int *status, unsigned int *changed);
 int apdu_check_keypad (int slot, int command, int pin_mode,
                        int pinlen_min, int pinlen_max, int pin_padlen);
+int apdu_keypad_verify (int slot, int class, int ins, int p0, int p1,
+                        int pin_mode, int pinlen_min, int pinlen_max,
+                        int pin_padlen);
 int apdu_send_simple (int slot, int extended_mode,
                       int class, int ins, int p0, int p1,
                       int lc, const char *data);
diff --git a/scd/app-dinsig.c b/scd/app-dinsig.c
index 30beb8e..50db78e 100644
--- a/scd/app-dinsig.c
+++ b/scd/app-dinsig.c
@@ -304,7 +304,7 @@ verify_pin (app_t app,
                     gpg_strerror (rc));
           return rc;
         }
-      rc = iso7816_verify_kp (app->slot, 0x81, "", 0, &pininfo);
+      rc = iso7816_verify_kp (app->slot, 0x81, &pininfo);
       /* Dismiss the prompt. */
       pincb (pincb_arg, NULL, NULL);
     }
diff --git a/scd/app-nks.c b/scd/app-nks.c
index c1b2aa3..28ccb9a 100644
--- a/scd/app-nks.c
+++ b/scd/app-nks.c
@@ -803,7 +803,7 @@ verify_pin (app_t app, int pwid, const char *desc,
           return rc;
         }
 
-      rc = iso7816_verify_kp (app->slot, pwid, "", 0, &pininfo);
+      rc = iso7816_verify_kp (app->slot, pwid, &pininfo);
       pincb (pincb_arg, NULL, NULL);  /* Dismiss the prompt. */
     }
   else
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index eb0b4f0..d7efad5 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -1550,7 +1550,7 @@ verify_a_chv (app_t app,
                     gpg_strerror (rc));
           return rc;
         }
-      rc = iso7816_verify_kp (app->slot, 0x80+chvno, "", 0, &pininfo);
+      rc = iso7816_verify_kp (app->slot, 0x80+chvno, &pininfo);
       /* Dismiss the prompt. */
       pincb (pincb_arg, NULL, NULL);
 
@@ -1730,7 +1730,7 @@ verify_chv3 (app_t app,
                         gpg_strerror (rc));
               return rc;
             }
-          rc = iso7816_verify_kp (app->slot, 0x83, "", 0, &pininfo);
+          rc = iso7816_verify_kp (app->slot, 0x83, &pininfo);
           /* Dismiss the prompt. */
           pincb (pincb_arg, NULL, NULL);
         }
diff --git a/scd/iso7816.c b/scd/iso7816.c
index 318fec8..1238552 100644
--- a/scd/iso7816.c
+++ b/scd/iso7816.c
@@ -281,22 +281,16 @@ iso7816_check_keypad (int slot, int command, iso7816_pininfo_t *pininfo)
 
 
 /* Perform a VERIFY command on SLOT using the card holder verification
-   vector CHVNO with a CHV of lenght CHVLEN.  With PININFO non-NULL
-   the keypad of the reader will be used.  Returns 0 on success. */
+   vector CHVNO.  With PININFO non-NULL the keypad of the reader will
+   be used.  Returns 0 on success. */
 gpg_error_t
-iso7816_verify_kp (int slot, int chvno, const char *chv, size_t chvlen,
-                   iso7816_pininfo_t *pininfo)
+iso7816_verify_kp (int slot, int chvno, iso7816_pininfo_t *pininfo)
 {
   int sw;
 
-  if (pininfo && pininfo->mode)
-    sw = apdu_send_simple_kp (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv,
-                              pininfo->mode,
-                              pininfo->minlen,
-                              pininfo->maxlen,
-                              pininfo->padlen);
-  else
-    sw = apdu_send_simple (slot, 0, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv);
+  sw = apdu_keypad_verify (slot, 0x00, CMD_VERIFY, 0, chvno,
+                           pininfo->mode, pininfo->minlen, pininfo->maxlen,
+                           pininfo->padlen);
   return map_sw (sw);
 }
 
@@ -305,7 +299,10 @@ iso7816_verify_kp (int slot, int chvno, const char *chv, size_t chvlen,
 gpg_error_t
 iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen)
 {
-  return iso7816_verify_kp (slot, chvno, chv, chvlen, NULL);
+  int sw;
+
+  sw = apdu_send_simple (slot, 0, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv);
+  return map_sw (sw);
 }
 
 /* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
diff --git a/scd/iso7816.h b/scd/iso7816.h
index a37759d..58e81d4 100644
--- a/scd/iso7816.h
+++ b/scd/iso7816.h
@@ -63,9 +63,7 @@ gpg_error_t iso7816_check_keypad (int slot, int command,
                                   iso7816_pininfo_t *pininfo);
 gpg_error_t iso7816_verify (int slot,
                             int chvno, const char *chv, size_t chvlen);
-gpg_error_t iso7816_verify_kp (int slot,
-                               int chvno, const char *chv, size_t chvlen,
-                               iso7816_pininfo_t *pininfo);
+gpg_error_t iso7816_verify_kp (int slot, int chvno, iso7816_pininfo_t *pininfo);
 gpg_error_t iso7816_change_reference_data (int slot, int chvno,
                                const char *oldchv, size_t oldchvlen,
                                const char *newchv, size_t newchvlen);
diff --git a/scd/pcsc-wrapper.c b/scd/pcsc-wrapper.c
index ee974ac..73b25f4 100644
--- a/scd/pcsc-wrapper.c
+++ b/scd/pcsc-wrapper.c
@@ -178,6 +178,13 @@ long (* pcsc_transmit) (unsigned long card,
                         unsigned long *recv_len);
 long (* pcsc_set_timeout) (unsigned long context,
                            unsigned long timeout);
+long (* pcsc_control) (unsigned long card,
+                       unsigned long control_code,
+                       const void *send_buffer,
+                       unsigned long send_len,
+                       void *recv_buffer,
+                       unsigned long recv_len,
+                       unsigned long *bytes_returned);
 
 
 
@@ -335,6 +342,7 @@ load_pcsc_driver (const char *libname)
   pcsc_end_transaction   = dlsym (handle, "SCardEndTransaction");
   pcsc_transmit          = dlsym (handle, "SCardTransmit");
   pcsc_set_timeout       = dlsym (handle, "SCardSetTimeout");
+  pcsc_control           = dlsym (handle, "SCardControl");
 
   if (!pcsc_establish_context
       || !pcsc_release_context
@@ -347,13 +355,14 @@ load_pcsc_driver (const char *libname)
       || !pcsc_begin_transaction
       || !pcsc_end_transaction
       || !pcsc_transmit
+      || !pcsc_control
       /* || !pcsc_set_timeout */)
     {
       /* Note that set_timeout is currently not used and also not
          available under Windows. */
       fprintf (stderr,
                "apdu_open_reader: invalid PC/SC driver "
-               "(%d%d%d%d%d%d%d%d%d%d%d%d)\n",
+               "(%d%d%d%d%d%d%d%d%d%d%d%d%d)\n",
                !!pcsc_establish_context,
                !!pcsc_release_context,
                !!pcsc_list_readers,
@@ -365,7 +374,8 @@ load_pcsc_driver (const char *libname)
                !!pcsc_begin_transaction,
                !!pcsc_end_transaction,
                !!pcsc_transmit,
-               !!pcsc_set_timeout );
+               !!pcsc_set_timeout,
+               !!pcsc_control );
       dlclose (handle);
       exit (1);
     }
@@ -720,6 +730,38 @@ handle_transmit (unsigned char *argbuf, size_t arglen)
 }
 
 
+/* Handle a control request.  The argument is expected to be a buffer
+   which contains CONTROL_CODE (4-byte) and INPUT_BYTES.
+ */
+static void
+handle_control (unsigned char *argbuf, size_t arglen)
+{
+  long err;
+  unsigned long ioctl_code;
+  unsigned long recv_len = 1024;
+  unsigned char buffer[1024];
+
+  if (arglen < 4)
+    bad_request ("CONTROL");
+
+  ioctl_code = (argbuf[0] << 24) | (argbuf[1] << 16) | (argbuf[2] << 8) | argbuf[3];
+  argbuf += 4;
+  arglen -= 4;
+
+  recv_len = sizeof (buffer);
+  err = pcsc_control (pcsc_card, ioctl_code, argbuf, arglen,
+                      buffer, recv_len, &recv_len);
+  if (err)
+    {
+      if (verbose)
+        fprintf (stderr, PGM": pcsc_control failed: %s (0x%lx)\n",
+                 pcsc_error_string (err), err);
+      request_failed (err);
+      return;
+    }
+  request_succeeded (buffer, recv_len);
+}
+
 
 static void
 print_version (int with_help)
@@ -831,6 +873,10 @@ main (int argc, char **argv)
           handle_reset (argbuffer, arglen);
           break;
 
+        case 6:
+          handle_control (argbuffer, arglen);
+          break;
+
         default:
           fprintf (stderr, PGM ": invalid request 0x%02X\n", c);
           exit (1);

-----------------------------------------------------------------------

Summary of changes:
 scd/ChangeLog      |   35 +++++
 scd/apdu.c         |  362 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 scd/apdu.h         |    3 +
 scd/app-dinsig.c   |    2 +-
 scd/app-nks.c      |    2 +-
 scd/app-openpgp.c  |    4 +-
 scd/iso7816.c      |   23 ++--
 scd/iso7816.h      |    4 +-
 scd/pcsc-wrapper.c |   50 +++++++-
 9 files changed, 460 insertions(+), 25 deletions(-)


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list