Add open card manufacturer 0x0008.
[gnupg.git] / agent / cvt-openpgp.c
index ef34463..671dd4c 100644 (file)
@@ -1,6 +1,5 @@
 /* cvt-openpgp.c - Convert an OpenPGP key to our internal format.
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2006, 2009,
- *               2010 Free Software Foundation, Inc.
+ * Copyright (C) 1998-2002, 2006, 2009, 2010 Free Software Foundation, Inc.
  * Copyright (C) 2013, 2014 Werner Koch
  *
  * This file is part of GnuPG.
@@ -36,6 +35,7 @@ struct try_do_unprotect_arg_s
   int  is_v4;
   int  is_protected;
   int  pubkey_algo;
+  const char *curve;
   int  protect_algo;
   char *iv;
   int  ivlen;
@@ -54,7 +54,8 @@ struct try_do_unprotect_arg_s
 
 /* Compute the keygrip from the public key and store it at GRIP.  */
 static gpg_error_t
-get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip)
+get_keygrip (int pubkey_algo, const char *curve, gcry_mpi_t *pkey,
+             unsigned char *grip)
 {
   gpg_error_t err;
   gcry_sexp_t s_pkey = NULL;
@@ -79,10 +80,16 @@ get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip)
       break;
 
     case GCRY_PK_ECC:
-      err = gcry_sexp_build (&s_pkey, NULL,
-                             "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))",
-                             pkey[0], pkey[1], pkey[2], pkey[3], pkey[4],
-                             pkey[5]);
+      if (!curve)
+        err = gpg_error (GPG_ERR_BAD_SECKEY);
+      else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL)))
+        err = gcry_sexp_build (&s_pkey, NULL,
+                               "(public-key(ecc(curve %s)(flags eddsa)(q%m)))",
+                               "Ed25519", pkey[0]);
+      else
+        err = gcry_sexp_build (&s_pkey, NULL,
+                               "(public-key(ecc(curve %s)(q%m)))",
+                               curve, pkey[0]);
       break;
 
     default:
@@ -102,7 +109,8 @@ get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip)
    parameters into our s-expression based format.  Note that
    PUBKEY_ALGO has an gcrypt algorithm number. */
 static gpg_error_t
-convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
+convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey,
+                    const char *curve)
 {
   gpg_error_t err;
   gcry_sexp_t s_skey = NULL;
@@ -135,11 +143,21 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
       break;
 
     case GCRY_PK_ECC:
-      err = gcry_sexp_build (&s_skey, NULL,
-                             "(private-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)"
-                             "(d%m)))",
-                             skey[0], skey[1], skey[2], skey[3], skey[4],
-                             skey[5], skey[6]);
+      if (!curve)
+        err = gpg_error (GPG_ERR_BAD_SECKEY);
+      else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL)))
+        {
+          /* Do not store the OID as name but the real name and the
+             EdDSA flag.  */
+          err = gcry_sexp_build (&s_skey, NULL,
+                                 "(private-key(ecc(curve%s)(flags eddsa)"
+                                 "(q%m)(d%m)))",
+                                 "Ed25519", skey[0], skey[1]);
+        }
+      else
+        err = gcry_sexp_build (&s_skey, NULL,
+                               "(private-key(ecc(curve%s)(q%m)(d%m)))",
+                               curve, skey[0], skey[1]);
       break;
 
     default:
@@ -160,7 +178,7 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
    mode.  Note that PUBKEY_ALGO has an gcrypt algorithm number. */
 static gpg_error_t
 convert_transfer_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey,
