w32: Add icons and version information.
[gnupg.git] / scd / ccid-driver.c
index dc50d47..42a219f 100644 (file)
@@ -1,6 +1,6 @@
 /* ccid-driver.c - USB ChipCardInterfaceDevices driver
  * Copyright (C) 2003, 2004, 2005, 2006, 2007
 /* 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.
  * Written by Werner Koch.
  *
  * This file is part of GnuPG.
@@ -91,6 +91,8 @@
 
 #include <usb.h>
 
 
 #include <usb.h>
 
+#include "scdaemon.h"
+#include "iso7816.h"
 #include "ccid-driver.h"
 
 #define DRVNAME "ccid-driver: "
 #include "ccid-driver.h"
 
 #define DRVNAME "ccid-driver: "
@@ -209,9 +211,11 @@ enum {
   VENDOR_SCM    = 0x04e6,
   VENDOR_OMNIKEY= 0x076b,
   VENDOR_GEMPC  = 0x08e6,
   VENDOR_SCM    = 0x04e6,
   VENDOR_OMNIKEY= 0x076b,
   VENDOR_GEMPC  = 0x08e6,
+  VENDOR_VEGA   = 0x0982,
+  VENDOR_REINER = 0x0c4b,
   VENDOR_KAAN   = 0x0d46,
   VENDOR_KAAN   = 0x0d46,
+  VENDOR_VASCO  = 0x1a44,
   VENDOR_FSIJ   = 0x234b,
   VENDOR_FSIJ   = 0x234b,
-  VENDOR_VASCO  = 0x1a44
 };
 
 /* Some product ids.  */
 };
 
 /* Some product ids.  */
@@ -222,6 +226,9 @@ enum {
 #define SCM_SPR532      0xe003
 #define CHERRY_ST2000   0x003e
 #define VASCO_920       0x0920
 #define SCM_SPR532      0xe003
 #define CHERRY_ST2000   0x003e
 #define VASCO_920       0x0920
+#define GEMPC_PINPAD    0x3478
+#define VEGA_ALPHA      0x0008
+#define CYBERJACK_GO    0x0504
 
 /* A list and a table with special transport descriptions. */
 enum {
 
 /* A list and a table with special transport descriptions. */
 enum {
@@ -300,6 +307,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);
                     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. */
 
 /* Convert a little endian stored 4 byte value into an unsigned
    integer. */
@@ -1521,7 +1531,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)
    pointer to be used as handle in HANDLE.  Returns 0 on success. */
 int 
 ccid_open_reader (ccid_driver_t *handle, const char *readerid)
@@ -1629,6 +1662,8 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
         }
     }
 
         }
     }
 
+  rc = ccid_vendor_specific_init (*handle);
+
  leave:
   free (ifcdesc_extra);
   if (rc)
  leave:
   free (ifcdesc_extra);
   if (rc)
@@ -2380,7 +2415,7 @@ update_param_by_atr (unsigned char *param, unsigned char *atr, size_t atrlen)
   NEXTBYTE ();
 
   if (atr[i] == 0x3F)
   NEXTBYTE ();
 
   if (atr[i] == 0x3F)
-    param[1] |= 0x02;          /* Convention is inverse.  */
+    param[1] |= 0x02;           /* Convention is inverse.  */
   NEXTBYTE ();
 
   y = (atr[i] >> 4);
   NEXTBYTE ();
 
   y = (atr[i] >> 4);
@@ -2389,91 +2424,91 @@ update_param_by_atr (unsigned char *param, unsigned char *atr, size_t atrlen)
 
   if ((y & 1))
     {
 
   if ((y & 1))
     {
-      param[0] = atr[i];       /* TA1 - Fi & Di */
+      param[0] = atr[i];        /* TA1 - Fi & Di */
       NEXTBYTE ();
     }
 
   if ((y & 2))
       NEXTBYTE ();
     }
 
   if ((y & 2))
-    NEXTBYTE ();               /* TB1 - ignore */
+    NEXTBYTE ();                /* TB1 - ignore */
 
   if ((y & 4))
     {
 
   if ((y & 4))
     {
-      param[2] = atr[i];       /* TC1 - Guard Time */
+      param[2] = atr[i];        /* TC1 - Guard Time */
       NEXTBYTE ();
     }
 
   if ((y & 8))
     {
       NEXTBYTE ();
     }
 
   if ((y & 8))
     {
-      y = (atr[i] >> 4);       /* TD1 */
+      y = (atr[i] >> 4);        /* TD1 */
       t = atr[i] & 0x0f;
       NEXTBYTE ();
 
       if ((y & 1))
       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))
 
       if ((y & 2))
