[git] GnuPG - branch, STABLE-BRANCH-2-0, updated. gnupg-2.0.19-84-g9fec82a

by NIIBE Yutaka cvs at cvs.gnupg.org
Wed Feb 6 06:15:32 CET 2013


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, STABLE-BRANCH-2-0 has been updated
       via  9fec82a30bec953b09548840dac4e8999310498e (commit)
       via  4a2f1e51339df469cf2284ab342ea23e3921ec9f (commit)
       via  c3070705a4060694bfe5112fa9c1edc9f5479bf4 (commit)
       via  031f783d8a3d242085985b6afb2d67e49e6a1454 (commit)
       via  eec69e5366e00d958f3204eb1aad6871e976293f (commit)
       via  1788aad9c1a6a68a5ae841c8746aabf76e8a9c65 (commit)
       via  85bd703e78768ae5290a64c405f3c9fed46ecff2 (commit)
       via  d1d51464d2db60a801f8f252c4a3386493989b31 (commit)
       via  daafc1c8fdee0e0387dff6f42cfc3b01046480d4 (commit)
       via  15bf5a10d47ae288fc4174424551e2e19e6b7b6a (commit)
       via  15200f7001ce591233e4f266428d97c7e1ee29f1 (commit)
       via  4fe024cf33fcb1c0c789b548de39da2f61154cb9 (commit)
       via  3d863c298b5914958ef1462409dc097b4a076b52 (commit)
       via  7c110e997adda6252dbc7c2ff3fce1db3edaff94 (commit)
       via  2dbd347fbe9765e72041857a5922390e01cf95f1 (commit)
      from  e8ea10990d9b860d9f2863928887811f86c304b6 (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 9fec82a30bec953b09548840dac4e8999310498e
Author: NIIBE Yutaka <gniibe at fsij.org>
Date:   Tue Feb 5 14:59:29 2013 +0900

    scd: Fix check_keypad_request.
    
    * scd/app-openpgp.c (check_keypad_request): 0 means not to use pinpad.

diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index c190098..78cdda3 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -1554,7 +1554,7 @@ check_keypad_request (app_t app, pininfo_t *pininfo, int admin_pin)
   else
     pininfo->fixedlen = app->app_local->keypad.fixedlen_user;
 
-  if (pininfo->fixedlen < 0    /* User requests disable pinpad.  */
+  if (pininfo->fixedlen == 0    /* User requests disable pinpad.  */
       || pininfo->fixedlen < pininfo->minlen
       || pininfo->fixedlen > pininfo->maxlen
       /* Reader doesn't have the capability to input a PIN which

commit 4a2f1e51339df469cf2284ab342ea23e3921ec9f
Author: NIIBE Yutaka <gniibe at fsij.org>
Date:   Tue Feb 5 14:37:14 2013 +0900

    scd: Clean up.
    
    * apdu.h (apdu_send_simple_kp): Remove.
    * apdu.c (apdu_send_simple_kp): Remove.

diff --git a/scd/apdu.c b/scd/apdu.c
index fa5c205..f1e53ea 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -3795,24 +3795,6 @@ apdu_send_simple (int slot, int extended_mode,
 }
 
 
-/* Same as apdu_send_simple but uses the keypad of the reader. */
-int
-apdu_send_simple_kp (int slot, int class, int ins, int p0, int p1,
-                     int lc, const char *data,
-                     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;
-  return send_le (slot, class, ins, p0, p1, lc, data, -1,
-                  NULL, NULL, &pininfo, 0);
-}
-
-
 /* This is a more generic version of the apdu sending routine.  It
    takes an already formatted APDU in APDUDATA or length APDUDATALEN
    and returns with an APDU including the status word.  With
diff --git a/scd/apdu.h b/scd/apdu.h
index 011806c..021508a 100644
--- a/scd/apdu.h
+++ b/scd/apdu.h
@@ -120,10 +120,6 @@ int apdu_keypad_modify (int slot, int class, int ins, int p0, int p1,
 int apdu_send_simple (int slot, int extended_mode,
                       int class, int ins, int p0, int p1,
                       int lc, const char *data);
-int apdu_send_simple_kp (int slot, int class, int ins, int p0, int p1,
-                         int lc, const char *data,  
-                         int pin_mode,
-                         int pinlen_min, int pinlen_max, int pin_padlen);
 int apdu_send (int slot, int extended_mode, 
                int class, int ins, int p0, int p1, int lc, const char *data,
                unsigned char **retbuf, size_t *retbuflen);

commit c3070705a4060694bfe5112fa9c1edc9f5479bf4
Author: NIIBE Yutaka <gniibe at fsij.org>
Date:   Mon Jan 28 11:46:40 2013 +0900

    SCD: Add vendor specific initalization.
    
    * scd/ccid-driver.c (ccid_vendor_specific_init): New.
    (ccid_open_reader): Call ccid_vendor_specific_init.

diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c
index fcc71ba..e01b20c 100644
--- a/scd/ccid-driver.c
+++ b/scd/ccid-driver.c
@@ -305,6 +305,9 @@ static int bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
                     size_t *nread, int expected_type, int seqno, int timeout,
                     int no_debug);
 static int abort_cmd (ccid_driver_t handle, int seqno);
+static int send_escape_cmd (ccid_driver_t handle, const unsigned char *data,
+                            size_t datalen, unsigned char *result,
+                            size_t resultmax, size_t *resultlen);
 
 /* Convert a little endian stored 4 byte value into an unsigned
    integer. */
@@ -1526,7 +1529,30 @@ ccid_get_reader_list (void)
 }
 
 
-/* Open the reader with the internal number READERNO and return a 
+/* Vendor specific custom initialization.  */
+static int
+ccid_vendor_specific_init (ccid_driver_t handle)
+{
+  if (handle->id_vendor == VENDOR_VEGA && handle->id_product == VEGA_ALPHA)
+    {
+      /*
+       * Vega alpha has a feature to show retry counter on the pinpad
+       * display.  But it assumes that the card returns the value of
+       * retry counter by VERIFY with empty data (return code of
+       * 63Cx).  Unfortunately, existing OpenPGP cards don't support
+       * VERIFY command with empty data.  This vendor specific command
+       * sequence is to disable the feature.
+       */
+      const unsigned char cmd[] = "\xb5\x01\x00\x03\x00";
+
+      return send_escape_cmd (handle, cmd, sizeof (cmd), NULL, 0, NULL);
+    }
+
+  return 0;
+}
+
+
+/* Open the reader with the internal number READERNO and return a
    pointer to be used as handle in HANDLE.  Returns 0 on success. */
 int 
 ccid_open_reader (ccid_driver_t *handle, const char *readerid)
@@ -1634,6 +1660,8 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
         }
     }
 
+  rc = ccid_vendor_specific_init (*handle);
+
  leave:
   free (ifcdesc_extra);
   if (rc)

commit 031f783d8a3d242085985b6afb2d67e49e6a1454
Author: NIIBE Yutaka <gniibe at fsij.org>
Date:   Sun Jan 13 12:12:10 2013 +0900

    SCD: Support P=N format for login data.
    
    * scd/app-openpgp.c (parse_login_data): Support P=N format.

diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index 0b3d21d..c190098 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -602,9 +602,9 @@ count_bits (const unsigned char *a, size_t len)
 
     P=<keypad-request>
 
-    Where KEYPAD_REQUEST is 0 or a pair of two integers: <n>,<m>.
-    0 means use keypad with variable length input.  <n>,<m> means use
-    keypad with fixed length input.  N for user PIN, M for admin PIN.
+    Where KEYPAD_REQUEST is in the format of: <n> or <n>,<m>.
+    N for user PIN, M for admin PIN.  If M is missing it means M=N.
+    0 means to force not to use keypad.
 
 */
 static void
