Fix for extended length Le in decipher
[gnupg.git] / scd / app-openpgp.c
index 3010f0c..d468591 100644 (file)
@@ -16,8 +16,6 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * $Id$
  */
 
 /* Some notes:
@@ -75,43 +73,45 @@ static struct {
   int tag;
   int constructed;
   int get_from;  /* Constructed DO with this DO or 0 for direct access. */
-  int binary;
-  int dont_cache;
-  int flush_on_error;
-  int get_immediate_in_v11; /* Enable a hack to bypass the cache of
-                               this data object if it is used in 1.1
-                               and later versions of the card.  This
-                               does not work with composite DO and is
-                               currently only useful for the CHV
-                               status bytes. */
+  int binary:1;
+  int dont_cache:1;
+  int flush_on_error:1;
+  int get_immediate_in_v11:1; /* Enable a hack to bypass the cache of
+                                 this data object if it is used in 1.1
+                                 and later versions of the card.  This
+                                 does not work with composite DO and
+                                 is currently only useful for the CHV
+                                 status bytes. */
+  int try_extlen:1;           /* Large object; try to use an extended
+                                 length APDU.  */
   char *desc;
 } data_objects[] = {
-  { 0x005E, 0,    0, 1, 0, 0, 0, "Login Data" },
-  { 0x5F50, 0,    0, 0, 0, 0, 0, "URL" },
-  { 0x5F52, 0,    0, 1, 0, 0, 0, "Historical Bytes" },
-  { 0x0065, 1,    0, 1, 0, 0, 0, "Cardholder Related Data"},
-  { 0x005B, 0, 0x65, 0, 0, 0, 0, "Name" },
-  { 0x5F2D, 0, 0x65, 0, 0, 0, 0, "Language preferences" },
-  { 0x5F35, 0, 0x65, 0, 0, 0, 0, "Sex" },
-  { 0x006E, 1,    0, 1, 0, 0, 0, "Application Related Data" },
-  { 0x004F, 0, 0x6E, 1, 0, 0, 0, "AID" },
-  { 0x0073, 1,    0, 1, 0, 0, 0, "Discretionary Data Objects" },
-  { 0x0047, 0, 0x6E, 1, 1, 0, 0, "Card Capabilities" },
-  { 0x00C0, 0, 0x6E, 1, 1, 0, 0, "Extended Card Capabilities" },
-  { 0x00C1, 0, 0x6E, 1, 1, 0, 0, "Algorithm Attributes Signature" },
-  { 0x00C2, 0, 0x6E, 1, 1, 0, 0, "Algorithm Attributes Decryption" },
-  { 0x00C3, 0, 0x6E, 1, 1, 0, 0, "Algorithm Attributes Authentication" },
-  { 0x00C4, 0, 0x6E, 1, 0, 1, 1, "CHV Status Bytes" },
-  { 0x00C5, 0, 0x6E, 1, 0, 0, 0, "Fingerprints" },
-  { 0x00C6, 0, 0x6E, 1, 0, 0, 0, "CA Fingerprints" },
-  { 0x00CD, 0, 0x6E, 1, 0, 0, 0, "Generation time" },
-  { 0x007A, 1,    0, 1, 0, 0, 0, "Security Support Template" },
-  { 0x0093, 0, 0x7A, 1, 1, 0, 0, "Digital Signature Counter" },
-  { 0x0101, 0,    0, 0, 0, 0, 0, "Private DO 1"},
-  { 0x0102, 0,    0, 0, 0, 0, 0, "Private DO 2"},
-  { 0x0103, 0,    0, 0, 0, 0, 0, "Private DO 3"},
-  { 0x0104, 0,    0, 0, 0, 0, 0, "Private DO 4"},
-  { 0x7F21, 1,    0, 1, 0, 0, 0, "Cardholder certificate"},
+  { 0x005E, 0,    0, 1, 0, 0, 0, 0, "Login Data" },
+  { 0x5F50, 0,    0, 0, 0, 0, 0, 0, "URL" },
+  { 0x5F52, 0,    0, 1, 0, 0, 0, 0, "Historical Bytes" },
+  { 0x0065, 1,    0, 1, 0, 0, 0, 0, "Cardholder Related Data"},
+  { 0x005B, 0, 0x65, 0, 0, 0, 0, 0, "Name" },
+  { 0x5F2D, 0, 0x65, 0, 0, 0, 0, 0, "Language preferences" },
+  { 0x5F35, 0, 0x65, 0, 0, 0, 0, 0, "Sex" },
+  { 0x006E, 1,    0, 1, 0, 0, 0, 0, "Application Related Data" },
+  { 0x004F, 0, 0x6E, 1, 0, 0, 0, 0, "AID" },
+  { 0x0073, 1,    0, 1, 0, 0, 0, 0, "Discretionary Data Objects" },
+  { 0x0047, 0, 0x6E, 1, 1, 0, 0, 0, "Card Capabilities" },
+  { 0x00C0, 0, 0x6E, 1, 1, 0, 0, 0, "Extended Card Capabilities" },
+  { 0x00C1, 0, 0x6E, 1, 1, 0, 0, 0, "Algorithm Attributes Signature" },
+  { 0x00C2, 0, 0x6E, 1, 1, 0, 0, 0, "Algorithm Attributes Decryption" },
+  { 0x00C3, 0, 0x6E, 1, 1, 0, 0, 0, "Algorithm Attributes Authentication" },
+  { 0x00C4, 0, 0x6E, 1, 0, 1, 1, 0, "CHV Status Bytes" },
+  { 0x00C5, 0, 0x6E, 1, 0, 0, 0, 0, "Fingerprints" },
+  { 0x00C6, 0, 0x6E, 1, 0, 0, 0, 0, "CA Fingerprints" },
+  { 0x00CD, 0, 0x6E, 1, 0, 0, 0, 0, "Generation time" },
+  { 0x007A, 1,    0, 1, 0, 0, 0, 0, "Security Support Template" },
+  { 0x0093, 0, 0x7A, 1, 1, 0, 0, 0, "Digital Signature Counter" },
+  { 0x0101, 0,    0, 0, 0, 0, 0, 0, "Private DO 1"},
+  { 0x0102, 0,    0, 0, 0, 0, 0, 0, "Private DO 2"},
+  { 0x0103, 0,    0, 0, 0, 0, 0, 0, "Private DO 3"},
+  { 0x0104, 0,    0, 0, 0, 0, 0, 0, "Private DO 4"},
+  { 0x7F21, 1,    0, 1, 0, 0, 0, 1, "Cardholder certificate"},
   { 0 }
 };
 