-                      gcry_sexp_t transfer_key)
+                      const char *curve, gcry_sexp_t transfer_key)
 {
   gpg_error_t err;
   gcry_sexp_t s_skey = NULL;
@@ -189,17 +207,30 @@ convert_transfer_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey,
     case GCRY_PK_RSA:
       err = gcry_sexp_build
         (&s_skey, NULL,
-         "(protected-private-key(rsa(n%m)(e%m)",
+         "(protected-private-key(rsa(n%m)(e%m)"
          "(protected openpgp-native%S)))",
          skey[0], skey[1], transfer_key );
       break;
 
     case GCRY_PK_ECC:
-      err = gcry_sexp_build
-        (&s_skey, NULL,
-         "(protected-private-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)"
-         "(protected openpgp-native%S)))",
-         skey[0], skey[1], skey[2], skey[3], skey[4], skey[5], transfer_key);
+      if (!curve)
+        err = gpg_error (GPG_ERR_BAD_SECKEY);
+      else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL)))
+        {
+          /* Do not store the OID as name but the real name and the
+             EdDSA flag.  */
+          err = gcry_sexp_build
+            (&s_skey, NULL,
+             "(protected-private-key(ecc(curve%s)(flags eddsa)(q%m)"
+             "(protected openpgp-native%S)))",
+             "Ed25519", skey[0], transfer_key);
+        }
+      else
+        err = gcry_sexp_build
+          (&s_skey, NULL,
+           "(protected-private-key(ecc(curve%s)(q%m)"
+           "(protected openpgp-native%S)))",
+           curve, skey[0], transfer_key);
       break;
 
     default:
@@ -254,6 +285,22 @@ checksum (const unsigned char *p, unsigned int n)
 }
 
 
+/* Return the number of expected key parameters.  */
+static void
+get_npkey_nskey (int pubkey_algo, size_t *npkey, size_t *nskey)
+{
+  switch (pubkey_algo)
+    {
+    case GCRY_PK_RSA:   *npkey = 2; *nskey = 6; break;
+    case GCRY_PK_ELG:   *npkey = 3; *nskey = 4; break;
+    case GCRY_PK_ELG_E: *npkey = 3; *nskey = 4; break;
+    case GCRY_PK_DSA:   *npkey = 4; *nskey = 5; break;
+    case GCRY_PK_ECC:   *npkey = 1; *nskey = 2; break;
+    default:            *npkey = 0; *nskey = 0; break;
+    }
+}
+
+
 /* Helper for do_unprotect.  PUBKEY_ALOGO is the gcrypt algo number.
    On success R_NPKEY and R_NSKEY receive the number or parameters for
    the algorithm PUBKEY_ALGO and R_SKEYLEN the used length of
@@ -264,7 +311,6 @@ prepare_unprotect (int pubkey_algo, gcry_mpi_t *skey, size_t skeysize,
                    unsigned int *r_npkey, unsigned int *r_nskey,
                    unsigned int *r_skeylen)
 {
-  gpg_error_t err;
   size_t npkey, nskey, skeylen;
   int i;
 
@@ -293,12 +339,8 @@ prepare_unprotect (int pubkey_algo, gcry_mpi_t *skey, size_t skeysize,
   /* Get properties of the public key algorithm and do some
      consistency checks.  Note that we need at least NPKEY+1 elements
      in the SKEY array. */
-  if ( (err = gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY,
-                                 NULL, &npkey))
-       || (err = gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NSKEY,
-                                    NULL, &nskey)))
-    return err;
-  if (!npkey || npkey >= nskey)
+  get_npkey_nskey (pubkey_algo, &npkey, &nskey);
+  if (!npkey || !nskey || npkey >= nskey)
     return gpg_error (GPG_ERR_INTERNAL);
   if (skeylen <= npkey)
     return gpg_error (GPG_ERR_MISSING_VALUE);
@@ -309,7 +351,7 @@ prepare_unprotect (int pubkey_algo, gcry_mpi_t *skey, size_t skeysize,
      encrypted.  */
   for (i=0; i < npkey; i++)
     {
-      if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE))
+      if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_USER1))
         return gpg_error (GPG_ERR_BAD_SECKEY);
     }
 
