scd: Cleanup SERIALNO protocol.
[gnupg.git] / scd / app-openpgp.c
index f909c6f..71c9e1b 100644 (file)
@@ -15,7 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 /* Some notes:
@@ -197,8 +197,6 @@ struct app_local_s {
     unsigned int sm_algo:2;            /* Symmetric crypto algo for SM.  */
     unsigned int max_certlen_3:16;
     unsigned int max_get_challenge:16; /* Maximum size for get_challenge.  */
-    unsigned int max_cmd_data:16;      /* Maximum data size for a command.  */
-    unsigned int max_rsp_data:16;      /* Maximum size of a response.  */
   } extcap;
 
   /* Flags used to control the application.  */
@@ -228,7 +226,7 @@ struct app_local_s {
         rsa_key_format_t format;
       } rsa;
       struct {
-        const char *oid;
+        const char *curve;
         int flags;
       } ecc;
     };
@@ -325,7 +323,7 @@ get_cached_data (app_t app, int tag,
     }
 
   if (try_extlen && app->app_local->cardcap.ext_lc_le)
-    exmode = app->app_local->extcap.max_rsp_data;
+    exmode = app->app_local->extcap.max_certlen_3;
   else
     exmode = 0;
 
@@ -455,10 +453,7 @@ 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)
     {
-      if (data_objects[i].try_extlen && app->app_local->cardcap.ext_lc_le)
-        exmode = app->app_local->extcap.max_rsp_data;
-      else
-        exmode = 0;
+      exmode = 0;
       rc = iso7816_get_data (app->slot, exmode, tag, &buffer, &buflen);
       if (rc)
         {
@@ -913,7 +908,7 @@ send_key_attr (ctrl_t ctrl, app_t app, const char *keyword, int keyno)
                 keyno==1? PUBKEY_ALGO_ECDH :
                 (app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK)?
                 PUBKEY_ALGO_EDDSA : PUBKEY_ALGO_ECDSA,
-                openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid, 0));
+                app->app_local->keyattr[keyno].ecc.curve);
     }
   else
     snprintf (buffer, sizeof buffer, "%d 0 0 UNKNOWN", keyno+1);
@@ -922,6 +917,22 @@ send_key_attr (ctrl_t ctrl, app_t app, const char *keyword, int keyno)
 }
 
 
+#define RSA_SMALL_SIZE_KEY 1952
+#define RSA_SMALL_SIZE_OP  2048
+
+static int
+determine_rsa_response (app_t app, int keyno)
+{
+  int size;
+
+  size = 2 + 3 /* header */
+    + 4 /* tag+len */ + app->app_local->keyattr[keyno].rsa.n_bits/8
+    + 2 /* tag+len */ + app->app_local->keyattr[keyno].rsa.e_bits/8;
+
+  return size;
+}
+
+
 /* Implement the GETATTR command.  This is similar to the LEARN
    command but returns just one value via the status interface. */
 static gpg_error_t