@@ -660,24 +660,22 @@ parse_login_data (app_t app)
 
           if (buflen)
             {
-              if (*buffer == '0')
-                {
-                  buffer++;
-                  buflen--;
-                  if (buflen && !(*buffer == '\n' || *buffer == '\x18'))
-                    goto next;
-                  /* Disable use of pinpad.  */
-                  app->app_local->keypad.specified = 1;
-                }
-              else if (digitp (buffer))
+              if (digitp (buffer))
                 {
                   char *q;
                   int n, m;
 
                   n = strtol (buffer, &q, 10);
-                  if (*q++ != ',' || !digitp (q))
-                    goto next;
-                  m = strtol (q, &q, 10);
+                  if (q >= (char *)buffer + buflen
+                      || *q == '\x18' || *q == '\n')
+                    m = n;
+                  else
+                    {
+                      if (*q++ != ',' || !digitp (q))
+                        goto next;
+                      m = strtol (q, &q, 10);
+                    }
+
                   buffer = q;
                   if (buflen < ((unsigned char *)q - buffer))
                     {
@@ -1540,14 +1538,16 @@ static int
 check_keypad_request (app_t app, pininfo_t *pininfo, int admin_pin)
 {
   if (app->app_local->keypad.specified == 0) /* No preference on card.  */
-    if (pininfo->fixedlen == 0) /* Reader has varlen capability.  */
-      return 0;                 /* Then, use pinpad.  */
-    else
-      /*
-       * Reader has limited capability, and it may not match PIN of
-       * the card.
-       */
-      return 1;
+    {
+      if (pininfo->fixedlen == 0) /* Reader has varlen capability.  */
+        return 0;                 /* Then, use pinpad.  */
+      else
+        /*
+         * Reader has limited capability, and it may not match PIN of
+         * the card.
+         */
+        return 1;
+    }
 
   if (admin_pin)
     pininfo->fixedlen = app->app_local->keypad.fixedlen_admin;

commit eec69e5366e00d958f3204eb1aad6871e976293f
Author: NIIBE Yutaka <gniibe at fsij.org>
Date:   Fri Jan 11 13:19:17 2013 +0900

    SCD: Better interoperability.
    
    * scd/apdu.c: Fill bTeoPrologue[2] field.
    --
    ccid-1.4.5 or older requires this field is filled by application.

diff --git a/scd/apdu.c b/scd/apdu.c
index 2e51ea2..fa5c205 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -2114,7 +2114,7 @@ pcsc_keypad_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] = 0x00; /* bTeoPrologue[2] */
+  pin_verify[14] = pininfo->fixedlen + 0x05; /* bTeoPrologue[2] */
   pin_verify[15] = pininfo->fixedlen + 0x05; /* ulDataLength */
   pin_verify[16] = 0x00; /* ulDataLength */
   pin_verify[17] = 0x00; /* ulDataLength */
@@ -2206,7 +2206,7 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
   pin_modify[16] = 0x00; /* bMsgIndex3 */
   pin_modify[17] = 0x00; /* bTeoPrologue[0] */
   pin_modify[18] = 0x00; /* bTeoPrologue[1] */
-  pin_modify[19] = 0x00; /* bTeoPrologue[2] */
+  pin_modify[19] = 2 * pininfo->fixedlen + 0x05; /* bTeoPrologue[2] */
   pin_modify[20] = 2 * pininfo->fixedlen + 0x05; /* ulDataLength */
   pin_modify[21] = 0x00; /* ulDataLength */
   pin_modify[22] = 0x00; /* ulDataLength */

commit 1788aad9c1a6a68a5ae841c8746aabf76e8a9c65
Author: NIIBE Yutaka <gniibe at fsij.org>
Date:   Fri Jan 11 10:41:38 2013 +0900

    SCD: Defaults to use pinpad if the reader has the capability.
    
    * scd/app-openpgp.c (struct app_local_s): Remove VARLEN.
    (parse_login_data): "P=0" means to disable pinpad.
    (check_keypad_request): Default is to use pinpad if available.

diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index 5929473..0b3d21d 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -195,7 +195,6 @@ struct app_local_s {
   struct
   {
     unsigned int specified:1;
-    unsigned int varlen:1;
     int fixedlen_user;
     int fixedlen_admin;
   } keypad;
@@ -619,9 +618,8 @@ parse_login_data (app_t app)
   app->app_local->flags.no_sync = 0;
   app->app_local->flags.def_chv2 = 0;
   app->app_local->keypad.specified = 0;
-  app->app_local->keypad.varlen = 0;
-  app->app_local->keypad.fixedlen_user = 6;
-  app->app_local->keypad.fixedlen_admin = 8;
+  app->app_local->keypad.fixedlen_user = -1;
+  app->app_local->keypad.fixedlen_admin = -1;
 
   /* Read the DO.  */
   relptr = get_one_do (app, 0x005E, &buffer, &buflen, NULL);
@@ -668,8 +666,8 @@ parse_login_data (app_t app)
                   buflen--;
                   if (buflen && !(*buffer == '\n' || *buffer == '\x18'))
                     goto next;
+                  /* Disable use of pinpad.  */
                   app->app_local->keypad.specified = 1;
-                  app->app_local->keypad.varlen = 1;
                 }
               else if (digitp (buffer))
                 {
@@ -1534,34 +1532,36 @@ do_readcert (app_t app, const char *certid,
 }
 
 
-/* Decide if we use keypad of reader for PIN input according to the
-   user preference on the card.  Returns 0 if we use keypad, 1 otherwise.  */
+/* Decide if we use the keypad of the reader for PIN input according
+   to the user preference on the card, and the capability of the
+   reader.  This routine is only called when the reader has keypad.
+   Returns 0 if we use keypad, 1 otherwise.  */
 static int
 check_keypad_request (app_t app, pininfo_t *pininfo, int admin_pin)
 {
-  /* User specifies no preference on card, then, use pinentry.  */
-  if (app->app_local->keypad.specified == 0)
-    return 1;
-
-  if (app->app_local->keypad.varlen)
-    if (pininfo->fixedlen == 0)
-      return 0;
+  if (app->app_local->keypad.specified == 0) /* No preference on card.  */
+    if (pininfo->fixedlen == 0) /* Reader has varlen capability.  */
+      return 0;                 /* Then, use pinpad.  */
     else
-      /* On card, user specifies varlen but reader doesn't have the feature.  */
+      /*
+       * Reader has limited capability, and it may not match PIN of
+       * the card.
+       */
       return 1;
+
+  if (admin_pin)
+    pininfo->fixedlen = app->app_local->keypad.fixedlen_admin;
   else
-    {
-      if (admin_pin)
-        pininfo->fixedlen = app->app_local->keypad.fixedlen_admin;
-      else
-        pininfo->fixedlen = app->app_local->keypad.fixedlen_user;
+    pininfo->fixedlen = app->app_local->keypad.fixedlen_user;
 
-      if (pininfo->fixedlen < pininfo->minlen
-          || pininfo->fixedlen > pininfo->maxlen)
-        return 1;
+  if (pininfo->fixedlen < 0    /* User requests disable pinpad.  */
+      || pininfo->fixedlen < pininfo->minlen
+      || pininfo->fixedlen > pininfo->maxlen
+      /* Reader doesn't have the capability to input a PIN which
+       * length is FIXEDLEN.  */)
+    return 1;
 
-      return 0;
-    }
+  return 0;
 }
 
 

commit 85bd703e78768ae5290a64c405f3c9fed46ecff2
Author: NIIBE Yutaka <gniibe at fsij.org>
Date:   Thu Jan 10 15:58:43 2013 +0900

    SCD: handle keypad request on the card.
    
    * scd/app-openpgp.c: Add 2013.
    (struct app_local_s): Add keypad structure.
    (parse_login_data): Add parsing keypad request on the card.
    (check_keypad_request): New.
    (verify_a_chv, verify_chv3, do_change_pin): Call check_keypad_request
    to determine use of keypad.

diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index d3c309e..5929473 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -1,6 +1,6 @@
 /* app-openpgp.c - The OpenPGP card application.
  * Copyright (C) 2003, 2004, 2005, 2007, 2008,
- *               2009 Free Software Foundation, Inc.
+ *               2009, 2013 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -191,6 +191,15 @@ struct app_local_s {
     unsigned int def_chv2:1;  /* Use 123456 for CHV2.  */
   } flags;
 
+  /* Keypad request specified on card.  */
+  struct
+  {
+    unsigned int specified:1;
+    unsigned int varlen:1;
+    int fixedlen_user;
+    int fixedlen_admin;
+  } keypad;
+
   struct
   {
     unsigned int n_bits;     /* Size of the modulus in bits.  The rest
@@ -581,17 +590,23 @@ count_bits (const unsigned char *a, size_t len)
    Everything up to a LF is considered a mailbox or account name.  If
    the first LF is followed by DC4 (0x14) control sequence are
    expected up to the next LF.  Control sequences are separated by FS
-   (0x18) and consist of key=value pairs.  There is one key defined:
+   (0x18) and consist of key=value pairs.  There are two keys defined:
 
     F=<flags>
 
-    Were FLAGS is a plain hexadecimal number representing flag values.
+    Where FLAGS is a plain hexadecimal number representing flag values.
     The lsb is here the rightmost bit.  Defined flags bits are:
 
       Bit 0 = CHV1 and CHV2 are not syncronized
       Bit 1 = CHV2 has been been set to the default PIN of "123456"
               (this implies that bit 0 is also set).
 
+    P=<keypad-request>
+
+    Where KEYPAD_REQUEST is 0 or a pair of two integers: <n>,<m>.
+    0 means use keypad with variable length input.  <n>,<m> means use
+    keypad with fixed length input.  N for user PIN, M for admin PIN.
+
 */
 static void
 parse_login_data (app_t app)
@@ -603,6 +618,10 @@ parse_login_data (app_t app)
   /* Set defaults.  */
   app->app_local->flags.no_sync = 0;
   app->app_local->flags.def_chv2 = 0;
+  app->app_local->keypad.specified = 0;
+  app->app_local->keypad.varlen = 0;
+  app->app_local->keypad.fixedlen_user = 6;
+  app->app_local->keypad.fixedlen_admin = 8;
 
   /* Read the DO.  */
   relptr = get_one_do (app, 0x005E, &buffer, &buflen, NULL);
@@ -628,11 +647,56 @@ parse_login_data (app_t app)
              any leading digits but bail out on invalid characters. */
           for (p=buffer+2, len = buflen-2; len && hexdigitp (p); p++, len--)
             lastdig = xtoi_1 (p);
+          buffer = p;
+          buflen = len;
           if (len && !(*p == '\n' || *p == '\x18'))
             goto next;  /* Invalid characters in field.  */
           app->app_local->flags.no_sync = !!(lastdig & 1);
           app->app_local->flags.def_chv2 = (lastdig & 3) == 3;
         }
+      else if (buflen > 1 && *buffer == 'P' && buffer[1] == '=')
+        {
+          /* Keypad request control sequence found.  */
+          buffer += 2;
+          buflen -= 2;
+
+          if (buflen)
+            {
+              if (*buffer == '0')
+                {
+                  buffer++;
+                  buflen--;
+                  if (buflen && !(*buffer == '\n' || *buffer == '\x18'))
+                    goto next;
+                  app->app_local->keypad.specified = 1;
+                  app->app_local->keypad.varlen = 1;
+                }
+              else if (digitp (buffer))
+                {
+                  char *q;
+                  int n, m;
+
+                  n = strtol (buffer, &q, 10);
+                  if (*q++ != ',' || !digitp (q))
+                    goto next;
+                  m = strtol (q, &q, 10);
+                  buffer = q;
+                  if (buflen < ((unsigned char *)q - buffer))
+                    {
+                      buflen = 0;
+                      break;
+                    }
+                  else
+                    buflen -= ((unsigned char *)q - buffer);
+
+                  if (buflen && !(*buffer == '\n' || *buffer == '\x18'))
+                    goto next;
+                  app->app_local->keypad.specified = 1;
+                  app->app_local->keypad.fixedlen_user = n;
+                  app->app_local->keypad.fixedlen_admin = m;
+                }
+            }
+        }
     next:
       for (; buflen && *buffer != '\x18'; buflen--, buffer++)
         if (*buffer == '\n')
@@ -1470,6 +1534,37 @@ do_readcert (app_t app, const char *certid,
 }
 
 
+/* Decide if we use keypad of reader for PIN input according to the
+   user preference on the card.  Returns 0 if we use keypad, 1 otherwise.  */
+static int
+check_keypad_request (app_t app, pininfo_t *pininfo, int admin_pin)
+{
+  /* User specifies no preference on card, then, use pinentry.  */
+  if (app->app_local->keypad.specified == 0)
+    return 1;
+
+  if (app->app_local->keypad.varlen)
+    if (pininfo->fixedlen == 0)
+      return 0;
+    else
+      /* On card, user specifies varlen but reader doesn't have the feature.  */
+      return 1;
+  else
+    {
+      if (admin_pin)
+        pininfo->fixedlen = app->app_local->keypad.fixedlen_admin;
+      else
+        pininfo->fixedlen = app->app_local->keypad.fixedlen_user;
+
+      if (pininfo->fixedlen < pininfo->minlen
+          || pininfo->fixedlen > pininfo->maxlen)
+        return 1;
+
+      return 0;
+    }
+}
+
+
 /* Verify a CHV either using using the pinentry or if possibile by
    using a keypad.  PINCB and PINCB_ARG describe the usual callback
    for the pinentry.  CHVNO must be either 1 or 2. SIGCOUNT is only
@@ -1537,7 +1632,8 @@ verify_a_chv (app_t app,
 
 
   if (!opt.disable_keypad
-      && !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo) )
+      && !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo)
+      && !check_keypad_request (app, &pininfo, 0))
     {
       /* The reader supports the verify command through the keypad.
          Note that the pincb appends a text to the prompt telling the
@@ -1720,7 +1816,8 @@ verify_chv3 (app_t app,
         return rc;
 
       if (!opt.disable_keypad
-          && !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo) )
+          && !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo)
+          && !check_keypad_request (app, &pininfo, 1))
         {
           /* The reader supports the verify command through the keypad. */
           rc = pincb (pincb_arg, prompt, NULL);
@@ -1970,7 +2067,8 @@ do_change_pin (app_t app, ctrl_t ctrl,  const char *chvnostr,
 
       if (!opt.disable_keypad
           && !iso7816_check_keypad (app->slot,
-                                    ISO7816_CHANGE_REFERENCE_DATA, &pininfo))
+                                    ISO7816_CHANGE_REFERENCE_DATA, &pininfo)
+          && !check_keypad_request (app, &pininfo, chvno == 3))
         use_keypad = 1;
 
       if (reset_mode)

commit d1d51464d2db60a801f8f252c4a3386493989b31
Author: NIIBE Yutaka <gniibe at fsij.org>
Date:   Thu Jan 10 15:52:24 2013 +0900

    SCD: Minor fix of ccid-driver.
    
    * scd/ccid-driver.c (VENDOR_VEGA): Fix typo.

diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c
index ba32a42..fcc71ba 100644
--- a/scd/ccid-driver.c
+++ b/scd/ccid-driver.c
@@ -211,7 +211,7 @@ enum {
   VENDOR_SCM    = 0x04e6,
   VENDOR_OMNIKEY= 0x076b,
   VENDOR_GEMPC  = 0x08e6,
-  VENDER_VEGA   = 0x0982,
+  VENDOR_VEGA   = 0x0982,
   VENDOR_KAAN   = 0x0d46,
   VENDOR_FSIJ   = 0x234b,
   VENDOR_VASCO  = 0x1a44

commit daafc1c8fdee0e0387dff6f42cfc3b01046480d4
Author: NIIBE Yutaka <gniibe at fsij.org>
Date:   Thu Jan 10 10:49:27 2013 +0900

    SCD: Add support of Covadis VEGA_ALPHA reader.
    
    * scd/ccid-driver.c: Add 2013.
    (VENDER_VEGA, VEGA_ALPHA):New.
    (ccid_transceive_secure): VEGA_ALPHA is same firmware as GEMPC_PINPAD.
    Change bNumberMessage to 0x01, as it works better (was: 0xff).

diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c
index ad404cd..ba32a42 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.
@@ -211,6 +211,7 @@ enum {
   VENDOR_SCM    = 0x04e6,
   VENDOR_OMNIKEY= 0x076b,
   VENDOR_GEMPC  = 0x08e6,
+  VENDER_VEGA   = 0x0982,
   VENDOR_KAAN   = 0x0d46,
   VENDOR_FSIJ   = 0x234b,
   VENDOR_VASCO  = 0x1a44
@@ -224,7 +225,8 @@ enum {
 #define SCM_SPR532      0xe003
 #define CHERRY_ST2000   0x003e
 #define VASCO_920       0x0920
-#define GEMPC_PINPAD	0x3478
+#define GEMPC_PINPAD    0x3478
+#define VEGA_ALPHA      0x0008
 
 /* A list and a table with special transport descriptions. */
 enum {
@@ -2383,7 +2385,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);
@@ -2392,91 +2394,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;
@@ -2605,16 +2607,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 */
@@ -2622,33 +2624,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. */
@@ -3299,7 +3301,7 @@ ccid_transceive (ccid_driver_t handle,
 int
 ccid_transceive_secure (ccid_driver_t handle,
                         const unsigned char *apdu_buf, size_t apdu_buflen,
-			pininfo_t *pininfo,
+                        pininfo_t *pininfo,
                         unsigned char *resp, size_t maxresplen, size_t *nresp)
 {
   int rc;
@@ -3361,16 +3363,17 @@ ccid_transceive_secure (ccid_driver_t handle,
       if (handle->id_product != CHERRY_ST2000)
         cherry_mode = 1;
       break;
-    case VENDOR_GEMPC:
-      if (handle->id_product == GEMPC_PINPAD)
-	{
-	  enable_varlen = 0;
-	  pininfo->minlen = 4;
-	  pininfo->maxlen = 8;
-	  break;
-	}
-      /* fall through */
     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;
     }
 
@@ -3413,8 +3416,8 @@ ccid_transceive_secure (ccid_driver_t handle,
   else
     {
       msg[13] = pininfo->fixedlen; /* bmPINBlockString:
-				      0 bits of pin length to insert.
-				      PIN block size by fixedlen.  */
+                                      0 bits of pin length to insert.
+                                      PIN block size by fixedlen.  */
       msg[14] = 0x00; /* bmPINLengthFormat:
                          Units are bytes, position is 0. */
     }
@@ -3446,7 +3449,7 @@ ccid_transceive_secure (ccid_driver_t handle,
   msglen++;
 
   if (apdu_buf[1] == 0x20)
-    msg[msglen++] = 0xff; /* bNumberMessage: Default. */
+    msg[msglen++] = 0x01; /* bNumberMessage. */
   else
     msg[msglen++] = 0x03; /* bNumberMessage. */
 

commit 15bf5a10d47ae288fc4174424551e2e19e6b7b6a
Author: NIIBE Yutaka <gniibe at fsij.org>
Date:   Wed Jan 9 16:40:41 2013 +0900

    SCD: Support fixed length PIN input for keypad (PC/SC).
    
    * scd/apdu.c (pcsc_keypad_verify): SUpport fixed length PIN input for
    keypad.
    (pcsc_keypad_modify): Likewise.
    * scd/ccid-driver.c (ccid_transceive_secure): Clean up.

diff --git a/scd/apdu.c b/scd/apdu.c
index dddaa1e..2e51ea2 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -2072,7 +2072,7 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
 {
   int sw;
   unsigned char *pin_verify;
-  int len = PIN_VERIFY_STRUCTURE_SIZE;
+  int len = PIN_VERIFY_STRUCTURE_SIZE + pininfo->fixedlen;
   unsigned char result[2];
   size_t resultlen = 2;
 
@@ -2080,7 +2080,7 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
       && (sw = reset_pcsc_reader (slot)))
     return sw;
 
-  if (pininfo->fixedlen != 0)
+  if (pininfo->fixedlen < 0 || pininfo->fixedlen >= 16)
     return SW_NOT_SUPPORTED;
 
   if (!pininfo->minlen)
@@ -2101,7 +2101,7 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
   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[3] = pininfo->fixedlen; /* bmPINBlockString */
   pin_verify[4] = 0x00; /* bmPINLengthFormat */
   pin_verify[5] = pininfo->maxlen; /* wPINMaxExtraDigit */
   pin_verify[6] = pininfo->minlen; /* wPINMaxExtraDigit */
@@ -2115,7 +2115,7 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
   pin_verify[12] = 0x00; /* bTeoPrologue[0] */
   pin_verify[13] = 0x00; /* bTeoPrologue[1] */
   pin_verify[14] = 0x00; /* bTeoPrologue[2] */
-  pin_verify[15] = 0x05; /* ulDataLength */
+  pin_verify[15] = pininfo->fixedlen + 0x05; /* ulDataLength */
   pin_verify[16] = 0x00; /* ulDataLength */
   pin_verify[17] = 0x00; /* ulDataLength */
   pin_verify[18] = 0x00; /* ulDataLength */
@@ -2123,7 +2123,9 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
   pin_verify[20] = ins; /* abData[1] */
   pin_verify[21] = p0; /* abData[2] */
   pin_verify[22] = p1; /* abData[3] */
-  pin_verify[23] = 0x00; /* abData[4] */
+  pin_verify[23] = pininfo->fixedlen; /* abData[4] */
+  if (pininfo->fixedlen)
+    memset (&pin_verify[24], 0xff, pininfo->fixedlen);
 
   if (DBG_CARD_IO)
     log_debug ("send secure: c=%02X i=%02X p1=%02X p2=%02X len=%d pinmax=%d\n",
@@ -2151,7 +2153,7 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
 {
   int sw;
   unsigned char *pin_modify;
-  int len = PIN_MODIFY_STRUCTURE_SIZE;
+  int len = PIN_MODIFY_STRUCTURE_SIZE + 2 * pininfo->fixedlen;
   unsigned char result[2];
   size_t resultlen = 2;
 
@@ -2159,7 +2161,7 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
       && (sw = reset_pcsc_reader (slot)))
     return sw;
 
-  if (pininfo->fixedlen != 0)
+  if (pininfo->fixedlen < 0 || pininfo->fixedlen >= 16)
     return SW_NOT_SUPPORTED;
 
   if (!pininfo->minlen)
@@ -2180,10 +2182,10 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
   pin_modify[0] = 0x00; /* bTimerOut */
   pin_modify[1] = 0x00; /* bTimerOut2 */
   pin_modify[2] = 0x82; /* bmFormatString: Byte, pos=0, left, ASCII. */
-  pin_modify[3] = 0x00; /* bmPINBlockString */
+  pin_modify[3] = pininfo->fixedlen; /* bmPINBlockString */
   pin_modify[4] = 0x00; /* bmPINLengthFormat */
   pin_modify[5] = 0x00; /* bInsertionOffsetOld */
-  pin_modify[6] = 0x00; /* bInsertionOffsetNew */
+  pin_modify[6] = pininfo->fixedlen; /* bInsertionOffsetNew */
   pin_modify[7] = pininfo->maxlen; /* wPINMaxExtraDigit */
   pin_modify[8] = pininfo->minlen; /* wPINMaxExtraDigit */
   pin_modify[9] = (p0 == 0 ? 0x03 : 0x01);
@@ -2205,7 +2207,7 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
   pin_modify[17] = 0x00; /* bTeoPrologue[0] */
   pin_modify[18] = 0x00; /* bTeoPrologue[1] */
   pin_modify[19] = 0x00; /* bTeoPrologue[2] */
-  pin_modify[20] = 0x05; /* ulDataLength */
+  pin_modify[20] = 2 * pininfo->fixedlen + 0x05; /* ulDataLength */
   pin_modify[21] = 0x00; /* ulDataLength */
   pin_modify[22] = 0x00; /* ulDataLength */
   pin_modify[23] = 0x00; /* ulDataLength */
@@ -2213,7 +2215,9 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
   pin_modify[25] = ins; /* abData[1] */
   pin_modify[26] = p0; /* abData[2] */
   pin_modify[27] = p1; /* abData[3] */
-  pin_modify[28] = 0x00; /* abData[4] */
+  pin_modify[28] = 2 * pininfo->fixedlen; /* abData[4] */
+  if (pininfo->fixedlen)
+    memset (&pin_modify[29], 0xff, 2 * pininfo->fixedlen);
 
   if (DBG_CARD_IO)
     log_debug ("send secure: c=%02X i=%02X p1=%02X p2=%02X len=%d pinmax=%d\n",
diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c
index 7cb5398..ad404cd 100644
--- a/scd/ccid-driver.c
+++ b/scd/ccid-driver.c
@@ -3412,14 +3412,9 @@ ccid_transceive_secure (ccid_driver_t handle,
     }
   else
     {
-      if (pininfo->fixedlen == 0)
-	msg[13] = 0x00; /* bmPINBlockString:
-			   0 bits of pin length to insert.
-			   0 bytes of PIN block size.  */
-      else
-	msg[13] = pininfo->fixedlen; /* bmPINBlockString:
-					0 bits of pin length to insert.
-					PIN block size by fixedlen.  */
+      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. */
     }
@@ -3428,10 +3423,7 @@ ccid_transceive_secure (ccid_driver_t handle,
   if (apdu_buf[1] == 0x24)
     {
       msg[msglen++] = 0;    /* bInsertionOffsetOld */
-      if (pininfo->fixedlen == 0)
-	msg[msglen++] = 0;    /* bInsertionOffsetNew */
-      else
-	msg[msglen++] = pininfo->fixedlen;    /* bInsertionOffsetNew */
+      msg[msglen++] = pininfo->fixedlen;    /* bInsertionOffsetNew */
     }
 
   /* The following is a little endian word. */

commit 15200f7001ce591233e4f266428d97c7e1ee29f1
Author: NIIBE Yutaka <gniibe at fsij.org>
Date:   Wed Jan 9 16:23:55 2013 +0900

    SCD: Support fixed length PIN input for keypad.
    
    * scd/iso7816.h (struct pininfo_s): Remove MODE and add FIXEDLEN.
    * scd/app-dinsig.c (verify_pin): Initialize FIXEDLEN to unknown.
    * scd/app-nks.c (verify_pin): Likewise.
    * scd/app-openpgp.c (verify_a_chv, verify_chv3, do_change_pin):
    Likewise.
    * scd/apdu.c (check_pcsc_keypad): Add comment.
    (pcsc_keypad_verify, pcsc_keypad_modify): PC/SC driver only support
    readers with the feature of variable length input (yet).
    (apdu_check_keypad): Set FIXEDLEN.
    * scd/ccid-driver.c (ccid_transceive_secure): Add GEMPC_PINPAD
    specific settings.
    Support fixed length PIN input for keypad.

diff --git a/scd/apdu.c b/scd/apdu.c
index 2fd2d4b..dddaa1e 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -2016,7 +2016,7 @@ check_pcsc_keypad (int slot, int command, pininfo_t *pininfo)
   size_t len = 256;
   int sw;
 
-  (void)pininfo;
+  (void)pininfo;      /* XXX: Identify reader and set pininfo->fixedlen.  */
 
  check_again:
   if (command == ISO7816_VERIFY)
@@ -2080,7 +2080,7 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
       && (sw = reset_pcsc_reader (slot)))
     return sw;
 
-  if (pininfo->mode != 1)
+  if (pininfo->fixedlen != 0)
     return SW_NOT_SUPPORTED;
 
   if (!pininfo->minlen)
@@ -2159,7 +2159,7 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
       && (sw = reset_pcsc_reader (slot)))
     return sw;
 
-  if (pininfo->mode != 1)
+  if (pininfo->fixedlen != 0)
     return SW_NOT_SUPPORTED;
 
   if (!pininfo->minlen)
@@ -3292,7 +3292,7 @@ apdu_check_keypad (int slot, int command, pininfo_t *pininfo)
     return SW_HOST_NO_DRIVER;
 
   if (opt.enable_keypad_varlen)
-    pininfo->mode = 0;
+    pininfo->fixedlen = 0;
 
   if (reader_table[slot].check_keypad)
     {
diff --git a/scd/app-dinsig.c b/scd/app-dinsig.c
index 5a2a902..07a152a 100644
--- a/scd/app-dinsig.c
+++ b/scd/app-dinsig.c
@@ -288,7 +288,7 @@ verify_pin (app_t app,
     return 0;  /* No need to verify it again.  */
 
   memset (&pininfo, 0, sizeof pininfo);
-  pininfo.mode = 1;
+  pininfo.fixedlen = -1;
   pininfo.minlen = 6;
   pininfo.maxlen = 8;
 
diff --git a/scd/app-nks.c b/scd/app-nks.c
index c53f45a..b8350b6 100644
--- a/scd/app-nks.c
+++ b/scd/app-nks.c
@@ -788,7 +788,7 @@ verify_pin (app_t app, int pwid, const char *desc,
     desc = "PIN";
 
   memset (&pininfo, 0, sizeof pininfo);
-  pininfo.mode = 1;
+  pininfo.fixedlen = -1;
   pininfo.minlen = 6;
   pininfo.maxlen = 16;
 
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index 5292f1d..d3c309e 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -1516,7 +1516,7 @@ verify_a_chv (app_t app,
     }
 
   memset (&pininfo, 0, sizeof pininfo);
-  pininfo.mode = 1;
+  pininfo.fixedlen = -1;
   pininfo.minlen = minlen;
 
 
@@ -1712,7 +1712,7 @@ verify_chv3 (app_t app,
       char *prompt;
 
       memset (&pininfo, 0, sizeof pininfo);
-      pininfo.mode = 1;
+      pininfo.fixedlen = -1;
       pininfo.minlen = minlen;
 
       rc = build_enter_admin_pin_prompt (app, &prompt);
@@ -1923,7 +1923,7 @@ do_change_pin (app_t app, ctrl_t ctrl,  const char *chvnostr,
 
   (void)ctrl;
   memset (&pininfo, 0, sizeof pininfo);
-  pininfo.mode = 1;
+  pininfo.fixedlen = -1;
   pininfo.minlen = minlen;
 
   if (reset_mode && chvno == 3)
diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c
index b057861..7cb5398 100644
--- a/scd/ccid-driver.c
+++ b/scd/ccid-driver.c
@@ -3362,23 +3362,27 @@ ccid_transceive_secure (ccid_driver_t handle,
         cherry_mode = 1;
       break;
     case VENDOR_GEMPC:
-      enable_varlen = 0;
       if (handle->id_product == GEMPC_PINPAD)
-	break;
+	{
+	  enable_varlen = 0;
+	  pininfo->minlen = 4;
+	  pininfo->maxlen = 8;
+	  break;
+	}
       /* fall through */
     default:
      return CCID_DRIVER_ERR_NOT_SUPPORTED;
     }
 
   if (enable_varlen)
-    pininfo->mode = 0;
-
-  if (pininfo->mode != 0 && pininfo->mode != 1)
-    return CCID_DRIVER_ERR_NOT_SUPPORTED;
+    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)
     {
@@ -3408,9 +3412,14 @@ 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.  */
+      if (pininfo->fixedlen == 0)
+	msg[13] = 0x00; /* bmPINBlockString:
+			   0 bits of pin length to insert.
+			   0 bytes of PIN block size.  */
+      else
+	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. */
     }
@@ -3419,7 +3428,10 @@ ccid_transceive_secure (ccid_driver_t handle,
   if (apdu_buf[1] == 0x24)
     {
       msg[msglen++] = 0;    /* bInsertionOffsetOld */
-      msg[msglen++] = 0;    /* bInsertionOffsetNew */
+      if (pininfo->fixedlen == 0)
+	msg[msglen++] = 0;    /* bInsertionOffsetNew */
+      else
+	msg[msglen++] = pininfo->fixedlen;    /* bInsertionOffsetNew */
     }
 
   /* The following is a little endian word. */
@@ -3458,10 +3470,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 */
@@ -3469,6 +3489,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);
 
diff --git a/scd/iso7816.h b/scd/iso7816.h
index 3db07a5..0815781 100644
--- a/scd/iso7816.h
+++ b/scd/iso7816.h
@@ -34,7 +34,12 @@
    ccid-driver.c for details. */
 struct pininfo_s
 {
-  int mode;    /* 0: Use variable length input.  1: Use fixed length input. */
+  int fixedlen;  /*
+		  * -1: Variable length input is not supported,
+		  *     no information of fixed length yet.
+		  *  0: Use variable length input.
+		  * >0: Fixed length of PIN.
+		  */
   int minlen;
   int maxlen;
 };

commit 4fe024cf33fcb1c0c789b548de39da2f61154cb9
Author: NIIBE Yutaka <gniibe at fsij.org>
Date:   Wed Jan 9 14:10:08 2013 +0900

    SCD: API cleanup for keypad handling.
    
    * scd/iso7816.h (struct pininfo_s): Rename from iso7816_pininfo_s.
    Change meaning of MODE.
    (pininfo_t): Rename from iso7816_pininfo_t.
    * scd/sc-copykeys.c: Include "iso7816.h".
    * scd/scdaemon.c, scd/command.c: Likewise.
    * scd/ccid-driver.c: Include "scdaemon.h" and "iso7816.h".
    (ccid_transceive_secure): Follow the change of PININFO_T.
    * scd/app.c: Include "apdu.h" after "iso7816.h".
    * scd/iso7816.c (iso7816_check_keypad, iso7816_verify_kp)
    (iso7816_change_reference_data_kp): Follow the change of API.
    * scd/apdu.c (struct reader_table_s): Change API of CHECK_KEYPAD,
    KEYPAD_VERIFY, KEYPAD_MODIFY to have arg of PININFO_T.
    (check_pcsc_keypad, check_ccid_keypad): Likewise.
    (apdu_check_keypad, apdu_keypad_verify, apdu_keypad_modify): Likewise.
    (pcsc_keypad_verify, pcsc_keypad_modify, ct_send_apdu)
    (pcsc_send_apdu_direct,  pcsc_send_apdu_wrapped, pcsc_send_apdu)
    (send_apdu_ccid, ccid_keypad_operation, my_rapdu_send_apdu, send_apdu)
    (send_le): Follow the change of API.
    * scd/apdu.h (apdu_check_keypad, apdu_keypad_verify)
    (apdu_keypad_modify): Change the API.
    * scd/app-dinsig.c, scd/app-nks.c, scd/app-openpgp.c: Follow the
    change.

diff --git a/scd/apdu.c b/scd/apdu.c
index 21cd574..2fd2d4b 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -59,10 +59,9 @@
 #include "exechelp.h"
 #endif /* GNUPG_MAJOR_VERSION != 1 */
 
+#include "iso7816.h"
 #include "apdu.h"
 #include "ccid-driver.h"
-#include "iso7816.h"
-
 
 /* Due to conflicting use of threading libraries we usually can't link
    against libpcsclite.   Instead we use a wrapper program.  */
@@ -82,8 +81,6 @@
 #define DLSTDCALL
 #endif
 
-#define pininfo_s iso7816_pininfo_s
-
 /* A structure to collect information pertaining to one reader
    slot. */
 struct reader_table_s {
@@ -98,12 +95,12 @@ struct reader_table_s {
   int (*reset_reader)(int);
   int (*get_status_reader)(int, unsigned int *);
   int (*send_apdu_reader)(int,unsigned char *,size_t,
-                          unsigned char *, size_t *, struct pininfo_s *);
-  int (*check_keypad)(int, int, int, int, int);
+                          unsigned char *, size_t *, pininfo_t *);
+  int (*check_keypad)(int, int, pininfo_t *);
   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 *);
-  int (*keypad_modify)(int, int, int, int, int, struct pininfo_s *);
+  int (*keypad_verify)(int, int, int, int, int, pininfo_t *);
+  int (*keypad_modify)(int, int, int, int, int, pininfo_t *);
 
   struct {
     ccid_driver_t handle;
@@ -304,12 +301,11 @@ 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);
+static int check_pcsc_keypad (int slot, int command, pininfo_t *pininfo);
 static int pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
-                               struct pininfo_s *pininfo);
+                               pininfo_t *pininfo);
 static int pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
-                               struct pininfo_s *pininfo);
+                               pininfo_t *pininfo);
 
 
 
@@ -621,7 +617,7 @@ ct_get_status (int slot, unsigned int *status)
    set to BUFLEN.  Returns: CT API error code. */
 static int
 ct_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
-              unsigned char *buffer, size_t *buflen, struct pininfo_s *pininfo)
+              unsigned char *buffer, size_t *buflen, pininfo_t *pininfo)
 {
   int rc;
   unsigned char dad[1], sad[1];
@@ -1053,7 +1049,7 @@ pcsc_get_status (int slot, unsigned int *status)
 static int
 pcsc_send_apdu_direct (int slot, unsigned char *apdu, size_t apdulen,
                        unsigned char *buffer, size_t *buflen,
-                       struct pininfo_s *pininfo)
+                       pininfo_t *pininfo)
 {
   long err;
   struct pcsc_io_request_s send_pci;
@@ -1089,7 +1085,7 @@ pcsc_send_apdu_direct (int slot, unsigned char *apdu, size_t apdulen,
 static int
 pcsc_send_apdu_wrapped (int slot, unsigned char *apdu, size_t apdulen,
                         unsigned char *buffer, size_t *buflen,
-                        struct pininfo_s *pininfo)
+                        pininfo_t *pininfo)
 {
   long err;
   reader_table_t slotp;
@@ -1208,7 +1204,7 @@ pcsc_send_apdu_wrapped (int slot, unsigned char *apdu, size_t apdulen,
 static int
 pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
                 unsigned char *buffer, size_t *buflen,
-                struct pininfo_s *pininfo)
+                pininfo_t *pininfo)
 {
 #ifdef NEED_PCSC_WRAPPER
   return pcsc_send_apdu_wrapped (slot, apdu, apdulen, buffer, buflen, pininfo);
@@ -2014,16 +2010,13 @@ 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)
+check_pcsc_keypad (int slot, int command, pininfo_t *pininfo)
 {
   unsigned char buf[256];
   size_t len = 256;
   int sw;
 
-  (void)pin_mode;
-  (void)pinlen_min;
-  (void)pinlen_max;
+  (void)pininfo;
 
  check_again:
   if (command == ISO7816_VERIFY)
@@ -2075,7 +2068,7 @@ check_pcsc_keypad (int slot, int command, int pin_mode,
 #define PIN_VERIFY_STRUCTURE_SIZE 24
 static int
 pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
-                    struct pininfo_s *pininfo)
+                    pininfo_t *pininfo)
 {
   int sw;
   unsigned char *pin_verify;
@@ -2154,7 +2147,7 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
 #define PIN_MODIFY_STRUCTURE_SIZE 29
 static int
 pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
-                    struct pininfo_s *pininfo)
+                    pininfo_t *pininfo)
 {
   int sw;
   unsigned char *pin_modify;
@@ -2325,7 +2318,7 @@ get_status_ccid (int slot, unsigned int *status)
 static int
 send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen,
                 unsigned char *buffer, size_t *buflen,
-                struct pininfo_s *pininfo)
+                pininfo_t *pininfo)
 {
   long err;
   size_t maxbuflen;
@@ -2341,10 +2334,7 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen,
   maxbuflen = *buflen;
   if (pininfo)
     err = ccid_transceive_secure (reader_table[slot].ccid.handle,
-                                  apdu, apdulen,
-                                  pininfo->mode,
-                                  pininfo->minlen,
-                                  pininfo->maxlen,
+                                  apdu, apdulen, pininfo,
                                   buffer, maxbuflen, buflen);
   else
     err = ccid_transceive (reader_table[slot].ccid.handle,
@@ -2362,22 +2352,19 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen,
    on the keypad.  Return 0 on success.  For a description of the pin
    parameters, see ccid-driver.c */
 static int
-check_ccid_keypad (int slot, int command, int pin_mode,
-                   int pinlen_min, int pinlen_max)
+check_ccid_keypad (int slot, int command, pininfo_t *pininfo)
 {
   unsigned char apdu[] = { 0, 0, 0, 0x81 };
 
   apdu[1] = command;
-  return ccid_transceive_secure (reader_table[slot].ccid.handle,
-                                 apdu, sizeof apdu,
-                                 pin_mode, pinlen_min, pinlen_max,
-                                 NULL, 0, NULL);
+  return ccid_transceive_secure (reader_table[slot].ccid.handle, apdu,
+				 sizeof apdu, pininfo, NULL, 0, NULL);
 }
 
 
 static int
 ccid_keypad_operation (int slot, int class, int ins, int p0, int p1,
-		       struct pininfo_s *pininfo)
+		       pininfo_t *pininfo)
 {
   unsigned char apdu[4];
   int err, sw;
@@ -2389,8 +2376,7 @@ ccid_keypad_operation (int slot, int class, int ins, int p0, int p1,
   apdu[2] = p0;
   apdu[3] = p1;
   err = ccid_transceive_secure (reader_table[slot].ccid.handle,
-                                apdu, sizeof apdu,
-                                pininfo->mode, pininfo->minlen, pininfo->maxlen,
+                                apdu, sizeof apdu, pininfo,
                                 result, 2, &resultlen);
   if (err)
     return err;
@@ -2610,7 +2596,7 @@ my_rapdu_get_status (int slot, unsigned int *status)
 static int
 my_rapdu_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
                     unsigned char *buffer, size_t *buflen,
-                    struct pininfo_s *pininfo)
+                    pininfo_t *pininfo)
 {
   int err;
   reader_table_t slotp;
@@ -3300,12 +3286,14 @@ apdu_get_status (int slot, int hang,
    the keypad.  Return 0 on success.  For a description of the pin
    parameters, see ccid-driver.c */
 int
-apdu_check_keypad (int slot, int command, int pin_mode,
-                   int pinlen_min, int pinlen_max)
+apdu_check_keypad (int slot, int command, pininfo_t *pininfo)
 {
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
 
+  if (opt.enable_keypad_varlen)
+    pininfo->mode = 0;
+
   if (reader_table[slot].check_keypad)
     {
       int sw;
@@ -3313,8 +3301,7 @@ apdu_check_keypad (int slot, int command, int pin_mode,
       if ((sw = lock_slot (slot)))
         return sw;
 
-      sw = reader_table[slot].check_keypad (slot, command,
-                                            pin_mode, pinlen_min, pinlen_max);
+      sw = reader_table[slot].check_keypad (slot, command, pininfo);
       unlock_slot (slot);
       return sw;
     }
@@ -3324,15 +3311,9 @@ 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)
+apdu_keypad_verify (int slot, int class, int ins, int p0, int p1,
+		    pininfo_t *pininfo)
 {
-  struct pininfo_s pininfo;
-
-  pininfo.mode = pin_mode;
-  pininfo.minlen = pinlen_min;
-  pininfo.maxlen = pinlen_max;
-
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
 
@@ -3344,7 +3325,7 @@ apdu_keypad_verify (int slot, int class, int ins, int p0, int p1, int pin_mode,
         return sw;
 
       sw = reader_table[slot].keypad_verify (slot, class, ins, p0, p1,
-                                             &pininfo);
+					     pininfo);
       unlock_slot (slot);
       return sw;
     }
@@ -3354,15 +3335,9 @@ apdu_keypad_verify (int slot, int class, int ins, int p0, int p1, int pin_mode,
 
 
 int
-apdu_keypad_modify (int slot, int class, int ins, int p0, int p1, int pin_mode,
-                    int pinlen_min, int pinlen_max)
+apdu_keypad_modify (int slot, int class, int ins, int p0, int p1,
+		    pininfo_t *pininfo)
 {
-  struct pininfo_s pininfo;
-
-  pininfo.mode = pin_mode;
-  pininfo.minlen = pinlen_min;
-  pininfo.maxlen = pinlen_max;
-
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
 
@@ -3374,7 +3349,7 @@ apdu_keypad_modify (int slot, int class, int ins, int p0, int p1, int pin_mode,
         return sw;
 
       sw = reader_table[slot].keypad_modify (slot, class, ins, p0, p1,
-                                             &pininfo);
+                                             pininfo);
       unlock_slot (slot);
       return sw;
     }
@@ -3387,7 +3362,7 @@ apdu_keypad_modify (int slot, int class, int ins, int p0, int p1, int pin_mode,
    function should be called in locked state. */
 static int
 send_apdu (int slot, unsigned char *apdu, size_t apdulen,
-           unsigned char *buffer, size_t *buflen, struct pininfo_s *pininfo)
+           unsigned char *buffer, size_t *buflen, pininfo_t *pininfo)
 {
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
@@ -3419,7 +3394,7 @@ static int
 send_le (int slot, int class, int ins, int p0, int p1,
          int lc, const char *data, int le,
          unsigned char **retbuf, size_t *retbuflen,
-         struct pininfo_s *pininfo, int extended_mode)
+         pininfo_t *pininfo, int extended_mode)
 {
 #define SHORT_RESULT_BUFFER_SIZE 258
   /* We allocate 8 extra bytes as a safety margin towards a driver bug.  */
diff --git a/scd/apdu.h b/scd/apdu.h
index 64c2162..011806c 100644
--- a/scd/apdu.h
+++ b/scd/apdu.h
@@ -112,12 +112,11 @@ int apdu_activate (int slot);
 int apdu_reset (int slot);
 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 apdu_check_keypad (int slot, int command, pininfo_t *pininfo);
 int apdu_keypad_verify (int slot, int class, int ins, int p0, int p1,
-                        int pin_mode, int pinlen_min, int pinlen_max);
+			pininfo_t *pininfo);
 int apdu_keypad_modify (int slot, int class, int ins, int p0, int p1,
-                        int pin_mode, int pinlen_min, int pinlen_max);
+			pininfo_t *pininfo);
 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 697cdf6..5a2a902 100644
--- a/scd/app-dinsig.c
+++ b/scd/app-dinsig.c
@@ -282,7 +282,7 @@ verify_pin (app_t app,
 {
   const char *s;
   int rc;
-  iso7816_pininfo_t pininfo;
+  pininfo_t pininfo;
 
   if ( app->did_chv1 && !app->force_chv1 ) 
     return 0;  /* No need to verify it again.  */
diff --git a/scd/app-nks.c b/scd/app-nks.c
index b51e1fc..c53f45a 100644
--- a/scd/app-nks.c
+++ b/scd/app-nks.c
@@ -781,7 +781,7 @@ verify_pin (app_t app, int pwid, const char *desc,
             gpg_error_t (*pincb)(void*, const char *, char **),
             void *pincb_arg)
 {
-  iso7816_pininfo_t pininfo;
+  pininfo_t pininfo;
   int rc;
 
   if (!desc)
@@ -1144,7 +1144,7 @@ do_change_pin (app_t app, ctrl_t ctrl,  const char *pwidstr,
   int is_sigg;
   const char *newdesc;
   int pwid;
-  iso7816_pininfo_t pininfo;
+  pininfo_t pininfo;
 
   (void)ctrl;
 
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index 98af5e8..5292f1d 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -1489,7 +1489,7 @@ verify_a_chv (app_t app,
   int rc = 0;
   char *prompt_buffer = NULL;
   const char *prompt;
-  iso7816_pininfo_t pininfo;
+  pininfo_t pininfo;
   int minlen = 6;
 
   assert (chvno == 1 || chvno == 2);
@@ -1707,7 +1707,7 @@ verify_chv3 (app_t app,
 
   if (!app->did_chv3)
     {
-      iso7816_pininfo_t pininfo;
+      pininfo_t pininfo;
       int minlen = 8;
       char *prompt;
 
@@ -1917,7 +1917,7 @@ do_change_pin (app_t app, ctrl_t ctrl,  const char *chvnostr,
   char *pinvalue = NULL;
   int reset_mode = !!(flags & APP_CHANGE_FLAG_RESET);
   int set_resetcode = 0;
-  iso7816_pininfo_t pininfo;
+  pininfo_t pininfo;
   int use_keypad = 0;
   int minlen = 6;
 
diff --git a/scd/app.c b/scd/app.c
index 7cbbf6e..8bdfefa 100644
--- a/scd/app.c
+++ b/scd/app.c
@@ -26,8 +26,8 @@
 
 #include "scdaemon.h"
 #include "app-common.h"
-#include "apdu.h"
 #include "iso7816.h"
+#include "apdu.h"
 #include "tlv.h"
 
 /* This table is used to keep track of locks on a per reader base.
diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c
index b8a9809..b057861 100644
--- a/scd/ccid-driver.c
+++ b/scd/ccid-driver.c
@@ -91,6 +91,8 @@
 
 #include <usb.h>
 
+#include "scdaemon.h"
+#include "iso7816.h"
 #include "ccid-driver.h"
 
 #define DRVNAME "ccid-driver: "
@@ -3297,7 +3299,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,
+			pininfo_t *pininfo,
                         unsigned char *resp, size_t maxresplen, size_t *nresp)
 {
   int rc;
@@ -3308,7 +3310,7 @@ ccid_transceive_secure (ccid_driver_t handle,
   size_t dummy_nresp;
   int testmode;
   int cherry_mode = 0;
-  int enable_varlen = opt.enable_keypad_varlen;
+  int enable_varlen = 0;
 
   testmode = !resp && !nresp;
 
@@ -3322,19 +3324,16 @@ 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 (!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
@@ -3348,7 +3347,7 @@ ccid_transceive_secure (ccid_driver_t handle,
       break;
     case VENDOR_VASCO: /* Tested with DIGIPASS 920 */
       enable_varlen = 1;
-      pinlen_max = 15;
+      pininfo->maxlen = 15;
       break;
     case VENDOR_CHERRY:
       enable_varlen = 1;
@@ -3371,6 +3370,12 @@ ccid_transceive_secure (ccid_driver_t handle,
      return CCID_DRIVER_ERR_NOT_SUPPORTED;
     }
 
+  if (enable_varlen)
+    pininfo->mode = 0;
+
+  if (pininfo->mode != 0 && pininfo->mode != 1)
+    return CCID_DRIVER_ERR_NOT_SUPPORTED;
+
   if (testmode)
     return 0; /* Success */
     
@@ -3418,8 +3423,8 @@ ccid_transceive_secure (ccid_driver_t handle,
     }
 
   /* 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;
@@ -3432,7 +3437,7 @@ 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++;
 
diff --git a/scd/ccid-driver.h b/scd/ccid-driver.h
index d5e40ca..549e858 100644
--- a/scd/ccid-driver.h
+++ b/scd/ccid-driver.h
@@ -93,8 +93,7 @@ int ccid_transceive (ccid_driver_t handle,
                      unsigned char *resp, size_t maxresplen, size_t *nresp);
 int ccid_transceive_secure (ccid_driver_t handle,
                      const unsigned char *apdu, size_t apdulen,
-                     int pin_mode,
-                     int pinlen_min, int pinlen_max,
+		     pininfo_t *pininfo,
                      unsigned char *resp, size_t maxresplen, size_t *nresp);
 int ccid_transceive_escape (ccid_driver_t handle,
                             const unsigned char *data, size_t datalen,
diff --git a/scd/command.c b/scd/command.c
index 2123b9d..cea71bf 100644
--- a/scd/command.c
+++ b/scd/command.c
@@ -34,6 +34,7 @@
 #include <assuan.h>
 #include <ksba.h>
 #include "app-common.h"
+#include "iso7816.h"
 #include "apdu.h" /* Required for apdu_*_reader (). */
 #include "exechelp.h"
 #ifdef HAVE_LIBUSB
diff --git a/scd/iso7816.c b/scd/iso7816.c
index 23b84cf..78e3c81 100644
--- a/scd/iso7816.c
+++ b/scd/iso7816.c
@@ -269,12 +269,11 @@ iso7816_apdu_direct (int slot, const void *apdudata, size_t apdudatalen,
 /* Check whether the reader supports the ISO command code COMMAND on
    the keypad.  Returns 0 on success.  */
 gpg_error_t
-iso7816_check_keypad (int slot, int command, iso7816_pininfo_t *pininfo)
+iso7816_check_keypad (int slot, int command, pininfo_t *pininfo)
 {
   int sw;
 
-  sw = apdu_check_keypad (slot, command,
-                          pininfo->mode, pininfo->minlen, pininfo->maxlen);
+  sw = apdu_check_keypad (slot, command, pininfo);
   return iso7816_map_sw (sw);
 }
 
@@ -283,12 +282,11 @@ iso7816_check_keypad (int slot, int command, iso7816_pininfo_t *pininfo)
    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, iso7816_pininfo_t *pininfo)
+iso7816_verify_kp (int slot, int chvno, pininfo_t *pininfo)
 {
   int sw;
 
-  sw = apdu_keypad_verify (slot, 0x00, CMD_VERIFY, 0, chvno,
-                           pininfo->mode, pininfo->minlen, pininfo->maxlen);
+  sw = apdu_keypad_verify (slot, 0x00, CMD_VERIFY, 0, chvno, pininfo);
   return map_sw (sw);
 }
 
@@ -309,14 +307,12 @@ iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen)
    data" is done, otherwise an "exchange reference data".  */
 gpg_error_t
 iso7816_change_reference_data_kp (int slot, int chvno, int is_exchange,
-                                  iso7816_pininfo_t *pininfo)
+                                  pininfo_t *pininfo)
 {
   int sw;
 
   sw = apdu_keypad_modify (slot, 0x00, CMD_CHANGE_REFERENCE_DATA,
-			   is_exchange ? 1 : 0,
-			   chvno, pininfo->mode, pininfo->minlen,
-			   pininfo->maxlen);
+			   is_exchange ? 1 : 0, chvno, pininfo);
   return map_sw (sw);
 }
 
diff --git a/scd/iso7816.h b/scd/iso7816.h
index 1d66f6d..3db07a5 100644
--- a/scd/iso7816.h
+++ b/scd/iso7816.h
@@ -32,13 +32,13 @@
 
 /* Information to be passed to keypad equipped readers.  See
    ccid-driver.c for details. */
-struct iso7816_pininfo_s
+struct pininfo_s
 {
-  int mode;    /* A mode of 0 means: Do not use the keypad. */
+  int mode;    /* 0: Use variable length input.  1: Use fixed length input. */
   int minlen;
   int maxlen;
 };
-typedef struct iso7816_pininfo_s iso7816_pininfo_t;
+typedef struct pininfo_s pininfo_t;
 
 
 gpg_error_t iso7816_map_sw (int sw);
@@ -58,16 +58,16 @@ gpg_error_t iso7816_apdu_direct (int slot,
                                  int handle_more,
                                  unsigned char **result, size_t *resultlen);
 gpg_error_t iso7816_check_keypad (int slot, int command,
-                                  iso7816_pininfo_t *pininfo);
+                                  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, iso7816_pininfo_t *pininfo);
+gpg_error_t iso7816_verify_kp (int slot, int chvno, 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);
 gpg_error_t iso7816_change_reference_data_kp (int slot, int chvno,
 					      int is_exchange,
-                                              iso7816_pininfo_t *pininfo);
+                                              pininfo_t *pininfo);
 gpg_error_t iso7816_reset_retry_counter (int slot, int chvno,
                                          const char *newchv, size_t newchvlen);
 gpg_error_t iso7816_reset_retry_counter_with_rc (int slot, int chvno,
diff --git a/scd/sc-copykeys.c b/scd/sc-copykeys.c
index 615e4b2..5217645 100644
--- a/scd/sc-copykeys.c
+++ b/scd/sc-copykeys.c
@@ -33,6 +33,7 @@
 
 #include "../common/ttyio.h"
 #include "../common/simple-pwquery.h"
+#include "iso7816.h"
 #include "apdu.h" /* for open_reader */
 #include "atr.h"
 #include "app-common.h"
diff --git a/scd/scdaemon.c b/scd/scdaemon.c
index 98f037f..ce72d25 100644
--- a/scd/scdaemon.c
+++ b/scd/scdaemon.c
@@ -48,6 +48,7 @@
 #include "i18n.h"
 #include "sysutils.h"
 #include "app-common.h"
+#include "iso7816.h"
 #include "apdu.h"
 #include "ccid-driver.h"
 #include "mkdtemp.h"

commit 3d863c298b5914958ef1462409dc097b4a076b52
Author: NIIBE Yutaka <gniibe at fsij.org>
Date:   Mon Jan 7 14:20:55 2013 +0900

    SCD: Clean up.  Remove PADLEN for keypad input.
    
    * scd/apdu.c (struct pininfo_s): Use iso7816_pininfo_s.
    (struct reader_table_s): Remove last arg from check_keypad method.
    (check_pcsc_keypad, check_pcsc_keypad): Remove PIN_PADLEN.
    (pcsc_keypad_verify, pcsc_keypad_modify): Don't check PIN_PADLEN.
    (send_apdu_ccid, ccid_keypad_operation): Remove PIN_PADLEN.
    (apdu_check_keypad, apdu_keypad_verify, apdu_keypad_modify):
    Likewise.
    
    * scd/apdu.h (apdu_check_keypad, apdu_keypad_verify)
    (apdu_keypad_modify): Remove PIN_PADLEN.
    
    * scd/ccid-driver.c (ccid_transceive_secure): Remove PIN_PADLEN.
    
    * scd/ccid-driver.h (ccid_transceive_secure): Remove PIN_PADLEN.
    
    * scd/iso7816.c (iso7816_check_keypad, iso7816_verify_kp)
    (iso7816_change_reference_data_kp): Remove PADLEN.
    
    * scd/iso7816.h (struct iso7816_pininfo_s): Remove PADLEN, PADCHAR.
    --
    In the OpenPGPcard specification, password comes with no padding.  In
    GnuPG, we support keypad input for OpenPGPcard only.  Thus, it is
    useless to try to support padding for keypad input.

diff --git a/scd/apdu.c b/scd/apdu.c
index 3c549a3..21cd574 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -82,15 +82,7 @@
 #define DLSTDCALL
 #endif
 
-
-/* Helper to pass parameters related to keypad based operations. */
-struct pininfo_s
-{
-  int mode;
-  int minlen;
-  int maxlen;
-  int padlen;
-};
+#define pininfo_s iso7816_pininfo_s
 
 /* A structure to collect information pertaining to one reader
    slot. */
@@ -107,7 +99,7 @@ struct reader_table_s {
   int (*get_status_reader)(int, unsigned int *);
   int (*send_apdu_reader)(int,unsigned char *,size_t,
                           unsigned char *, size_t *, struct pininfo_s *);
-  int (*check_keypad)(int, int, int, int, int, int);
+  int (*check_keypad)(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 *);
@@ -313,7 +305,7 @@ 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);
+                              int pinlen_min, int pinlen_max);
 static int pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
                                struct pininfo_s *pininfo);
 static int pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
@@ -2023,7 +2015,7 @@ open_pcsc_reader (const char *portstr)
    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)
+                   int pinlen_min, int pinlen_max)
 {
   unsigned char buf[256];
   size_t len = 256;
@@ -2032,7 +2024,6 @@ check_pcsc_keypad (int slot, int command, int pin_mode,
   (void)pin_mode;
   (void)pinlen_min;
   (void)pinlen_max;
-  (void)pin_padlen;
 
  check_again:
   if (command == ISO7816_VERIFY)
@@ -2099,9 +2090,6 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
   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)
@@ -2181,9 +2169,6 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
   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)
@@ -2360,7 +2345,6 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen,
                                   pininfo->mode,
                                   pininfo->minlen,
                                   pininfo->maxlen,
-                                  pininfo->padlen,
                                   buffer, maxbuflen, buflen);
   else
     err = ccid_transceive (reader_table[slot].ccid.handle,
@@ -2379,14 +2363,14 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen,
    parameters, see ccid-driver.c */
 static int
 check_ccid_keypad (int slot, int command, int pin_mode,
-                   int pinlen_min, int pinlen_max, int pin_padlen)
+                   int pinlen_min, int pinlen_max)
 {
   unsigned char apdu[] = { 0, 0, 0, 0x81 };
 
   apdu[1] = command;
   return ccid_transceive_secure (reader_table[slot].ccid.handle,
                                  apdu, sizeof apdu,
-                                 pin_mode, pinlen_min, pinlen_max, pin_padlen,
+                                 pin_mode, pinlen_min, pinlen_max,
                                  NULL, 0, NULL);
 }
 
@@ -2407,7 +2391,6 @@ ccid_keypad_operation (int slot, int class, int ins, int p0, int 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;
@@ -3318,7 +3301,7 @@ apdu_get_status (int slot, int hang,
    parameters, see ccid-driver.c */
 int
 apdu_check_keypad (int slot, int command, int pin_mode,
-                   int pinlen_min, int pinlen_max, int pin_padlen)
+                   int pinlen_min, int pinlen_max)
 {
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
@@ -3331,8 +3314,7 @@ apdu_check_keypad (int slot, int command, int pin_mode,
         return sw;
 
       sw = reader_table[slot].check_keypad (slot, command,
-                                            pin_mode, pinlen_min, pinlen_max,
-                                            pin_padlen);
+                                            pin_mode, pinlen_min, pinlen_max);
       unlock_slot (slot);
       return sw;
     }
@@ -3343,14 +3325,13 @@ 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)
+                    int pinlen_min, int pinlen_max)
 {
   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;
@@ -3374,14 +3355,13 @@ apdu_keypad_verify (int slot, int class, int ins, int p0, int p1, int pin_mode,
 
 int
 apdu_keypad_modify (int slot, int class, int ins, int p0, int p1, int pin_mode,
-                    int pinlen_min, int pinlen_max, int pin_padlen)
+                    int pinlen_min, int pinlen_max)
 {
   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;
diff --git a/scd/apdu.h b/scd/apdu.h
index 61501c4..64c2162 100644
--- a/scd/apdu.h
+++ b/scd/apdu.h
@@ -113,13 +113,11 @@ int apdu_reset (int slot);
 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 pinlen_min, int pinlen_max);
 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 pin_mode, int pinlen_min, int pinlen_max);
 int apdu_keypad_modify (int slot, int class, int ins, int p0, int p1,
-                        int pin_mode, int pinlen_min, int pinlen_max,
-                        int pin_padlen);
+                        int pin_mode, int pinlen_min, int pinlen_max);
 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/ccid-driver.c b/scd/ccid-driver.c
index 6d135e0..b8a9809 100644
--- a/scd/ccid-driver.c
+++ b/scd/ccid-driver.c
@@ -3289,8 +3289,8 @@ 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
    given APDU and PIN_MODE. */
@@ -3298,7 +3298,6 @@ 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, 
                         unsigned char *resp, size_t maxresplen, size_t *nresp)
 {
   int rc;
@@ -3327,9 +3326,6 @@ ccid_transceive_secure (ccid_driver_t handle,
   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)
diff --git a/scd/ccid-driver.h b/scd/ccid-driver.h
index 6bb1913..d5e40ca 100644
--- a/scd/ccid-driver.h
+++ b/scd/ccid-driver.h
@@ -93,8 +93,8 @@ int ccid_transceive (ccid_driver_t handle,
                      unsigned char *resp, size_t maxresplen, size_t *nresp);
 int ccid_transceive_secure (ccid_driver_t handle,
                      const unsigned char *apdu, size_t apdulen,
-                     int pin_mode, 
-                     int pinlen_min, int pinlen_max, int pin_padlen, 
+                     int pin_mode,
+                     int pinlen_min, int pinlen_max,
                      unsigned char *resp, size_t maxresplen, size_t *nresp);
 int ccid_transceive_escape (ccid_driver_t handle,
                             const unsigned char *data, size_t datalen,
diff --git a/scd/iso7816.c b/scd/iso7816.c
index 12daff9..23b84cf 100644
--- a/scd/iso7816.c
+++ b/scd/iso7816.c
@@ -273,9 +273,8 @@ iso7816_check_keypad (int slot, int command, iso7816_pininfo_t *pininfo)
 {
   int sw;
 
-  sw = apdu_check_keypad (slot, command, 
-                          pininfo->mode, pininfo->minlen, pininfo->maxlen,
-                          pininfo->padlen);
+  sw = apdu_check_keypad (slot, command,
+                          pininfo->mode, pininfo->minlen, pininfo->maxlen);
   return iso7816_map_sw (sw);
 }
 
@@ -289,8 +288,7 @@ iso7816_verify_kp (int slot, int chvno, iso7816_pininfo_t *pininfo)
   int sw;
 
   sw = apdu_keypad_verify (slot, 0x00, CMD_VERIFY, 0, chvno,
-                           pininfo->mode, pininfo->minlen, pininfo->maxlen,
-                           pininfo->padlen);
+                           pininfo->mode, pininfo->minlen, pininfo->maxlen);
   return map_sw (sw);
 }
 
@@ -318,7 +316,7 @@ iso7816_change_reference_data_kp (int slot, int chvno, int is_exchange,
   sw = apdu_keypad_modify (slot, 0x00, CMD_CHANGE_REFERENCE_DATA,
 			   is_exchange ? 1 : 0,
 			   chvno, pininfo->mode, pininfo->minlen,
-			   pininfo->maxlen, pininfo->padlen);
+			   pininfo->maxlen);
   return map_sw (sw);
 }
 
diff --git a/scd/iso7816.h b/scd/iso7816.h
index d12855b..1d66f6d 100644
--- a/scd/iso7816.h
+++ b/scd/iso7816.h
@@ -37,8 +37,6 @@ struct iso7816_pininfo_s
   int mode;    /* A mode of 0 means: Do not use the keypad. */
   int minlen;
   int maxlen;
-  int padlen;
-  int padchar;
 };
 typedef struct iso7816_pininfo_s iso7816_pininfo_t;
 

commit 7c110e997adda6252dbc7c2ff3fce1db3edaff94
Author: NIIBE Yutaka <gniibe at fsij.org>
Date:   Wed Jan 9 13:24:57 2013 +0900

    SCD: Add option enable-keypad-varlen and support for GEMPC_PINPAD.
    
    * scd/scdaemon.h (opt): Add enable_keypad_varlen.
    * scd/scdaemon.c (cmd_and_opt_values): Add oEnableKeypadVarlen.
    (opts, main): Add oEnableKeypadVarlen.
    * scd/ccid-driver.c (GEMPC_PINPAD): New.
    (ccid_transceive_secure): Add enable_varlen handling.
    Enable GEMPC_PINPAD.
    --
    Note that GEMPC_PINPAD doesn't support variable length keypad input.
    The feature of fixed length keypad input will be added soon.

diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c
index dc50d47..6d135e0 100644
--- a/scd/ccid-driver.c
+++ b/scd/ccid-driver.c
@@ -222,6 +222,7 @@ enum {
 #define SCM_SPR532      0xe003
 #define CHERRY_ST2000   0x003e
 #define VASCO_920       0x0920
+#define GEMPC_PINPAD	0x3478
 
 /* A list and a table with special transport descriptions. */
 enum {
@@ -3308,6 +3309,7 @@ ccid_transceive_secure (ccid_driver_t handle,
   size_t dummy_nresp;
   int testmode;
   int cherry_mode = 0;
+  int enable_varlen = opt.enable_keypad_varlen;
 
   testmode = !resp && !nresp;
 
@@ -3346,11 +3348,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 Gnuk (0.21). */
+      enable_varlen = 1;
       break;
     case VENDOR_VASCO: /* Tested with DIGIPASS 920 */
+      enable_varlen = 1;
       pinlen_max = 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,6 +3366,11 @@ ccid_transceive_secure (ccid_driver_t handle,
       if (handle->id_product != CHERRY_ST2000)
         cherry_mode = 1;
       break;
+    case VENDOR_GEMPC:
+      enable_varlen = 0;
+      if (handle->id_product == GEMPC_PINPAD)
+	break;
+      /* fall through */
     default:
      return CCID_DRIVER_ERR_NOT_SUPPORTED;
     }
diff --git a/scd/scdaemon.c b/scd/scdaemon.c
index defd039..98f037f 100644
--- a/scd/scdaemon.c
+++ b/scd/scdaemon.c
@@ -91,6 +91,7 @@ enum cmd_and_opt_values
   oAllowAdmin,
   oDenyAdmin,
   oDisableApplication,
+  oEnableKeypadVarlen,
   oDebugDisableTicker
 };
 
@@ -143,6 +144,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oDenyAdmin, "deny-admin",
                 N_("deny the use of admin card commands")),
   ARGPARSE_s_s (oDisableApplication, "disable-application", "@"),
+  ARGPARSE_s_n (oEnableKeypadVarlen, "enable-keypad-varlen",
+                N_("use variable length input for keypad")),
 
   ARGPARSE_end ()
 };
@@ -594,6 +597,8 @@ main (int argc, char **argv )
           add_to_strlist (&opt.disabled_applications, pargs.r.ret_str);
           break;
 
+	case oEnableKeypadVarlen: opt.enable_keypad_varlen = 1; break;
+
         default:
           pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR;
           break;
diff --git a/scd/scdaemon.h b/scd/scdaemon.h
index c429396..3eb0fe8 100644
--- a/scd/scdaemon.h
+++ b/scd/scdaemon.h
@@ -57,6 +57,7 @@ struct
   const char *reader_port;  /* NULL or reder port to use. */
   int disable_ccid;    /* Disable the use of the internal CCID driver. */
   int disable_keypad;  /* Do not use a keypad. */
+  int enable_keypad_varlen;  /* Use variable length input for keypad. */
   int allow_admin;     /* Allow the use of admin commands for certain
                           cards. */
   strlist_t disabled_applications;  /* Card applications we do not

commit 2dbd347fbe9765e72041857a5922390e01cf95f1
Author: NIIBE Yutaka <gniibe at fsij.org>
Date:   Tue Jan 8 15:22:31 2013 +0900

    SCD: Support not-so-smart card readers.
    
    * scd/ccid-driver.c (struct ccid_driver_s): Add auto_voltage,
    auto_param, and auto_pps.
    (parse_ccid_descriptor): Set auto_voltage, auto_param, and auto_pps.
    Support non-autoconf readers.
    (update_param_by_atr): New.
    (ccid_get_atr): Use 5V for PowerOn when auto_voltage is not supported.
    Use 0x10 when nonnull_nad for SetParameters.
    Call update_param_by_atr for parsing ATR, and use param for
    SetParameters.
    Send PPS if reader requires it and card is negotiable.
    When bNadValue in the return values of SetParameters == 0,
    clear handle->nonnull_nad flag.
    --
    This change is to support more card readers by the internal driver.
    Tested with 08e6:3478 Gemplus PinPad Smart Card Reader.

diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c
index 49dde61..dc50d47 100644
--- a/scd/ccid-driver.c
+++ b/scd/ccid-driver.c
@@ -266,6 +266,9 @@ struct ccid_driver_s
   unsigned char apdu_level:2;     /* Reader supports short APDU level
                                      exchange.  With a value of 2 short
                                      and extended level is supported.*/
+  unsigned int auto_voltage:1;
+  unsigned int auto_param:1;
+  unsigned int auto_pps:1;
   unsigned int auto_ifsd:1;
   unsigned int powered_off:1;
   unsigned int has_pinpad:2;
@@ -760,7 +763,7 @@ parse_ccid_descriptor (ccid_driver_t handle,
 {
   unsigned int i;
   unsigned int us;
-  int have_t1 = 0, have_tpdu=0, have_auto_conf = 0;
+  int have_t1 = 0, have_tpdu=0;
 
 
   handle->nonnull_nad = 0;
@@ -769,6 +772,9 @@ parse_ccid_descriptor (ccid_driver_t handle,
   handle->ifsd = 0;
   handle->has_pinpad = 0;
   handle->apdu_level = 0;
+  handle->auto_voltage = 0;
+  handle->auto_param = 0;
+  handle->auto_pps = 0;
   DEBUGOUT_3 ("idVendor: %04X  idProduct: %04X  bcdDevice: %04X\n",
               handle->id_vendor, handle->id_product, handle->bcd_device);
   if (buflen < 54 || buf[0] < 54)
@@ -844,22 +850,31 @@ parse_ccid_descriptor (ccid_driver_t handle,
   DEBUGOUT_1 ("  dwFeatures       %08X\n", us);
   if ((us & 0x0002))
     {
-      DEBUGOUT ("    Auto configuration based on ATR\n");
-      have_auto_conf = 1;
+      DEBUGOUT ("    Auto configuration based on ATR (assumes auto voltage)\n");
+      handle->auto_voltage = 1;
     }
   if ((us & 0x0004))
     DEBUGOUT ("    Auto activation on insert\n");
   if ((us & 0x0008))
-    DEBUGOUT ("    Auto voltage selection\n");
+    {
+      DEBUGOUT ("    Auto voltage selection\n");
+      handle->auto_voltage = 1;
+    }
   if ((us & 0x0010))
     DEBUGOUT ("    Auto clock change\n");
   if ((us & 0x0020))
     DEBUGOUT ("    Auto baud rate change\n");
   if ((us & 0x0040))
-    DEBUGOUT ("    Auto parameter negotiation made by CCID\n");
+    {
+      DEBUGOUT ("    Auto parameter negotiation made by CCID\n");
+      handle->auto_param = 1;
+    }
   else if ((us & 0x0080))
-    DEBUGOUT ("    Auto PPS made by CCID\n");
-  else if ((us & (0x0040 | 0x0080)))
+    {
+      DEBUGOUT ("    Auto PPS made by CCID\n");
+      handle->auto_pps = 1;
+    }
+  if ((us & (0x0040 | 0x0080)) == (0x0040 | 0x0080))
     DEBUGOUT ("    WARNING: conflicting negotiation features\n");
 
   if ((us & 0x0100))
@@ -936,11 +951,10 @@ parse_ccid_descriptor (ccid_driver_t handle,
     DEBUGOUT_LF ();
   }
 
-  if (!have_t1 || !(have_tpdu  || handle->apdu_level) || !have_auto_conf)
+  if (!have_t1 || !(have_tpdu  || handle->apdu_level))
     {
       DEBUGOUT ("this drivers requires that the reader supports T=1, "
-                "TPDU or APDU level exchange and auto configuration - "
-                "this is not available\n");
+                "TPDU or APDU level exchange - this is not available\n");
       return -1;
     }
 
@@ -2339,6 +2353,151 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits)
 }
 
 
+/* Parse ATR string (of ATRLEN) and update parameters at PARAM.
+   Calling this routine, it should prepare default values at PARAM
+   beforehand.  This routine assumes that card is accessed by T=1
+   protocol.  It doesn't analyze historical bytes at all.
+
+   Returns < 0 value on error:
+     -1 for parse error or integrity check error
+     -2 for card doesn't support T=1 protocol
+     -3 for parameters are nod explicitly defined by ATR
+     -4 for this driver doesn't support CRC
+
+   Returns >= 0 on success:
+      0 for card is negotiable mode
+      1 for card is specific mode (and not negotiable)
+ */
+static int
+update_param_by_atr (unsigned char *param, unsigned char *atr, size_t atrlen)
+{
+  int i = -1;
+  int t, y, chk;
+  int historical_bytes_num, negotiable = 1;
+
+#define NEXTBYTE() do { i++; if (atrlen <= i) return -1; } while (0)
+
+  NEXTBYTE ();
+
+  if (atr[i] == 0x3F)
+    param[1] |= 0x02;		/* Convention is inverse.  */
+  NEXTBYTE ();
+
+  y = (atr[i] >> 4);
+  historical_bytes_num = atr[i] & 0x0f;
+  NEXTBYTE ();
+
+  if ((y & 1))
+    {
+      param[0] = atr[i];	/* TA1 - Fi & Di */
+      NEXTBYTE ();
+    }
+
+  if ((y & 2))
+    NEXTBYTE ();		/* TB1 - ignore */
+
+  if ((y & 4))
+    {
+      param[2] = atr[i];	/* TC1 - Guard Time */
+      NEXTBYTE ();
+    }
+
+  if ((y & 8))
+    {
+      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).  */
+
+	  if ((atr[i] & 0x10) != 0x10)
+	    return -3; /* Transmission parameters are implicitly defined. */
+
+	  negotiable = 0;	/* TA2 means specific mode.  */
+	  NEXTBYTE ();
+	}
+
+      if ((y & 2))
+	NEXTBYTE ();		/* TB2 - ignore */
+
+      if ((y & 4))
+	NEXTBYTE ();		/* TC2 - ignore */
+
+      if ((y & 8))
+	{
+	  y = (atr[i] >> 4);	/* TD2 */
+	  t = atr[i] & 0x0f;
+	  NEXTBYTE ();
+	}
+      else
+	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;
+	}
+    }
+
+  i += historical_bytes_num - 1;
+  NEXTBYTE ();
+  if (atrlen != i+1)
+    return -1;
+
+#undef NEXTBYTE
+
+  chk = 0;
+  do
+    {
+      chk ^= atr[i];
+      i--;
+    }
+  while (i > 0);
+
+  if (chk != 0)
+    return -1;
+
+  return negotiable;
+}
+
+
 /* Return the ATR of the card.  This is not a cached value and thus an
    actual reset is done.  */
 int 
@@ -2355,6 +2514,15 @@ ccid_get_atr (ccid_driver_t handle,
   unsigned int edc;
   int tried_iso = 0;
   int got_param;
+  unsigned char param[7] = { /* For Protocol T=1 */
+    0x11, /* bmFindexDindex */
+    0x10, /* bmTCCKST1 */
+    0x00, /* bGuardTimeT1 */
+    0x4d, /* bmWaitingIntegersT1 */
+    0x00, /* bClockStop */
+    0x20, /* bIFSC */
+    0x00  /* bNadValue */
+  };
 
   /* First check whether a card is available.  */
   rc = ccid_slot_status (handle, &statusbits);
@@ -2369,7 +2537,8 @@ ccid_get_atr (ccid_driver_t handle,
   msg[0] = PC_to_RDR_IccPowerOn;
   msg[5] = 0; /* slot */
   msg[6] = seqno = handle->seqno++;
-  msg[7] = 0; /* power select (0=auto, 1=5V, 2=3V, 3=1.8V) */
+  /* power select (0=auto, 1=5V, 2=3V, 3=1.8V) */
+  msg[7] = handle->auto_voltage ? 0 : 1;
   msg[8] = 0; /* RFU */
   msg[9] = 0; /* RFU */
   set_msg_len (msg, 0);
@@ -2411,23 +2580,73 @@ ccid_get_atr (ccid_driver_t handle,
       *atrlen = n;
     }
 
+  param[6] = handle->nonnull_nad? ((1 << 4) | 0): 0;
+  rc = update_param_by_atr (param, msg+10, msglen - 10);
+  if (rc < 0)
+    {
+      DEBUGOUT_1 ("update_param_by_atr failed: %d\n", rc);
+      return CCID_DRIVER_ERR_CARD_IO_ERROR;
+    }
+
   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, 0);
-  if (!rc)
-    rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters,
-                  seqno, 2000, 0);
-  if (rc)
-    DEBUGOUT ("GetParameters failed\n");
-  else if (msglen == 17 && msg[9] == 1)
-    got_param = 1;
+
+  if (handle->auto_param)
+    {
+      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, 0);
+      if (!rc)
+	rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters,
+		      seqno, 2000, 0);
+      if (rc)
+	DEBUGOUT ("GetParameters failed\n");
+      else if (msglen == 17 && msg[9] == 1)
+	got_param = 1;
+    }
+  else if (handle->auto_pps)
+    ;
+  else if (rc == 1)		/* It's negotiable, send PPS.  */
+    {
+      msg[0] = PC_to_RDR_XfrBlock;
+      msg[5] = 0; /* slot */
+      msg[6] = seqno = handle->seqno++;
+      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[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;
+
+      rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock,
+		    seqno, 5000, 0);
+      if (rc)
+	return rc;
+
+      if (msglen != 10 + 4)
+	{
+	  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;
+	}
+    }
 
   /* Setup parameters to select T=1. */
   msg[0] = PC_to_RDR_SetParameters;
@@ -2438,16 +2657,7 @@ ccid_get_atr (ccid_driver_t handle,
   msg[9] = 0; /* RFU */
 
   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. */
-    }
+    memcpy (&msg[10], param, 7);
   set_msg_len (msg, 7);
   msglen = 10 + 7;
 
@@ -2464,6 +2674,12 @@ ccid_get_atr (ccid_driver_t handle,
   else
     handle->ifsc = 128; /* Something went wrong, assume 128 bytes.  */
 
+  if (handle->nonnull_nad && msglen > 16 && msg[16] == 0)
+    {
+      DEBUGOUT ("Use Null-NAD, clearing handle->nonnull_nad.\n");
+      handle->nonnull_nad = 0;
+    }
+
   handle->t1_ns = 0;
   handle->t1_nr = 0;
 

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

Summary of changes:
 scd/apdu.c        |  167 +++++++---------------
 scd/apdu.h        |   13 +--
 scd/app-dinsig.c  |    4 +-
 scd/app-nks.c     |    6 +-
 scd/app-openpgp.c |  122 ++++++++++++++--
 scd/app.c         |    2 +-
 scd/ccid-driver.c |  410 ++++++++++++++++++++++++++++++++++++++++++++---------
 scd/ccid-driver.h |    3 +-
 scd/command.c     |    1 +
 scd/iso7816.c     |   18 +--
 scd/iso7816.h     |   19 ++-
 scd/sc-copykeys.c |    1 +
 scd/scdaemon.c    |    6 +
 scd/scdaemon.h    |    1 +
 14 files changed, 543 insertions(+), 230 deletions(-)


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




More information about the Gnupg-commits mailing list