@@ -211,6 +211,12 @@ static gpg_error_t do_auth (app_t app, const char *keyidstr,
                             void *pincb_arg,
                             const void *indata, size_t indatalen,
                             unsigned char **outdata, size_t *outdatalen);
+static void parse_algorithm_attribute (app_t app, int keyno);
+static gpg_error_t change_keyattr_from_string
+                           (app_t app, 
+                            gpg_error_t (*pincb)(void*, const char *, char **),
+                            void *pincb_arg,
+                            const void *value, size_t valuelen);
 
 
 
@@ -244,17 +250,19 @@ do_deinit (app_t app)
 
 /* Wrapper around iso7816_get_data which first tries to get the data
    from the cache.  With GET_IMMEDIATE passed as true, the cache is
-   bypassed. */
+   bypassed.  With TRY_EXTLEN extended lengths APDUs are use if
+   supported by the card.  */
 static gpg_error_t
 get_cached_data (app_t app, int tag, 
                  unsigned char **result, size_t *resultlen,
-                 int get_immediate)
+                 int get_immediate, int try_extlen)
 {
   gpg_error_t err;
   int i;
   unsigned char *p;
   size_t len;
   struct cache_s *c;
+  int exmode;
 
   *result = NULL;
   *resultlen = 0;
@@ -279,7 +287,12 @@ get_cached_data (app_t app, int tag,
           }
     }
   
-  err = iso7816_get_data (app->slot, tag, &p, &len);
+  if (try_extlen && app->app_local->cardcap.ext_lc_le)
+    exmode = app->app_local->extcap.max_rsp_data;
+  else
+    exmode = 0;
+
+  err = iso7816_get_data (app->slot, exmode, tag, &p, &len);
   if (err)
     return err;
   *result = p;
@@ -392,6 +405,7 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes,
   unsigned char *value;
   size_t valuelen;
   int dummyrc;
+  int exmode;
 
   if (!r_rc)
     r_rc = &dummyrc;