-       NEXTBYTE ();            /* TB2 - ignore */
+        NEXTBYTE ();            /* TB2 - ignore */
 
       if ((y & 4))
 
       if ((y & 4))
-       NEXTBYTE ();            /* TC2 - ignore */
+        NEXTBYTE ();            /* TC2 - ignore */
 
       if ((y & 8))
 
       if ((y & 8))
-       {
-         y = (atr[i] >> 4);    /* TD2 */
-         t = atr[i] & 0x0f;
-         NEXTBYTE ();
-       }
+        {
+          y = (atr[i] >> 4);    /* TD2 */
+          t = atr[i] & 0x0f;
+          NEXTBYTE ();
+        }
       else
       else
-       y = 0;
+        y = 0;
 
       while (y)
 
       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;
     }
 
   i += historical_bytes_num - 1;
@@ -2602,16 +2637,16 @@ ccid_get_atr (ccid_driver_t handle,
       msglen = 10;
       rc = bulk_out (handle, msg, msglen, 0);
       if (!rc)
       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)
       if (rc)
-       DEBUGOUT ("GetParameters failed\n");
+        DEBUGOUT ("GetParameters failed\n");
       else if (msglen == 17 && msg[9] == 1)
       else if (msglen == 17 && msg[9] == 1)
-       got_param = 1;
+        got_param = 1;
     }
   else if (handle->auto_pps)
     ;
     }
   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 */
     {
       msg[0] = PC_to_RDR_XfrBlock;
       msg[5] = 0; /* slot */
@@ -2619,33 +2654,33 @@ ccid_get_atr (ccid_driver_t handle,
       msg[7] = 0;
       msg[8] = 0;
       msg[9] = 0;
       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)
       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,
 
       rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock,
-                   seqno, 5000, 0);
+                    seqno, 5000, 0);
       if (rc)
       if (rc)
-       return rc;
+        return rc;
 
       if (msglen != 10 + 4)
 
       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])
 
       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. */
     }
 
   /* Setup parameters to select T=1. */
@@ -2807,7 +2842,7 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
   /* The maximum length for a short APDU T=1 block is 261.  For an
      extended APDU T=1 block the maximum length 65544; however
      extended APDU exchange level is not fully supported yet.  */
   /* The maximum length for a short APDU T=1 block is 261.  For an
      extended APDU T=1 block the maximum length 65544; however
      extended APDU exchange level is not fully supported yet.  */
-  if (apdulen > 289)
+  if (apdulen > sizeof (send_buffer) - 10)
     return CCID_DRIVER_ERR_INV_VALUE; /* Invalid length. */
   
   msg[0] = PC_to_RDR_XfrBlock;
     return CCID_DRIVER_ERR_INV_VALUE; /* Invalid length. */
   
   msg[0] = PC_to_RDR_XfrBlock;