@@ -967,21 +978,13 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
   if (table[idx].special == -1)
     {
       /* The serial number is very special.  We could have used the
-         AID DO to retrieve it, but we have it already in the app
-         context and the stamp argument is required anyway which we
-         can't by other means. The AID DO is available anyway but not
-         hex formatted. */
-      char *serial;
-      time_t stamp;
-      char tmp[50];
-
-      if (!app_get_serial_and_stamp (app, &serial, &stamp))
+         AID DO to retrieve it.  The AID DO is available anyway but
+         not hex formatted. */
+      char *serial = app_get_serialno (app);
+
+      if (serial)
         {
-          sprintf (tmp, "%lu", (unsigned long)stamp);
-          send_status_info (ctrl, "SERIALNO",
-                            serial, strlen (serial),
-                            tmp, strlen (tmp),
-                            NULL, 0);
+          send_status_direct (ctrl, "SERIALNO", serial);
           xfree (serial);
         }
       return 0;
@@ -1018,10 +1021,9 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
     }
   if (table[idx].special == -4)
     {
-      char *serial;
-      time_t stamp;
+      char *serial = app_get_serialno (app);
 
-      if (!app_get_serial_and_stamp (app, &serial, &stamp))
+      if (serial)
         {
           if (strlen (serial) > 16+12)
             {
@@ -1115,8 +1117,8 @@ retrieve_fpr_from_card (app_t app, int keyno, char *fpr)
 #if GNUPG_MAJOR_VERSION > 1
 static gpg_error_t
 retrieve_key_material (FILE *fp, const char *hexkeyid,
-                      const unsigned char **m, size_t *mlen,
-                      const unsigned char **e, size_t *elen)
+                       const unsigned char **m, size_t *mlen,
+                       const unsigned char **e, size_t *elen)
 {
   gcry_error_t err = 0;
   char *line = NULL;    /* read_line() buffer. */
@@ -1146,10 +1148,10 @@ retrieve_key_material (FILE *fp, const char *hexkeyid,
       if (!i)
         break; /* EOF. */
       if (i < 0)
-       {
-         err = gpg_error_from_syserror ();
-         goto leave; /* Error. */
-       }
+        {
+          err = gpg_error_from_syserror ();
+          goto leave; /* Error. */
+        }
       if (!max_length)
         {
           err = gpg_error (GPG_ERR_TRUNCATED);
@@ -1173,7 +1175,7 @@ retrieve_key_material (FILE *fp, const char *hexkeyid,
                && nfields > 4 && !strcmp (fields[4], hexkeyid))
             found_key = 1;
           continue;
-       }
+        }
 
       if ( !strcmp (fields[0], "sub") || !strcmp (fields[0], "pub") )
         break; /* Next key - stop.  */
@@ -1307,21 +1309,45 @@ rsa_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at,  int keyno,
   return err;
 }
 
+
+/* Determine KDF hash algorithm and KEK encryption algorithm by CURVE.  */
+static const unsigned char*
+ecdh_params (const char *curve)
+{
+  unsigned int nbits;
+
+  openpgp_curve_to_oid (curve, &nbits);
+
+  /* See RFC-6637 for those constants.
+         0x03: Number of bytes
+         0x01: Version for this parameter format
+         KDF algo
+        KEK algo
+  */
+  if (nbits <= 256)
+    return (const unsigned char*)"\x03\x01\x08\x07";
+  else if (nbits <= 384)
+    return (const unsigned char*)"\x03\x01\x09\x08";
+  else
+    return (const unsigned char*)"\x03\x01\x0a\x09";
+}
+
 static gpg_error_t
 ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
                  const unsigned char *data, size_t datalen, gcry_sexp_t *r_sexp)
 {
   gpg_error_t err;
-  unsigned char *qbuf;
+  unsigned char *qbuf = NULL;
   const unsigned char *ecc_q;
   size_t ecc_q_len;
-  gcry_mpi_t oid;
+  gcry_mpi_t oid = NULL;
   int n;
+  const char *curve;
+  const char *oidstr;
   const unsigned char *oidbuf;
   size_t oid_len;
   int algo;
   const char *format;
-  const char *curve;
 
   ecc_q = find_tlv (data, datalen, 0x0086, &ecc_q_len);
   if (!ecc_q)
@@ -1330,23 +1356,25 @@ ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
       return gpg_error (GPG_ERR_CARD);
     }
 
-  err = openpgp_oid_from_str (app->app_local->keyattr[keyno].ecc.oid, &oid);
+  curve = app->app_local->keyattr[keyno].ecc.curve;
+  oidstr = openpgp_curve_to_oid (curve, NULL);
+  err = openpgp_oid_from_str (oidstr, &oid);
   if (err)
     return err;
-
   oidbuf = gcry_mpi_get_opaque (oid, &n);
   if (!oidbuf)
     {
       err = gpg_error_from_syserror ();
-      gcry_mpi_release (oid);
-      return err;
+      goto leave;
     }
-  gcry_mpi_release (oid);
   oid_len = (n+7)/8;
 
   qbuf = xtrymalloc (ecc_q_len + 1);
   if (!qbuf)
-    return gpg_error_from_syserror ();
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
 
   if ((app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
     {               /* Prepend 0x40 prefix.  */
@@ -1359,14 +1387,14 @@ ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
 
   if (ctrl)
     {
-      send_key_data (ctrl, "q", ecc_q, ecc_q_len);
+      send_key_data (ctrl, "q", qbuf, ecc_q_len);
       send_key_data (ctrl, "curve", oidbuf, oid_len);
     }
 
   if (keyno == 1)
     {
       if (ctrl)
-        send_key_data (ctrl, "kdf", "\x03\x01\x08\x07", (size_t)4);
+        send_key_data (ctrl, "kdf/kek", ecdh_params (curve), (size_t)4);
       algo = PUBKEY_ALGO_ECDH;
     }
   else
@@ -1382,7 +1410,7 @@ ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
       unsigned char fprbuf[20];
 
       err = store_fpr (app, keyno, created_at, fprbuf, algo, oidbuf, oid_len,
-                       qbuf, ecc_q_len, "\x03\x01\x08\x07", (size_t)4);
+                       qbuf, ecc_q_len, ecdh_params (curve), (size_t)4);
       if (err)
         goto leave;
 
@@ -1396,9 +1424,11 @@ ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
   else
     format = "(public-key(ecc(curve%s)(flags eddsa)(q%b)))";
 
-  curve = openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid, 1);
-  err = gcry_sexp_build (r_sexp, NULL, format, curve, (int)ecc_q_len, qbuf);
+  err = gcry_sexp_build (r_sexp, NULL, format,
+                         app->app_local->keyattr[keyno].ecc.curve,
+                         (int)ecc_q_len, qbuf);
  leave:
+  gcry_mpi_release (oid);
   xfree (qbuf);
   return err;
 }
@@ -1503,10 +1533,12 @@ get_public_key (app_t app, int keyno)
       int exmode, le_value;
 
       /* We may simply read the public key out of these cards.  */
-      if (app->app_local->cardcap.ext_lc_le)
+      if (app->app_local->cardcap.ext_lc_le
+          && app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA
+          && app->app_local->keyattr[keyno].rsa.n_bits > RSA_SMALL_SIZE_KEY)
         {
           exmode = 1;    /* Use extended length.  */
-          le_value = app->app_local->extcap.max_rsp_data;
+          le_value = determine_rsa_response (app, keyno);
         }
       else
         {
@@ -1533,8 +1565,8 @@ get_public_key (app_t app, int keyno)
          Clearly that is not an option and thus we try to locate the
          key using an external helper.
 
-        The helper we use here is gpg itself, which should know about
-        the key in any case.  */
+         The helper we use here is gpg itself, which should know about
+         the key in any case.  */
 
       char fpr[41];
       char *hexkeyid;
@@ -1546,38 +1578,38 @@ get_public_key (app_t app, int keyno)
 
       err = retrieve_fpr_from_card (app, keyno, fpr);
       if (err)
-       {
-         log_error ("error while retrieving fpr from card: %s\n",
-                    gpg_strerror (err));
-         goto leave;
-       }
+        {
+          log_error ("error while retrieving fpr from card: %s\n",
+                     gpg_strerror (err));
+          goto leave;
+        }
       hexkeyid = fpr + 24;
 
       ret = gpgrt_asprintf
         (&command, "gpg --list-keys --with-colons --with-key-data '%s'", fpr);
       if (ret < 0)
-       {
-         err = gpg_error_from_syserror ();
-         goto leave;
-       }
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
 
       fp = popen (command, "r");
       xfree (command);
       if (!fp)
-       {
-         err = gpg_error_from_syserror ();
-         log_error ("running gpg failed: %s\n", gpg_strerror (err));
-         goto leave;
-       }
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("running gpg failed: %s\n", gpg_strerror (err));
+          goto leave;
+        }
 
       err = retrieve_key_material (fp, hexkeyid, &m, &mlen, &e, &elen);
       pclose (fp);
       if (err)
-       {
-         log_error ("error while retrieving key material through pipe: %s\n",
+        {
+          log_error ("error while retrieving key material through pipe: %s\n",
                      gpg_strerror (err));
-         goto leave;
-       }
+          goto leave;
+        }
 
       err = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%b)(e%b)))",
                              (int)mlen, m, (int)elen, e);