@@ -329,7 +371,7 @@ prepare_unprotect (int pubkey_algo, gcry_mpi_t *skey, size_t skeysize,
 static int
 do_unprotect (const char *passphrase,
               int pkt_version, int pubkey_algo, int is_protected,
-              gcry_mpi_t *skey, size_t skeysize,
+              const char *curve, gcry_mpi_t *skey, size_t skeysize,
               int protect_algo, void *protect_iv, size_t protect_ivlen,
               int s2k_mode, int s2k_algo, byte *s2k_salt, u32 s2k_count,
               u16 desired_csum, gcry_sexp_t *r_key)
@@ -353,23 +395,26 @@ do_unprotect (const char *passphrase,
      merely verify the checksum.  */
   if (!is_protected)
     {
-      unsigned char *buffer;
-
       actual_csum = 0;
       for (i=npkey; i < nskey; i++)
         {
-          if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE))
+          if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_USER1))
             return gpg_error (GPG_ERR_BAD_SECKEY);
 
-          err = gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &nbytes, skey[i]);
-          if (!err)
+          if (gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE))
             {
-              buffer = (gcry_is_secure (skey[i])?
-                        xtrymalloc_secure (nbytes) : xtrymalloc (nbytes));
-              if (!buffer)
-                return gpg_error_from_syserror ();
-              err = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes,
-                                    NULL, skey[i]);
+              unsigned int nbits;
+              const unsigned char *buffer;
+              buffer = gcry_mpi_get_opaque (skey[i], &nbits);
+              nbytes = (nbits+7)/8;
+              actual_csum += checksum (buffer, nbytes);
+            }
+          else
+            {
+              unsigned char *buffer;
+
+              err = gcry_mpi_aprint (GCRYMPI_FMT_PGP, &buffer, &nbytes,
+                                     skey[i]);
               if (!err)
                 actual_csum += checksum (buffer, nbytes);
               xfree (buffer);
@@ -380,7 +425,8 @@ do_unprotect (const char *passphrase,
 
       if (actual_csum != desired_csum)
         return gpg_error (GPG_ERR_CHECKSUM);
-      return 0;
+
+      goto do_convert;
     }
 
 
@@ -428,7 +474,8 @@ do_unprotect (const char *passphrase,
     {
       int ndata;
       unsigned int ndatabits;
-      unsigned char *p, *data;
+      const unsigned char *p;
+      unsigned char *data;
       u16 csum_pgp7 = 0;
 
       if (!gcry_mpi_get_flag (skey[npkey], GCRYMPI_FLAG_OPAQUE ))
@@ -527,7 +574,7 @@ do_unprotect (const char *passphrase,
 
       for (i = npkey; i < nskey; i++)
         {
-          unsigned char *p;
+          const unsigned char *p;
           size_t ndata;
           unsigned int ndatabits;
 
@@ -577,10 +624,11 @@ do_unprotect (const char *passphrase,
   if (actual_csum != desired_csum)
     return gpg_error (GPG_ERR_BAD_PASSPHRASE);
 
+ do_convert:
   if (nskey != skeylen)
     err = gpg_error (GPG_ERR_BAD_SECKEY);
   else
-    err = convert_secret_key (r_key, pubkey_algo, skey);
+    err = convert_secret_key (r_key, pubkey_algo, skey, curve);
   if (err)
     return err;
 
@@ -608,6 +656,7 @@ try_do_unprotect_cb (struct pin_entry_info_s *pi)
   err = do_unprotect (pi->pin,
                       arg->is_v4? 4:3,
                       arg->pubkey_algo, arg->is_protected,
+                      arg->curve,
                       arg->skey, arg->skeysize,
                       arg->protect_algo, arg->iv, arg->ivlen,
                       arg->s2k_mode, arg->s2k_algo,
@@ -651,6 +700,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
   u32  s2k_count = 0;
   size_t npkey, nskey;
   gcry_mpi_t skey[10];  /* We support up to 9 parameters.  */
+  char *curve = NULL;
   u16 desired_csum;
   int skeyidx = 0;
   gcry_sexp_t s_skey = NULL;
@@ -695,8 +745,6 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
       if (!string)
         goto bad_seckey;
       protect_algo = gcry_cipher_map_name (string);
-      if (!protect_algo && !!strcmp (string, "IDEA"))
-        protect_algo = GCRY_CIPHER_IDEA;
       xfree (string);
 
       value = gcry_sexp_nth_data (list, 3, &valuelen);
@@ -739,11 +787,21 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
   pubkey_algo = gcry_pk_map_name (string);
   xfree (string);
 
-  if (gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey)
-      || gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey)
-      || !npkey || npkey >= nskey)
+  get_npkey_nskey (pubkey_algo, &npkey, &nskey);
+  if (!npkey || !nskey || npkey >= nskey)
     goto bad_seckey;
 
+  if (npkey == 1) /* This is ECC */
+    {
+      gcry_sexp_release (list);
+      list = gcry_sexp_find_token (top_list, "curve", 0);
+      if (!list)
+        goto bad_seckey;
+      curve = gcry_sexp_nth_string (list, 1);
+      if (!curve)
+        goto bad_seckey;
+    }
+
   gcry_sexp_release (list);
   list = gcry_sexp_find_token (top_list, "skey", 0);
   if (!list)
@@ -770,15 +828,15 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
       value = gcry_sexp_nth_data (list, ++idx, &valuelen);
       if (!value || !valuelen)
         goto bad_seckey;
-      if (is_enc)
+      if (is_enc || curve)
         {
-          void *p = xtrymalloc (valuelen);
-          if (!p)
-            goto outofmem;
-          memcpy (p, value, valuelen);
-          skey[skeyidx] = gcry_mpi_set_opaque (NULL, p, valuelen*8);
+          /* Encrypted parameters and ECC parameters need or can be
+             stored as opaque.  */
+          skey[skeyidx] = gcry_mpi_set_opaque_copy (NULL, value, valuelen*8);
           if (!skey[skeyidx])
             goto outofmem;
+          if (is_enc)
+            gcry_mpi_set_flag (skey[skeyidx], GCRYMPI_FLAG_USER1);
         }
       else
         {
@@ -807,33 +865,24 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
   gcry_sexp_release (list); list = NULL;
   gcry_sexp_release (top_list); top_list = NULL;
 
-  /* log_debug ("XXX is_v4=%d\n", is_v4); */
-  /* log_debug ("XXX pubkey_algo=%d\n", pubkey_algo); */
-  /* log_debug ("XXX is_protected=%d\n", is_protected); */
-  /* log_debug ("XXX protect_algo=%d\n", protect_algo); */
-  /* log_printhex ("XXX iv", iv, ivlen); */
-  /* log_debug ("XXX ivlen=%d\n", ivlen); */
-  /* log_debug ("XXX s2k_mode=%d\n", s2k_mode); */
-  /* log_debug ("XXX s2k_algo=%d\n", s2k_algo); */
-  /* log_printhex ("XXX s2k_salt", s2k_salt, sizeof s2k_salt); */
-  /* log_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count); */
-  /* for (idx=0; skey[idx]; idx++) */
-  /*   { */
-  /*     int is_enc = gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE); */
-  /*     log_info ("XXX skey[%d]%s:", idx, is_enc? " (enc)":""); */
-  /*     if (is_enc) */
-  /*       { */
-  /*         void *p; */
-  /*         unsigned int nbits; */
-  /*         p = gcry_mpi_get_opaque (skey[idx], &nbits); */
-  /*         log_printhex (NULL, p, (nbits+7)/8); */
-  /*       } */
-  /*     else */
-  /*       gcry_mpi_dump (skey[idx]); */
-  /*     log_printf ("\n"); */
-  /*   } */
-
-  err = get_keygrip (pubkey_algo, skey, grip);
+#if 0
+  log_debug ("XXX is_v4=%d\n", is_v4);
+  log_debug ("XXX pubkey_algo=%d\n", pubkey_algo);
+  log_debug ("XXX is_protected=%d\n", is_protected);
+  log_debug ("XXX protect_algo=%d\n", protect_algo);
+  log_printhex ("XXX iv", iv, ivlen);
+  log_debug ("XXX ivlen=%d\n", ivlen);
+  log_debug ("XXX s2k_mode=%d\n", s2k_mode);
+  log_debug ("XXX s2k_algo=%d\n", s2k_algo);
+  log_printhex ("XXX s2k_salt", s2k_salt, sizeof s2k_salt);
+  log_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count);
+  log_debug ("XXX curve='%s'\n", curve);
+  for (idx=0; skey[idx]; idx++)
+    gcry_log_debugmpi (gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_USER1)
+                       ? "skey(e)" : "skey(_)", skey[idx]);
+#endif /*0*/
+
+  err = get_keygrip (pubkey_algo, curve, skey, grip);
   if (err)
     goto leave;
 
@@ -850,7 +899,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
       if (err)
         goto leave;
 
-      err = convert_transfer_key (&s_skey, pubkey_algo, skey, s_pgp);
+      err = convert_transfer_key (&s_skey, pubkey_algo, skey, curve, s_pgp);
       if (err)
         goto leave;
     }
@@ -871,6 +920,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
       pi_arg.is_v4 = is_v4;
       pi_arg.is_protected = is_protected;
       pi_arg.pubkey_algo = pubkey_algo;
+      pi_arg.curve = curve;
       pi_arg.protect_algo = protect_algo;
       pi_arg.iv = iv;
       pi_arg.ivlen = ivlen;
@@ -885,7 +935,11 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
       pi_arg.r_key = &s_skey;
 
       err = gpg_error (GPG_ERR_BAD_PASSPHRASE);
-      if (cache_nonce)
+      if (!is_protected)
+        {
+          err = try_do_unprotect_cb (pi);
+        }
+      else if (cache_nonce)
         {
           char *cache_value;
 
@@ -908,7 +962,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
       if (gpg_err_code (err) == GPG_ERR_BAD_PASSPHRASE && !from_native)
         err = agent_askpin (ctrl, prompt, NULL, NULL, pi);
       skeyidx = pi_arg.skeyidx;
-      if (!err && r_passphrase)
+      if (!err && r_passphrase && is_protected)
         {
           *r_passphrase = xtrystrdup (pi->pin);
           if (!*r_passphrase)
@@ -929,6 +983,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
   err = make_canon_sexp_pad (s_skey, 1, r_key, NULL);
 
  leave:
+  xfree (curve);
   gcry_sexp_release (s_skey);
   gcry_sexp_release (list);
   gcry_sexp_release (top_list);
@@ -1037,15 +1092,36 @@ apply_protection (gcry_mpi_t *array, int npkey, int nskey,
   ndata = 20; /* Space for the SHA-1 checksum.  */
   for (i = npkey, j = 0; i < nskey; i++, j++ )
     {
-      err = gcry_mpi_aprint (GCRYMPI_FMT_USG, bufarr+j, narr+j, array[i]);
-      if (err)
+      if (gcry_mpi_get_flag (array[i], GCRYMPI_FLAG_OPAQUE))
         {
-          err = gpg_error_from_syserror ();
-          for (i = 0; i < j; i++)
-            xfree (bufarr[i]);
-          return err;
+          const void *s;
+          unsigned int n;
+
+          s = gcry_mpi_get_opaque (array[i], &n);
+          nbits[j] = n;
+          n = (n+7)/8;
+          narr[j] = n;
+          bufarr[j] = gcry_is_secure (s)? xtrymalloc_secure (n):xtrymalloc (n);
+          if (!bufarr[j])
+            {
+              err = gpg_error_from_syserror ();
+              for (i = 0; i < j; i++)
+                xfree (bufarr[i]);
+              return err;
+            }
+          memcpy (bufarr[j], s, n);
+        }
+      else
+        {
+          err = gcry_mpi_aprint (GCRYMPI_FMT_USG, bufarr+j, narr+j, array[i]);
+          if (err)
+            {
+              for (i = 0; i < j; i++)
+                xfree (bufarr[i]);
+              return err;
+            }
+          nbits[j] = gcry_mpi_get_nbits (array[i]);
         }
-      nbits[j] = gcry_mpi_get_nbits (array[i]);
       ndata += 2 + narr[j];
     }
 
@@ -1115,6 +1191,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
   const char *algoname;
   int npkey, nskey;
   gcry_mpi_t array[10];
+  gcry_sexp_t curve = NULL;
   char protect_iv[16];
   char salt[8];
   unsigned long s2k_count;
@@ -1173,13 +1250,24 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
     }
   else if (!strcmp (name, "ecc"))
     {
-      /* FIXME: We need to use the curve parameter.  */
+      gcry_buffer_t iob;
+      char iobbuf[32];
+
       algoname = "ecc"; /* Decide later by checking the usage.  */
-      npkey = 6;
-      nskey = 7;
-      err = gcry_sexp_extract_param (list, NULL, "pabgnqd",
-                                     array+0, array+1, array+2, array+3,
-                                     array+4, array+5, array+6, NULL);
+      npkey = 1;
+      nskey = 2;
+      iob.data = iobbuf;
+      iob.size = sizeof iobbuf - 1;
+      iob.off = 0;
+      iob.len = 0;
+      err = gcry_sexp_extract_param (list, NULL, "&'curve'/qd",
+                                     &iob, array+0, array+1, NULL);
+      if (!err)
+        {
+          assert (iob.len < sizeof iobbuf -1);
+          iobbuf[iob.len] = 0;
+          err = gcry_sexp_build (&curve, NULL, "(curve %s)", iobbuf);
+        }
     }
   else if (!strcmp (name, "ecdsa"))
     {
@@ -1204,9 +1292,12 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
       err = gpg_error (GPG_ERR_PUBKEY_ALGO);
     }
   xfree (name);
-  gcry_sexp_release (list);
+  gcry_sexp_release (list); list = NULL;
   if (err)
-    return err;
+    {
+      gcry_sexp_release (curve);
+      return err;
+    }
 
   gcry_create_nonce (protect_iv, sizeof protect_iv);
   gcry_create_nonce (salt, sizeof salt);
@@ -1223,11 +1314,9 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
     {
       char countbuf[35];
       membuf_t mbuf;
-      void *format_args_buf_ptr[1];
-      int   format_args_buf_int[1];
       void *format_args[10+2];
-      unsigned int n;
-      gcry_sexp_t tmpkey, tmpsexp = NULL;
+      gcry_sexp_t tmpkey;
+      gcry_sexp_t tmpsexp = NULL;
 
       snprintf (countbuf, sizeof countbuf, "%lu", s2k_count);
 
@@ -1238,11 +1327,8 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
           put_membuf_str (&mbuf, " _ %m");
           format_args[j++] = array + i;
         }
-      put_membuf_str (&mbuf, " e %b");
-      format_args_buf_ptr[0] = gcry_mpi_get_opaque (array[npkey], &n);
-      format_args_buf_int[0] = (n+7)/8;
-      format_args[j++] = format_args_buf_int;
-      format_args[j++] = format_args_buf_ptr;
+      put_membuf_str (&mbuf, " e %m");
+      format_args[j++] = array + npkey;
       put_membuf_str (&mbuf, ")\n");
       put_membuf (&mbuf, "", 1);
 
@@ -1260,9 +1346,10 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
                                "(openpgp-private-key\n"
                                " (version 1:4)\n"
                                " (algo %s)\n"
-                               " %S\n"
+                               " %S%S\n"
                                " (protection sha1 aes %b 1:3 sha1 %b %s))\n",
                                algoname,
+                               curve,
                                tmpkey,
                                (int)sizeof protect_iv, protect_iv,
                                (int)sizeof salt, salt,
@@ -1275,6 +1362,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
 
   for (i=0; i < DIM (array); i++)
     gcry_mpi_release (array[i]);
+  gcry_sexp_release (curve);
 
   return err;
 }