@@ -3288,16 +3323,15 @@ 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
           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. */
 int
 ccid_transceive_secure (ccid_driver_t handle,
                         const unsigned char *apdu_buf, size_t apdu_buflen,
    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. */
 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, 
+                        pininfo_t *pininfo,
                         unsigned char *resp, size_t maxresplen, size_t *nresp)
 {
   int rc;
                         unsigned char *resp, size_t maxresplen, size_t *nresp)
 {
   int rc;
@@ -3308,6 +3342,7 @@ ccid_transceive_secure (ccid_driver_t handle,
   size_t dummy_nresp;
   int testmode;
   int cherry_mode = 0;
   size_t dummy_nresp;
   int testmode;
   int cherry_mode = 0;
+  int enable_varlen = 0;
 
   testmode = !resp && !nresp;
 
 
   testmode = !resp && !nresp;
 
@@ -3320,23 +3355,17 @@ ccid_transceive_secure (ccid_driver_t handle,
   else if (apdu_buflen >= 4 && apdu_buf[1] == 0x24 && (handle->has_pinpad & 2))
     ;
   else
   else if (apdu_buflen >= 4 && apdu_buf[1] == 0x24 && (handle->has_pinpad & 2))
     ;
   else
-    return CCID_DRIVER_ERR_NO_KEYPAD;
-    
-  if (pin_mode != 1)
-    return CCID_DRIVER_ERR_NOT_SUPPORTED;
-
-  if (pin_padlen != 0)
-    return CCID_DRIVER_ERR_NOT_SUPPORTED;
+    return CCID_DRIVER_ERR_NO_PINPAD;
 
 
-  if (!pinlen_min)
-    pinlen_min = 1;
-  if (!pinlen_max)
-    pinlen_max = 25;
+  if (!pininfo->minlen)
+    pininfo->minlen = 1;
+  if (!pininfo->maxlen)
+    pininfo->maxlen = 15;
 
   /* Note that the 25 is the maximum value the SPR532 allows.  */
 
   /* 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
     return CCID_DRIVER_ERR_INV_VALUE;
 
   /* We have only tested a few readers so better don't risk anything
@@ -3346,11 +3375,16 @@ 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). */
     case VENDOR_SCM:  /* Tested with SPR 532. */
     case VENDOR_KAAN: /* Tested with KAAN Advanced (1.02). */
     case VENDOR_FSIJ: /* Tested with Gnuk (0.21). */
+      pininfo->maxlen = 25;
+      enable_varlen = 1;
       break;
       break;
+    case VENDOR_REINER: /* Tested with cyberJack go */
     case VENDOR_VASCO: /* Tested with DIGIPASS 920 */
     case VENDOR_VASCO: /* Tested with DIGIPASS 920 */
-      pinlen_max = 15;
+      enable_varlen = 1;
       break;
     case VENDOR_CHERRY:
       break;
     case VENDOR_CHERRY:
+      pininfo->maxlen = 25;
+      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
       /* 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
@@ -3362,12 +3396,28 @@ ccid_transceive_secure (ccid_driver_t handle,
         cherry_mode = 1;
       break;
     default:
         cherry_mode = 1;
       break;
     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;
     }
 
      return CCID_DRIVER_ERR_NOT_SUPPORTED;
     }
 
+  if (enable_varlen)
+    pininfo->fixedlen = 0;
+
   if (testmode)
     return 0; /* Success */
   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)
     {
   msg = send_buffer;
   if (handle->id_vendor == VENDOR_SCM)
     {
@@ -3397,9 +3447,9 @@ ccid_transceive_secure (ccid_driver_t handle,
     }
   else
     {
     }
   else
     {
-      msg[13] = 0x00; /* bmPINBlockString:
-                         0 bits of pin length to insert. 
-                         0 bytes of PIN block size.  */
+      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. */
     }
       msg[14] = 0x00; /* bmPINLengthFormat:
                          Units are bytes, position is 0. */
     }
@@ -3408,12 +3458,12 @@ ccid_transceive_secure (ccid_driver_t handle,
   if (apdu_buf[1] == 0x24)
     {
       msg[msglen++] = 0;    /* bInsertionOffsetOld */
   if (apdu_buf[1] == 0x24)
     {
       msg[msglen++] = 0;    /* bInsertionOffsetOld */
-      msg[msglen++] = 0;    /* bInsertionOffsetNew */
+      msg[msglen++] = pininfo->fixedlen;    /* bInsertionOffsetNew */
     }
 
   /* The following is a little endian word. */
     }
 
   /* 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;
 
   if (apdu_buf[1] == 0x24)
     msg[msglen++] = apdu_buf[2] == 0 ? 0x03 : 0x01;
@@ -3426,12 +3476,12 @@ ccid_transceive_secure (ccid_driver_t handle,
 
   msg[msglen] = 0x02; /* bEntryValidationCondition:
                          Validation key pressed */
 
   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++;
 
   if (apdu_buf[1] == 0x20)
     msg[msglen] |= 0x01; /* Max size reached.  */
   msglen++;
 
   if (apdu_buf[1] == 0x20)
-    msg[msglen++] = 0xff; /* bNumberMessage: Default. */
+    msg[msglen++] = 0x01; /* bNumberMessage. */
   else
     msg[msglen++] = 0x03; /* bNumberMessage. */
 
   else
     msg[msglen++] = 0x03; /* bNumberMessage. */
 
@@ -3447,10 +3497,18 @@ ccid_transceive_secure (ccid_driver_t handle,
       msg[msglen++] = 2;    /* bMsgIndex3. */
     }
 
       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 */
   /* 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 */
   /* APDU follows:  */
   msg[msglen++] = apdu_buf[0]; /* CLA */
   msg[msglen++] = apdu_buf[1]; /* INS */
@@ -3458,6 +3516,12 @@ ccid_transceive_secure (ccid_driver_t handle,
   msg[msglen++] = apdu_buf[3]; /* P2 */
   if (cherry_mode)
     msg[msglen++] = 0;
   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);
 
   /* An EDC is not required. */
   set_msg_len (msg, msglen - 10);