@@ -1698,7 +1730,8 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
    buffer. On error PK and PKLEN are not changed and an error code is
    returned.  */
 static gpg_error_t
-do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
+do_readkey (app_t app, int advanced, const char *keyid,
+            unsigned char **pk, size_t *pklen)
 {
 #if GNUPG_MAJOR_VERSION > 1
   gpg_error_t err;
@@ -1721,15 +1754,42 @@ do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
   buf = app->app_local->pk[keyno].key;
   if (!buf)
     return gpg_error (GPG_ERR_NO_PUBKEY);
-  *pklen = app->app_local->pk[keyno].keylen;;
-  *pk = xtrymalloc (*pklen);
-  if (!*pk)
+
+  if (advanced)
     {
-      err = gpg_error_from_syserror ();
-      *pklen = 0;
-      return err;
+      gcry_sexp_t s_key;
+
+      err = gcry_sexp_new (&s_key, buf, app->app_local->pk[keyno].keylen, 0);
+      if (err)
+        return err;
+
+      *pklen = gcry_sexp_sprint (s_key, GCRYSEXP_FMT_ADVANCED, NULL, 0);
+      *pk = xtrymalloc (*pklen);
+      if (!*pk)
+        {
+          err = gpg_error_from_syserror ();
+          *pklen = 0;
+          return err;
+        }
+
+      gcry_sexp_sprint (s_key, GCRYSEXP_FMT_ADVANCED, *pk, *pklen);
+      gcry_sexp_release (s_key);
+      /* Decrement for trailing '\0' */
+      *pklen = *pklen - 1;
+    }
+  else
+    {
+      *pklen = app->app_local->pk[keyno].keylen;
+      *pk = xtrymalloc (*pklen);
+      if (!*pk)
+        {
+          err = gpg_error_from_syserror ();
+          *pklen = 0;
+          return err;
+        }
+      memcpy (*pk, buf, *pklen);
     }
-  memcpy (*pk, buf, *pklen);
+
   return 0;
 #else
   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
@@ -2338,7 +2398,7 @@ do_change_pin (app_t app, ctrl_t ctrl,  const char *chvnostr,
         }
       else if (chvno == 1 || chvno == 3)
         {
-         if (!use_pinpad)
+          if (!use_pinpad)
             {
               char *promptbuf = NULL;
               const char *prompt;
@@ -3340,12 +3400,13 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
   const unsigned char *ecc_q = NULL;
   const unsigned char *ecc_d = NULL;
   size_t ecc_q_len, ecc_d_len;
+  const char *curve = NULL;
   u32 created_at = 0;
-  const char *oidstr = NULL;
+  const char *oidstr;
   int flag_djb_tweak = 0;
   int algo;
-  gcry_mpi_t oid;
-  const unsigned char *oidbuf = NULL;
+  gcry_mpi_t oid = NULL;
+  const unsigned char *oidbuf;
   unsigned int n;
   size_t oid_len;
   unsigned char fprbuf[20];
@@ -3370,22 +3431,22 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
 
       if (tok && toklen == 5 && !memcmp (tok, "curve", 5))
         {
-          unsigned char *curve;
+          char *curve_name;
 
           if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
             goto leave;
 
-          curve = xtrymalloc (toklen+1);
-          if (!curve)
+          curve_name = xtrymalloc (toklen+1);
+          if (!curve_name)
             {
               err = gpg_error_from_syserror ();
               goto leave;
             }
 
-          memcpy (curve, tok, toklen);
-          curve[toklen] = 0;
-          oidstr = openpgp_curve_to_oid (curve, NULL);
-          xfree (curve);
+          memcpy (curve_name, tok, toklen);
+          curve_name[toklen] = 0;
+          curve = openpgp_is_curve_supported (curve_name, NULL, NULL);
+          xfree (curve_name);
         }
       else if (tok && toklen == 5 && !memcmp (tok, "flags", 5))
         {
@@ -3472,7 +3533,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
 
   /* Check that we have all parameters and that they match the card
      description. */
-  if (!oidstr)
+  if (!curve)
     {
       log_error (_("unsupported curve\n"));
       err = gpg_error (GPG_ERR_INV_VALUE);
@@ -3491,6 +3552,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
   else
     algo = PUBKEY_ALGO_ECDSA;
 
+  oidstr = openpgp_curve_to_oid (curve, NULL);
   err = openpgp_oid_from_str (oidstr, &oid);
   if (err)
     goto leave;
@@ -3498,24 +3560,34 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
   if (!oidbuf)
     {
       err = gpg_error_from_syserror ();
-      gcry_mpi_release (oid);
       goto leave;
     }
-  gcry_mpi_release (oid);
   oid_len = (n+7)/8;
 
   if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_ECC
-      || app->app_local->keyattr[keyno].ecc.oid != oidstr
+      || app->app_local->keyattr[keyno].ecc.curve != curve
       || (flag_djb_tweak !=
           (app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK)))
     {
       if (app->app_local->extcap.algo_attr_change)
         {
-          unsigned char keyattr[oid_len];
+          unsigned char *keyattr;
 
+          if (!oid_len)
+            {
+              err = gpg_error (GPG_ERR_INTERNAL);
+              goto leave;
+            }
+          keyattr = xtrymalloc (oid_len);
+          if (!keyattr)
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
           keyattr[0] = algo;
           memcpy (keyattr+1, oidbuf+1, oid_len-1);
           err = change_keyattr (app, keyno, keyattr, oid_len, pincb, pincb_arg);
+          xfree (keyattr);
           if (err)
             goto leave;
         }
@@ -3580,9 +3652,10 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
     }
 
   err = store_fpr (app, keyno, created_at, fprbuf, algo, oidbuf, oid_len,
-                   ecc_q, ecc_q_len, "\x03\x01\x08\x07", (size_t)4);
+                   ecc_q, ecc_q_len, ecdh_params (curve), (size_t)4);
 
  leave:
+  gcry_mpi_release (oid);
   return err;
 }
 
@@ -3712,12 +3785,11 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
       if (keybits > 4096)
         return gpg_error (GPG_ERR_TOO_LARGE);
 
-      /* Test whether we will need extended length mode.  (1900 is an
-         arbitrary length which for sure fits into a short apdu.)  */
-      if (app->app_local->cardcap.ext_lc_le && keybits > 1900)
+      if (app->app_local->cardcap.ext_lc_le && keybits > RSA_SMALL_SIZE_KEY
+          && app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA)
         {
           exmode = 1;    /* Use extended length w/o a limit.  */
-          le_value = app->app_local->extcap.max_rsp_data;
+          le_value = determine_rsa_response (app, keyno);
           /* No need to check le_value because it comes from a 16 bit
              value and thus can't create an overflow on a 32 bit
              system.  */
@@ -3961,23 +4033,23 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
   else
     {
       for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
-       ;
+        ;
       if (n != 32)
-       return gpg_error (GPG_ERR_INV_ID);
+        return gpg_error (GPG_ERR_INV_ID);
       else if (!*s)
-       ; /* no fingerprint given: we allow this for now. */
+        ; /* no fingerprint given: we allow this for now. */
       else if (*s == '/')
-       fpr = s + 1;
+        fpr = s + 1;
       else
-       return gpg_error (GPG_ERR_INV_ID);
+        return gpg_error (GPG_ERR_INV_ID);
 
       for (s=keyidstr, n=0; n < 16; s += 2, n++)
-       tmp_sn[n] = xtoi_2 (s);
+        tmp_sn[n] = xtoi_2 (s);
 
       if (app->serialnolen != 16)
-       return gpg_error (GPG_ERR_INV_CARD);
+        return gpg_error (GPG_ERR_INV_CARD);
       if (memcmp (app->serialno, tmp_sn, 16))
-       return gpg_error (GPG_ERR_WRONG_CARD);
+        return gpg_error (GPG_ERR_WRONG_CARD);
     }
 
   /* If a fingerprint has been specified check it against the one on
@@ -4065,10 +4137,12 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
     }
 
 
-  if (app->app_local->cardcap.ext_lc_le)
+  if (app->app_local->cardcap.ext_lc_le
+      && app->app_local->keyattr[0].key_type == KEY_TYPE_RSA
+      && app->app_local->keyattr[0].rsa.n_bits > RSA_SMALL_SIZE_OP)
     {
       exmode = 1;    /* Use extended length.  */
-      le_value = app->app_local->extcap.max_rsp_data;
+      le_value = app->app_local->keyattr[0].rsa.n_bits / 8;
     }
   else
     {
@@ -4168,10 +4242,12 @@ do_auth (app_t app, const char *keyidstr,
     {
       int exmode, le_value;
 
-      if (app->app_local->cardcap.ext_lc_le)
+      if (app->app_local->cardcap.ext_lc_le
+          && app->app_local->keyattr[2].key_type == KEY_TYPE_RSA
+          && app->app_local->keyattr[2].rsa.n_bits > RSA_SMALL_SIZE_OP)
         {
           exmode = 1;    /* Use extended length.  */
-          le_value = app->app_local->extcap.max_rsp_data;
+          le_value = app->app_local->keyattr[2].rsa.n_bits / 8;
         }
       else
         {
@@ -4215,23 +4291,23 @@ do_decipher (app_t app, const char *keyidstr,
   else
     {
       for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
-       ;
+        ;
       if (n != 32)
-       return gpg_error (GPG_ERR_INV_ID);
+        return gpg_error (GPG_ERR_INV_ID);
       else if (!*s)
-       ; /* no fingerprint given: we allow this for now. */
+        ; /* no fingerprint given: we allow this for now. */
       else if (*s == '/')
-       fpr = s + 1;
+        fpr = s + 1;
       else
-       return gpg_error (GPG_ERR_INV_ID);
+        return gpg_error (GPG_ERR_INV_ID);
 
       for (s=keyidstr, n=0; n < 16; s += 2, n++)
-       tmp_sn[n] = xtoi_2 (s);
+        tmp_sn[n] = xtoi_2 (s);
 
       if (app->serialnolen != 16)
-       return gpg_error (GPG_ERR_INV_CARD);
+        return gpg_error (GPG_ERR_INV_CARD);
       if (memcmp (app->serialno, tmp_sn, 16))
-       return gpg_error (GPG_ERR_WRONG_CARD);
+        return gpg_error (GPG_ERR_WRONG_CARD);
     }
 
   /* If a fingerprint has been specified check it against the one on
@@ -4360,10 +4436,13 @@ do_decipher (app_t app, const char *keyidstr,
   else
     return gpg_error (GPG_ERR_INV_VALUE);
 
-  if (app->app_local->cardcap.ext_lc_le && indatalen > 254 )
+  if (app->app_local->cardcap.ext_lc_le
+      && (indatalen > 254
+          || (app->app_local->keyattr[1].key_type == KEY_TYPE_RSA
+              && app->app_local->keyattr[1].rsa.n_bits > RSA_SMALL_SIZE_OP)))
     {
       exmode = 1;    /* Extended length w/o a limit.  */
-      le_value = app->app_local->extcap.max_rsp_data;
+      le_value = app->app_local->keyattr[1].rsa.n_bits / 8;
     }
   else if (app->app_local->cardcap.cmd_chaining && indatalen > 254)
     {
@@ -4377,20 +4456,29 @@ do_decipher (app_t app, const char *keyidstr,
                          indata, indatalen, le_value, padind,
                          outdata, outdatalen);
   xfree (fixbuf);
-  if (app->app_local->keyattr[1].key_type == KEY_TYPE_ECC
-      && (app->app_local->keyattr[1].ecc.flags & ECC_FLAG_DJB_TWEAK))
-    { /* Add the prefix 0x40 */
-      fixbuf = xtrymalloc (*outdatalen + 1);
-      if (!fixbuf)
-        {
+  if (app->app_local->keyattr[1].key_type == KEY_TYPE_ECC)
+    {
+      unsigned char prefix = 0;
+
+      if (app->app_local->keyattr[1].ecc.flags & ECC_FLAG_DJB_TWEAK)
+        prefix = 0x40;
+      else if ((*outdatalen % 2) == 0) /* No 0x04 -> x-coordinate only */
+        prefix = 0x41;
+
+      if (prefix)
+        { /* Add the prefix */
+          fixbuf = xtrymalloc (*outdatalen + 1);
+          if (!fixbuf)
+            {
+              xfree (*outdata);
+              return gpg_error_from_syserror ();
+            }
+          fixbuf[0] = prefix;
+          memcpy (fixbuf+1, *outdata, *outdatalen);
           xfree (*outdata);
-          return gpg_error_from_syserror ();
+          *outdata = fixbuf;
+          *outdatalen = *outdatalen + 1;
         }
-      fixbuf[0] = 0x40;
-      memcpy (fixbuf+1, *outdata, *outdatalen);
-      xfree (*outdata);
-      *outdata = fixbuf;
-      *outdatalen = *outdatalen + 1;
     }
 
   if (gpg_err_code (rc) == GPG_ERR_CARD /* actual SW is 0x640a */
@@ -4512,8 +4600,6 @@ show_caps (struct app_local_s *s)
     log_printf (" (%s)", s->extcap.sm_algo==2? "3DES":
                 (s->extcap.sm_algo==2? "AES-128" : "AES-256"));
   log_info ("Max-Cert3-Len ..: %u\n", s->extcap.max_certlen_3);
-  log_info ("Max-Cmd-Data ...: %u\n", s->extcap.max_cmd_data);
-  log_info ("Max-Rsp-Data ...: %u\n", s->extcap.max_rsp_data);
   log_info ("Cmd-Chaining ...: %s\n", s->cardcap.cmd_chaining?"yes":"no");
   log_info ("Ext-Lc-Le ......: %s\n", s->cardcap.ext_lc_le?"yes":"no");
   log_info ("Status Indicator: %02X\n", s->status_indicator);
@@ -4577,12 +4663,11 @@ parse_historical (struct app_local_s *apploc,
 
 /*
  * Check if the OID in an DER encoding is available by GnuPG/libgcrypt,
- * and return the constant string in dotted decimal form.
- * Return NULL if not available.
+ * and return the curve name.  Return NULL if not available.
  * The constant string is not allocated dynamically, never free it.
  */
 static const char *
-ecc_oid (unsigned char *buf, size_t buflen)
+ecc_curve (unsigned char *buf, size_t buflen)
 {
   gcry_mpi_t oid;
   char *oidstr;
@@ -4607,7 +4692,7 @@ ecc_oid (unsigned char *buf, size_t buflen)
   if (!oidstr)
     return NULL;
 
-  result = openpgp_curve_to_oid (oidstr, NULL);
+  result = openpgp_oid_to_curve (oidstr, 1);
   xfree (oidstr);
   return result;
 }
@@ -4670,7 +4755,7 @@ parse_algorithm_attribute (app_t app, int keyno)
   else if (*buffer == PUBKEY_ALGO_ECDH || *buffer == PUBKEY_ALGO_ECDSA
            || *buffer == PUBKEY_ALGO_EDDSA)
     {
-      const char *oid;
+      const char *curve;
       int oidlen = buflen - 1;
 
       app->app_local->keyattr[keyno].ecc.flags = 0;
@@ -4682,22 +4767,22 @@ parse_algorithm_attribute (app_t app, int keyno)
             app->app_local->keyattr[keyno].ecc.flags |= ECC_FLAG_PUBKEY;
         }
 
-      oid = ecc_oid (buffer + 1, oidlen);
+      curve = ecc_curve (buffer + 1, oidlen);
 
-      if (!oid)
+      if (!curve)
         log_printhex ("Curve with OID not supported: ", buffer+1, buflen-1);
       else
         {
           app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECC;
-          app->app_local->keyattr[keyno].ecc.oid = oid;
+          app->app_local->keyattr[keyno].ecc.curve = curve;
           if (*buffer == PUBKEY_ALGO_EDDSA
               || (*buffer == PUBKEY_ALGO_ECDH
-                  && !strcmp (app->app_local->keyattr[keyno].ecc.oid,
-                              "1.3.6.1.4.1.3029.1.5.1")))
+                  && !strcmp (app->app_local->keyattr[keyno].ecc.curve,
+                              "Curve25519")))
             app->app_local->keyattr[keyno].ecc.flags |= ECC_FLAG_DJB_TWEAK;
           if (opt.verbose)
             log_printf
-              ("ECC, curve=%s%s\n", app->app_local->keyattr[keyno].ecc.oid,
+              ("ECC, curve=%s%s\n", app->app_local->keyattr[keyno].ecc.curve,
                !(app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK)?
                "": keyno==1? " (djb-tweak)": " (eddsa)");
         }
@@ -4818,8 +4903,6 @@ app_select_openpgp (app_t app)
           app->app_local->extcap.max_get_challenge
                                                = (buffer[2] << 8 | buffer[3]);
           app->app_local->extcap.max_certlen_3 = (buffer[4] << 8 | buffer[5]);
-          app->app_local->extcap.max_cmd_data  = (buffer[6] << 8 | buffer[7]);
-          app->app_local->extcap.max_rsp_data  = (buffer[8] << 8 | buffer[9]);
         }
       xfree (relptr);