@@ -404,7 +418,11 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes,
 
   if (app->card_version > 0x0100 && data_objects[i].get_immediate_in_v11)
     {
-      rc = iso7816_get_data (app->slot, tag, &buffer, &buflen);
+      if (data_objects[i].try_extlen && app->app_local->cardcap.ext_lc_le)
+        exmode = app->app_local->extcap.max_rsp_data;
+      else
+        exmode = 0;
+      rc = iso7816_get_data (app->slot, exmode, tag, &buffer, &buflen);
       if (rc)
         {
           *r_rc = rc;
@@ -422,7 +440,8 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes,
       rc = get_cached_data (app, data_objects[i].get_from,
                             &buffer, &buflen,
                             (data_objects[i].dont_cache 
-                             || data_objects[i].get_immediate_in_v11));
+                             || data_objects[i].get_immediate_in_v11),
+                            data_objects[i].try_extlen);
       if (!rc)
         {
           const unsigned char *s;
@@ -445,7 +464,8 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes,
     {
       rc = get_cached_data (app, tag, &buffer, &buflen,
                             (data_objects[i].dont_cache 
-                             || data_objects[i].get_immediate_in_v11));
+                             || data_objects[i].get_immediate_in_v11),
+                            data_objects[i].try_extlen);
       if (!rc)
         {
           value = buffer;
@@ -476,7 +496,9 @@ dump_all_do (int slot)
       if (data_objects[i].get_from)
         continue;
 
-      rc = iso7816_get_data (slot, data_objects[i].tag, &buffer, &buflen);
+      /* We don't try extended length APDU because such large DO would
+         be pretty useless in a log file.  */
+      rc = iso7816_get_data (slot, 0, data_objects[i].tag, &buffer, &buflen);
       if (gpg_err_code (rc) == GPG_ERR_NO_OBJ)
         ;
       else if (rc) 
@@ -621,13 +643,14 @@ parse_login_data (app_t app)
 
 /* Note, that FPR must be at least 20 bytes. */
 static gpg_error_t 
-store_fpr (int slot, int keynumber, u32 timestamp,
+store_fpr (app_t app, int keynumber, u32 timestamp,
            const unsigned char *m, size_t mlen,
            const unsigned char *e, size_t elen, 
            unsigned char *fpr, unsigned int card_version)
 {
   unsigned int n, nbits;
   unsigned char *buffer, *p;
+  int tag, tag2;
   int rc;
   
   for (; mlen && !*m; mlen--, m++) /* strip leading zeroes */
@@ -662,9 +685,12 @@ store_fpr (int slot, int keynumber, u32 timestamp,
 
   xfree (buffer);
 
-  rc = iso7816_put_data (slot, 0, 
-                         (card_version > 0x0007? 0xC7 : 0xC6)
-                         + keynumber, fpr, 20);
+  tag = (card_version > 0x0007? 0xC7 : 0xC6) + keynumber;
+  flush_cache_item (app, tag);
+  tag2 = 0xCE + keynumber;
+  flush_cache_item (app, tag2);
+
+  rc = iso7816_put_data (app->slot, 0, tag, fpr, 20);
   if (rc)
     log_error (_("failed to store the fingerprint: %s\n"),gpg_strerror (rc));
 
@@ -677,7 +703,7 @@ store_fpr (int slot, int keynumber, u32 timestamp,
       buf[2] = timestamp >>  8;
       buf[3] = timestamp;
 
-      rc = iso7816_put_data (slot, 0, 0xCE + keynumber, buf, 4);
+      rc = iso7816_put_data (app->slot, 0, tag2, buf, 4);
       if (rc)
         log_error (_("failed to store the creation date: %s\n"),
                    gpg_strerror (rc));
@@ -833,13 +859,16 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
       char tmp[100];
 
       snprintf (tmp, sizeof tmp,
-                "gc=%d ki=%d fc=%d pd=%d mcl3=%u aac=%d", 
+                "gc=%d ki=%d fc=%d pd=%d mcl3=%u aac=%d sm=%d", 
                 app->app_local->extcap.get_challenge,
                 app->app_local->extcap.key_import,
                 app->app_local->extcap.change_force_chv,
                 app->app_local->extcap.private_dos,
                 app->app_local->extcap.max_certlen_3,
-                app->app_local->extcap.algo_attr_change);
+                app->app_local->extcap.algo_attr_change,
+                (app->app_local->extcap.sm_supported
+                 ? (app->app_local->extcap.sm_aes128? 7 : 2)
+                 : 0));
       send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
       return 0;
     }
@@ -1093,11 +1122,25 @@ get_public_key (app_t app, int keyno)
 
   if (app->card_version > 0x0100)
     {
+      int exmode, le_value;
+
       /* We may simply read the public key out of these cards.  */
+      if (app->app_local->cardcap.ext_lc_le)
+        {
+          exmode = 1;    /* Use extended length.  */
+          le_value = app->app_local->extcap.max_rsp_data;
+        }
+      else
+        {
+          exmode = 0;
+          le_value = 256; /* Use legacy value. */
+        }
+
       err = iso7816_read_public_key 
-        (app->slot, 0, (const unsigned char*)(keyno == 0? "\xB6" :
-                                              keyno == 1? "\xB8" : "\xA4"), 2,  
-         0,
+        (app->slot, exmode,
+         (const unsigned char*)(keyno == 0? "\xB6" :
+                                keyno == 1? "\xB8" : "\xA4"), 2,  
+         le_value,
          &buffer, &buflen);
       if (err)
         {
@@ -1398,8 +1441,9 @@ do_readcert (app_t app, const char *certid,
   if (!relptr)
     return gpg_error (GPG_ERR_NOT_FOUND);
 
-  *cert = xtrymalloc (buflen);
-  if (!*cert)
+  if (!buflen)
+    err = gpg_error (GPG_ERR_NOT_FOUND);
+  else if (!(*cert = xtrymalloc (buflen)))
     err = gpg_error_from_syserror ();
   else
     {
@@ -1553,43 +1597,31 @@ verify_chv2 (app_t app,
   char *pinvalue;
 
   if (app->did_chv2) 
-    return 0;  /* We already verified CHV2 (PW1 for v2 cards).  */
+    return 0;  /* We already verified CHV2.  */
 
-  if (app->app_local->extcap.is_v2)
-    {
-      /* Version two cards don't have a CHV2 anymore.  We need to
-         verify CHV1 (now called PW1) instead.  */
-      rc = verify_a_chv (app, pincb, pincb_arg, 1, 0, &pinvalue);
-      if (rc)
-        return rc;
-      app->did_chv2 = 1;
-    }
-  else
-    {
-      /* Version 1 cards only.  */
-      rc = verify_a_chv (app, pincb, pincb_arg, 2, 0, &pinvalue);
-      if (rc)
-        return rc;
-      app->did_chv2 = 1;
+  rc = verify_a_chv (app, pincb, pincb_arg, 2, 0, &pinvalue);
+  if (rc)
+    return rc;
+  app->did_chv2 = 1;
   
-      if (!app->did_chv1 && !app->force_chv1 && pinvalue)
+  if (!app->did_chv1 && !app->force_chv1 && pinvalue)
+    {
+      /* For convenience we verify CHV1 here too.  We do this only if
+         the card is not configured to require a verification before
+         each CHV1 controlled operation (force_chv1) and if we are not
+         using the keypad (PINVALUE == NULL). */
+      rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue));
+      if (gpg_err_code (rc) == GPG_ERR_BAD_PIN)
+        rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED);
+      if (rc)
         {
-          /* For convenience we verify CHV1 here too.  We do this only
-             if the card is not configured to require a verification
-             before each CHV1 controlled operation (force_chv1) and if
-             we are not using the keypad (PINVALUE == NULL). */
-          rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue));
-          if (gpg_err_code (rc) == GPG_ERR_BAD_PIN)
-            rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED);
-          if (rc)
-            {
-              log_error (_("verify CHV%d failed: %s\n"), 1, gpg_strerror (rc));
-              flush_cache_after_error (app);
-            }
-          else
-            app->did_chv1 = 1;
+          log_error (_("verify CHV%d failed: %s\n"), 1, gpg_strerror (rc));
+          flush_cache_after_error (app);
         }
+      else
+        app->did_chv1 = 1;
     }
+
   xfree (pinvalue);
 
   return rc;
@@ -1764,6 +1796,7 @@ do_setattr (app_t app, const char *name,
     { "CERT-3",       0x7F21, 3, 0, 1 },
     { "SM-KEY-ENC",   0x00D1, 3, 0, 1 },
     { "SM-KEY-MAC",   0x00D2, 3, 0, 1 },
+    { "KEY-ATTR",     0,      0, 3, 1 },
     { NULL, 0 }
   };
   int exmode;
@@ -1775,6 +1808,9 @@ do_setattr (app_t app, const char *name,
   if (table[idx].need_v2 && !app->app_local->extcap.is_v2)
     return gpg_error (GPG_ERR_NOT_SUPPORTED); /* Not yet supported.  */
 
+  if (table[idx].special == 3)
+    return change_keyattr_from_string (app, pincb, pincb_arg, value, valuelen);
+
   switch (table[idx].need_chv)
     {
     case 2:
@@ -2116,9 +2152,10 @@ do_change_pin (app_t app, ctrl_t ctrl,  const char *chvnostr,
 
 /* Check whether a key already exists.  KEYIDX is the index of the key
    (0..2).  If FORCE is TRUE a diagnositic will be printed but no
-   error returned if the key already exists. */
+   error returned if the key already exists.  The flag GENERATING is
+   only used to print correct messages. */
 static gpg_error_t
-does_key_exist (app_t app, int keyidx, int force)
+does_key_exist (app_t app, int keyidx, int generating, int force)
 {
   const unsigned char *fpr;
   unsigned char *buffer;
@@ -2127,7 +2164,7 @@ does_key_exist (app_t app, int keyidx, int force)
 
   assert (keyidx >=0 && keyidx <= 2);
 
-  if (iso7816_get_data (app->slot, 0x006E, &buffer, &buflen))
+  if (iso7816_get_data (app->slot, 0, 0x006E, &buffer, &buflen))
     {
       log_error (_("error reading application data\n"));
       return gpg_error (GPG_ERR_GENERAL);
@@ -2150,8 +2187,10 @@ does_key_exist (app_t app, int keyidx, int force)
     }
   else if (i!=20)
     log_info (_("existing key will be replaced\n"));
-  else
+  else if (generating)
     log_info (_("generating new key\n"));
+  else
+    log_info (_("writing new key\n"));
   return 0;
 }
 
@@ -2312,6 +2351,105 @@ build_privkey_template (app_t app, int keyno,
 }
 
 
+/* Helper for do_writekley to change the size of a key.  Not ethat
+   this deletes the entire key without asking.  */
+static gpg_error_t
+change_keyattr (app_t app, int keyno, unsigned int nbits,
+                gpg_error_t (*pincb)(void*, const char *, char **),
+                void *pincb_arg)
+{
+  gpg_error_t err;
+  unsigned char *buffer;
+  size_t buflen;
+  void *relptr;
+
+  assert (keyno >=0 && keyno <= 2);
+
+  if (nbits > 3072)
+    return gpg_error (GPG_ERR_TOO_LARGE);
+
+  /* Read the current attributes into a buffer.  */
+  relptr = get_one_do (app, 0xC1+keyno, &buffer, &buflen, NULL);
+  if (!relptr)
+    return gpg_error (GPG_ERR_CARD);
+  if (buflen < 6 || buffer[0] != 1)
+    {
+      /* Attriutes too short or not an RSA key.  */
+      xfree (relptr);
+      return gpg_error (GPG_ERR_CARD);
+    }
+  
+  /* We only change n_bits and don't touch anything else.  Before we
+     do so, we round up NBITS to a sensible way in the same way as
+     gpg's key generation does it.  This may help to sort out problems
+     with a few bits too short keys.  */
+  nbits = ((nbits + 31) / 32) * 32;
+  buffer[1] = (nbits >> 8);
+  buffer[2] = nbits;
+
+  /* Prepare for storing the key.  */
+  err = verify_chv3 (app, pincb, pincb_arg);
+  if (err)
+    {
+      xfree (relptr);
+      return err;
+    }
+
+  /* Change the attribute.  */
+  err = iso7816_put_data (app->slot, 0, 0xC1+keyno, buffer, buflen);
+  xfree (relptr);
+  if (err)
+    log_error ("error changing size of key %d to %u bits\n", keyno+1, nbits);
+  else
+    log_info ("size of key %d changed to %u bits\n", keyno+1, nbits);
+  flush_cache (app);
+  parse_algorithm_attribute (app, keyno);
+  app->did_chv1 = 0;
+  app->did_chv2 = 0;
+  app->did_chv3 = 0;
+  return err;
+}
+
+
+/* Helper to process an setattr command for name KEY-ATTR.  It expects
+   a string "--force <keyno> <algo> <nbits>" in (VALUE,VALUELEN).  */
+static gpg_error_t 
+change_keyattr_from_string (app_t app, 
+                            gpg_error_t (*pincb)(void*, const char *, char **),
+                            void *pincb_arg,
+                            const void *value, size_t valuelen)
+{
+  gpg_error_t err;
+  char *string;
+  int keyno, algo;
+  unsigned int nbits;
+
+  /* VALUE is expected to be a string but not guaranteed to be
+     terminated.  Thus copy it to an allocated buffer first. */
+  string = xtrymalloc (valuelen+1);
+  if (!string)
+    return gpg_error_from_syserror ();
+  memcpy (string, value, valuelen);
+  string[valuelen] = 0;
+
+  /* Because this function deletes the key we require the string
+     "--force" in the data to make clear that something serious might
+     happen.  */
+  if (sscanf (string, " --force %d %d %u", &keyno, &algo, &nbits) != 3)
+    err = gpg_error (GPG_ERR_INV_DATA);
+  else if (keyno < 1 || keyno > 3)
+    err = gpg_error (GPG_ERR_INV_ID);
+  else if (algo != 1)
+    err = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Not RSA.  */
+  else if (nbits < 1024)
+    err = gpg_error (GPG_ERR_TOO_SHORT);
+  else
+    err = change_keyattr (app, keyno-1, nbits, pincb, pincb_arg);
+
+  xfree (string);
+  return err;
+}
+
 
 /* Handle the WRITEKEY command for OpenPGP.  This function expects a
    canonical encoded S-expression with the secret key in KEYDATA and
@@ -2357,7 +2495,7 @@ do_writekey (app_t app, ctrl_t ctrl,
   else
     return gpg_error (GPG_ERR_INV_ID);
   
-  err = does_key_exist (app, keyno, force);
+  err = does_key_exist (app, keyno, 0, force);
   if (err)
     return err;
 
@@ -2487,6 +2625,14 @@ do_writekey (app_t app, ctrl_t ctrl,
   if (opt.verbose)
     log_info ("RSA modulus size is %u bits (%u bytes)\n", 
               nbits, (unsigned int)rsa_n_len);
+  if (nbits && nbits != maxbits
+      && app->app_local->extcap.algo_attr_change)
+    {
+      /* Try to switch the key to a new length.  */
+      err = change_keyattr (app, keyno, nbits, pincb, pincb_arg);
+      if (!err)
+        maxbits = app->app_local->keyattr[keyno].n_bits;
+    }
   if (nbits != maxbits)
     {
       log_error (_("RSA modulus missing or not of size %d bits\n"), 
@@ -2619,7 +2765,7 @@ do_writekey (app_t app, ctrl_t ctrl,
       goto leave;
     }
  
-  err = store_fpr (app->slot, keyno, created_at,
+  err = store_fpr (app, keyno, created_at,
                   rsa_n, rsa_n_len, rsa_e, rsa_e_len,
                   fprbuf, app->card_version);
   if (err)
@@ -2668,7 +2814,7 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
   app->app_local->pk[keyno].read_done = 0;
 
   /* Check whether a key already exists.  */
-  rc = does_key_exist (app, keyno, force);
+  rc = does_key_exist (app, keyno, 1, force);
   if (rc)
     return rc;
 
@@ -2753,7 +2899,7 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
   send_status_info (ctrl, "KEY-CREATED-AT",
                     numbuf, (size_t)strlen(numbuf), NULL, 0);
 
-  rc = store_fpr (app->slot, keyno, (u32)created_at,
+  rc = store_fpr (app, keyno, (u32)created_at,
                   m, mlen, e, elen, fprbuf, app->card_version);
   if (rc)
     goto leave;
@@ -2807,7 +2953,7 @@ compare_fingerprint (app_t app, int keyno, unsigned char *sha1fpr)
   
   assert (keyno >= 1 && keyno <= 3);
 
-  rc = get_cached_data (app, 0x006E, &buffer, &buflen, 0);
+  rc = get_cached_data (app, 0x006E, &buffer, &buflen, 0, 0);
   if (rc)
     {
       log_error (_("error reading application data\n"));
@@ -2833,11 +2979,11 @@ compare_fingerprint (app_t app, int keyno, unsigned char *sha1fpr)
 }
 
 
-  /* If a fingerprint has been specified check it against the one on
-     the card.  This is allows for a meaningful error message in case
-     the key on the card has been replaced but the shadow information
-     known to gpg was not updated.  If there is no fingerprint we
-     assume that this is okay. */
+/* If a fingerprint has been specified check it against the one on the
+   card.  This allows for a meaningful error message in case the key
+   on the card has been replaced but the shadow information known to
+   gpg has not been updated.  If there is no fingerprint we assume
+   that this is okay. */
 static gpg_error_t
 check_against_given_fingerprint (app_t app, const char *fpr, int keyno)
 {
@@ -2911,6 +3057,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
   const char *fpr = NULL;
   unsigned long sigcount;
   int use_auth = 0;
+  int exmode, le_value;
 
   if (!keyidstr || !*keyidstr)
     return gpg_error (GPG_ERR_INV_VALUE);
@@ -3051,7 +3198,19 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
       xfree (pinvalue);
     }
 
-  rc = iso7816_compute_ds (app->slot, data, datalen, outdata, outdatalen);
+
+  if (app->app_local->cardcap.ext_lc_le)
+    {
+      exmode = 1;    /* Use extended length.  */
+      le_value = app->app_local->extcap.max_rsp_data;
+    }
+  else
+    {
+      exmode = 0;
+      le_value = 0; 
+    }
+  rc = iso7816_compute_ds (app->slot, exmode, data, datalen, le_value,
+                           outdata, outdatalen);
   return rc;
 }
 
@@ -3122,8 +3281,23 @@ do_auth (app_t app, const char *keyidstr,
 
   rc = verify_chv2 (app, pincb, pincb_arg);
   if (!rc)
-    rc = iso7816_internal_authenticate (app->slot, indata, indatalen,
-                                        outdata, outdatalen);
+    {
+      int exmode, le_value;
+
+      if (app->app_local->cardcap.ext_lc_le)
+        {
+          exmode = 1;    /* Use extended length.  */
+          le_value = app->app_local->extcap.max_rsp_data;
+        }
+      else
+        {
+          exmode = 0;
+          le_value = 0; 
+        }
+      rc = iso7816_internal_authenticate (app->slot, exmode,
+                                          indata, indatalen, le_value,
+                                          outdata, outdatalen);
+    }
   return rc;
 }
 
@@ -3140,7 +3314,7 @@ do_decipher (app_t app, const char *keyidstr,
   const char *s;
   int n;
   const char *fpr = NULL;
-  int exmode;
+  int exmode, le_value;
 
   if (!keyidstr || !*keyidstr || !indatalen)
     return gpg_error (GPG_ERR_INV_VALUE);
@@ -3223,16 +3397,22 @@ do_decipher (app_t app, const char *keyidstr,
           indatalen = fixuplen + indatalen;
           padind = -1; /* Already padded.  */
         }
-      
+
       if (app->app_local->cardcap.ext_lc_le && indatalen > 254 )
-        exmode = 1;    /* Extended length w/o a limit.  */
+        {
+          exmode = 1;    /* Extended length w/o a limit.  */
+          le_value = app->app_local->extcap.max_rsp_data;
+        }
       else if (app->app_local->cardcap.cmd_chaining && indatalen > 254)
-        exmode = -254; /* Command chaining with max. 254 bytes.  */
+        {
+          exmode = -254; /* Command chaining with max. 254 bytes.  */
+          le_value = 0;
+        }
       else
-        exmode = 0;    
+        exmode = le_value = 0;    
 
       rc = iso7816_decipher (app->slot, exmode, 
-                             indata, indatalen, padind,
+                             indata, indatalen, le_value, padind,
                              outdata, outdatalen);
       xfree (fixbuf);
     }
@@ -3498,7 +3678,7 @@ app_select_openpgp (app_t app)
          replace a possibly already set one from a EF.GDO with this
          one.  Note, that for current OpenPGP cards, no EF.GDO exists
          and thus it won't matter at all. */
-      rc = iso7816_get_data (slot, 0x004F, &buffer, &buflen);
+      rc = iso7816_get_data (slot, 0, 0x004F, &buffer, &buflen);
       if (rc)
         goto leave;
       if (opt.verbose)