Fix minor compiler warnings.
[gnupg.git] / g10 / keygen.c
index 55048b1..9c371bd 100644 (file)
 enum para_name {
   pKEYTYPE,
   pKEYLENGTH,
 enum para_name {
   pKEYTYPE,
   pKEYLENGTH,
+  pKEYCURVE,
   pKEYUSAGE,
   pSUBKEYTYPE,
   pSUBKEYLENGTH,
   pKEYUSAGE,
   pSUBKEYTYPE,
   pSUBKEYLENGTH,
+  pSUBKEYCURVE,
   pSUBKEYUSAGE,
   pAUTHKEYTYPE,
   pNAMEREAL,
   pSUBKEYUSAGE,
   pAUTHKEYTYPE,
   pNAMEREAL,
@@ -216,9 +218,6 @@ do_add_key_flags (PKT_signature *sig, unsigned int use)
     if (use & PUBKEY_USAGE_AUTH)
         buf[0] |= 0x20;
 
     if (use & PUBKEY_USAGE_AUTH)
         buf[0] |= 0x20;
 
-    if (!buf[0])
-        return;
-
     build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1);
 }
 
     build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1);
 }
 
@@ -272,7 +271,7 @@ set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf)
     for (i=0; i < *nbuf; i++ )
       if (buf[i] == val)
        {
     for (i=0; i < *nbuf; i++ )
       if (buf[i] == val)
        {
-         log_info (_("preference `%s' duplicated\n"), item);
+         log_info (_("preference '%s' duplicated\n"), item);
          return -1;
         }
 
          return -1;
         }
 
@@ -349,7 +348,7 @@ keygen_set_std_prefs (const char *string,int personal)
               break PGP2, but that is difficult with the current
               code, and not really worth checking as a non-RSA <=2048
               bit key wouldn't be usable by PGP2 anyway. -dms */
               break PGP2, but that is difficult with the current
               code, and not really worth checking as a non-RSA <=2048
               bit key wouldn't be usable by PGP2 anyway. -dms */
-           if ( !openpgp_cipher_test_algo (CIPHER_ALGO_IDEA) )
+           if (PGP2 && !openpgp_cipher_test_algo (CIPHER_ALGO_IDEA) )
              strcat(dummy_string,"S1 ");
 
 
              strcat(dummy_string,"S1 ");
 
 
@@ -441,13 +440,7 @@ keygen_set_std_prefs (const char *string,int personal)
              modify=0;
            else
              {
              modify=0;
            else
              {
-               log_info (_("invalid item `%s' in preference string\n"),tok);
-
-               /* Complain if IDEA is not available. */
-               if(ascii_strcasecmp(tok,"s1")==0
-                  || ascii_strcasecmp(tok,"idea")==0)
-                 idea_cipher_warn(1);
-
+               log_info (_("invalid item '%s' in preference string\n"),tok);
                rc=-1;
              }
          }
                rc=-1;
              }
          }
@@ -1080,40 +1073,6 @@ write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk,
   return err;
 }
 
   return err;
 }
 
-/* Map the Libgcrypt ECC curve NAME to an OID.  If R_NBITS is not NULL
-   store the bit size of the curve there.  Returns NULL for unknown
-   curve names.  */
-const char *
-gpg_curve_to_oid (const char *name, unsigned int *r_nbits)
-{
-  unsigned int nbits = 0;
-  const char *oidstr;
-
-  if (!name)
-    oidstr = NULL;
-  else if (!strcmp (name, "NIST P-256"))
-    {
-      oidstr = "1.2.840.10045.3.1.7";
-      nbits = 256;
-    }
-  else if (!strcmp (name, "NIST P-384"))
-    {
-      oidstr = "1.3.132.0.34";
-      nbits = 384;
-    }
-  else if (!strcmp (name, "NIST P-521"))
-    {
-      oidstr = "1.3.132.0.35";
-      nbits = 521;
-    }
-  else
-    oidstr = NULL;
-
-  if (r_nbits)
-    *r_nbits = nbits;
-  return oidstr;
-}
-
 
 static gpg_error_t
 ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
 
 static gpg_error_t
 ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
@@ -1151,7 +1110,7 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
       goto leave;
     }
   gcry_sexp_release (l2);
       goto leave;
     }
   gcry_sexp_release (l2);
-  oidstr = gpg_curve_to_oid (curve, &nbits);
+  oidstr = openpgp_curve_to_oid (curve, &nbits);
   if (!oidstr)
     {
       /* That can't happen because we used one of the curves
   if (!oidstr)
     {
       /* That can't happen because we used one of the curves
@@ -1197,7 +1156,7 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
           array[i] = NULL;
         }
     }
           array[i] = NULL;
         }
     }
-  return 0;
+  return err;
 }
 
 
 }
 
 
@@ -1417,7 +1376,7 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
 
   if (nbits < 512)
     {
 
   if (nbits < 512)
     {
-      nbits = 1024;
+      nbits = 2048;
       log_info (_("keysize invalid; using %u bits\n"), nbits );
     }
 
       log_info (_("keysize invalid; using %u bits\n"), nbits );
     }
 
@@ -1467,7 +1426,7 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
 
   if ( nbits < 512)
     {
 
   if ( nbits < 512)
     {
-      nbits = 1024;
+      nbits = 2048;
       log_info(_("keysize invalid; using %u bits\n"), nbits );
     }
   else if ( nbits > 3072 )
       log_info(_("keysize invalid; using %u bits\n"), nbits );
     }
   else if ( nbits > 3072 )
@@ -1543,31 +1502,24 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
  * Generate an ECC key
  */
 static gpg_error_t
  * Generate an ECC key
  */
 static gpg_error_t
-gen_ecc (int algo, unsigned int nbits, kbnode_t pub_root,
+gen_ecc (int algo, const char *curve, kbnode_t pub_root,
          u32 timestamp, u32 expireval, int is_subkey,
          int keygen_flags, char **cache_nonce_addr)
 {
   gpg_error_t err;
          u32 timestamp, u32 expireval, int is_subkey,
          int keygen_flags, char **cache_nonce_addr)
 {
   gpg_error_t err;
-  const char *curve;
   char *keyparms;
 
   assert (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH);
 
   char *keyparms;
 
   assert (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH);
 
-  /* For now we may only use one of the 3 NIST curves.  See also
-     gpg_curve_to_oid.  */
-  if (nbits <= 256)
-    curve = "NIST P-256";
-  else if (nbits <= 384)
-    curve = "NIST P-384";
-  else
-    curve = "NIST P-521";
+  if (!curve || !*curve)
+    return gpg_error (GPG_ERR_UNKNOWN_CURVE);
 
 
-  keyparms = xtryasprintf ("(genkey(%s(curve %zu:%s)%s))",
-                           algo == PUBKEY_ALGO_ECDSA ? "ecdsa" : "ecdh",
+  keyparms = xtryasprintf ("(genkey(ecc(curve %zu:%s)(flags nocomp%s%s)))",
                            strlen (curve), curve,
                            strlen (curve), curve,
-                           ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
-                            && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
-                           "(transient-key)" : "" );
+                           (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
+                             && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
+                            " transient-key" : ""),
+                           (!strcmp (curve, "Ed25519")? " eddsa":""));
   if (!keyparms)
     err = gpg_error_from_syserror ();
   else
   if (!keyparms)
     err = gpg_error_from_syserror ();
   else
@@ -1601,7 +1553,7 @@ gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
 
   if (nbits < 1024)
     {
 
   if (nbits < 1024)
     {
-      nbits = 1024;
+      nbits = 2048;
       log_info (_("keysize invalid; using %u bits\n"), nbits );
     }
 
       log_info (_("keysize invalid; using %u bits\n"), nbits );
     }
 
@@ -2091,6 +2043,98 @@ ask_keysize (int algo, unsigned int primary_keysize)
 }
 
 
 }
 
 
+/* Ask for the key size.  ALGO is the algorithm.  If PRIMARY_KEYSIZE
+   is not 0, the function asks for the size of the encryption
+   subkey. */
+static char *
+ask_curve (void)
+{
+  struct {
+    const char *name;
+    int available;
+    int expert_only;
+    const char *pretty_name;
+  } curves[] = {
+    { "Ed25519",         0, 0, "Curve 25519" },
+    { "NIST P-256",      0, 1, },
+    { "NIST P-384",      0, 0, },
+    { "NIST P-521",      0, 1, },
+    { "brainpoolP256r1", 0, 1, "Brainpool P-256" },
+    { "brainpoolP384r1", 0, 1, "Brainpool P-384" },
+    { "brainpoolP512r1", 0, 1, "Brainpool P-512" },
+  };
+  int idx;
+  char *answer;
+  char *result = NULL;
+  gcry_sexp_t keyparms;
+
+  tty_printf (_("Please select which elliptic curve you want:\n"));
+
+  keyparms = NULL;
+  for (idx=0; idx < DIM(curves); idx++)
+    {
+      int rc;
+
+      curves[idx].available = 0;
+      if (!opt.expert && curves[idx].expert_only)
+        continue;
+
+      gcry_sexp_release (keyparms);
+      rc = gcry_sexp_build (&keyparms, NULL,
+                            "(public-key(ecc(curve %s)))", curves[idx].name);
+      if (rc)
+        continue;
+      if (!gcry_pk_get_curve (keyparms, 0, NULL))
+        continue;
+
+      curves[idx].available = 1;
+      tty_printf (_("   (%d) %s\n"), idx + 1,
+                  curves[idx].pretty_name?
+                  curves[idx].pretty_name:curves[idx].name);
+    }
+  gcry_sexp_release (keyparms);
+
+
+  for (;;)
+    {
+      answer = cpr_get ("keygen.curve", _("Your selection? "));
+      cpr_kill_prompt ();
+      idx = *answer? atoi (answer) : 1;
+      if (*answer && !idx)
+        {
+          /* See whether the user entered the name of the curve.  */
+          for (idx=0; idx < DIM(curves); idx++)
+            {
+              if (!opt.expert && curves[idx].expert_only)
+                continue;
+              if (!stricmp (curves[idx].name, answer)
+                  || (curves[idx].pretty_name
+                      && !stricmp (curves[idx].pretty_name, answer)))
+                break;
+            }
+          if (idx == DIM(curves))
+            idx = -1;
+        }
+      else
+        idx--;
+      xfree(answer);
+      answer = NULL;
+      if (idx < 0 || idx >= DIM (curves) || !curves[idx].available)
+        tty_printf (_("Invalid selection.\n"));
+      else
+        {
+          result = xstrdup (curves[idx].name);
+          break;
+        }
+    }
+
+  if (!result)
+    result = xstrdup (curves[0].name);
+
+  return result;
+}
+
+
 /****************
  * Parse an expire string and return its value in seconds.
  * Returns (u32)-1 on error.
 /****************
  * Parse an expire string and return its value in seconds.
  * Returns (u32)-1 on error.
@@ -2393,7 +2437,7 @@ ask_user_id (int mode, KBNODE keyblock)
        /* print a note in case that UTF8 mapping has to be done */
        for(p=uid; *p; p++ ) {
            if( *p & 0x80 ) {
        /* print a note in case that UTF8 mapping has to be done */
        for(p=uid; *p; p++ ) {
            if( *p & 0x80 ) {
-               tty_printf(_("You are using the `%s' character set.\n"),
+               tty_printf(_("You are using the '%s' character set.\n"),
                           get_native_charset() );
                break;
            }
                           get_native_charset() );
                break;
            }
@@ -2548,7 +2592,7 @@ do_ask_passphrase (STRING2KEY **ret_s2k, int mode, int *r_canceled)
 /* Basic key generation.  Here we divert to the actual generation
    routines based on the requested algorithm.  */
 static int
 /* Basic key generation.  Here we divert to the actual generation
    routines based on the requested algorithm.  */
 static int
-do_create (int algo, unsigned int nbits, KBNODE pub_root,
+do_create (int algo, unsigned int nbits, const char *curve, KBNODE pub_root,
            u32 timestamp, u32 expiredate, int is_subkey,
            int keygen_flags, char **cache_nonce_addr)
 {
            u32 timestamp, u32 expiredate, int is_subkey,
            int keygen_flags, char **cache_nonce_addr)
 {
@@ -2570,7 +2614,7 @@ do_create (int algo, unsigned int nbits, KBNODE pub_root,
     err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey,
                    keygen_flags, cache_nonce_addr);
   else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
     err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey,
                    keygen_flags, cache_nonce_addr);
   else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
-    err = gen_ecc (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
+    err = gen_ecc (algo, curve, pub_root, timestamp, expiredate, is_subkey,
                    keygen_flags, cache_nonce_addr);
   else if (algo == PUBKEY_ALGO_RSA)
     err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
                    keygen_flags, cache_nonce_addr);
   else if (algo == PUBKEY_ALGO_RSA)
     err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
@@ -2597,6 +2641,17 @@ generate_user_id (KBNODE keyblock)
 }
 
 
 }
 
 
+/* Append R to the linked list PARA.  */
+static void
+append_to_parameter (struct para_data_s *para, struct para_data_s *r)
+{
+  assert (para);
+  while (para->next)
+    para = para->next;
+  para->next = r;
+}
+
+/* Release the parameter list R.  */
 static void
 release_parameter_list (struct para_data_s *r)
 {
 static void
 release_parameter_list (struct para_data_s *r)
 {
@@ -2823,8 +2878,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
       r->u.usage = (is_default
                     ? (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG)
                     : openpgp_pk_algo_usage(algo));
       r->u.usage = (is_default
                     ? (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG)
                     : openpgp_pk_algo_usage(algo));
-      r->next = para;
-      para = r;
+      append_to_parameter (para, r);
     }
   else if (err == -1)
     return -1;
     }
   else if (err == -1)
     return -1;
@@ -2860,8 +2914,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
          r->u.usage = (is_default
                         ? PUBKEY_USAGE_ENC
                         : openpgp_pk_algo_usage (algo));
          r->u.usage = (is_default
                         ? PUBKEY_USAGE_ENC
                         : openpgp_pk_algo_usage (algo));
-         r->next = para;
-         para = r;
+          append_to_parameter (para, r);
        }
       else if (err == -1)
        return -1;
        }
       else if (err == -1)
        return -1;
@@ -2898,8 +2951,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
            p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")");
          if( s3 )
            p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">");
            p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")");
          if( s3 )
            p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">");
-         r->next = para;
-         para = r;
+          append_to_parameter (para, r);
          have_user_id=1;
        }
     }
          have_user_id=1;
        }
     }
@@ -2952,13 +3004,11 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
           r = xmalloc_clear( sizeof *r );
           r->key = pPASSPHRASE_DEK;
           r->u.dek = dek;
           r = xmalloc_clear( sizeof *r );
           r->key = pPASSPHRASE_DEK;
           r->u.dek = dek;
-          r->next = para;
-          para = r;
+          append_to_parameter (para, r);
           r = xmalloc_clear( sizeof *r );
           r->key = pPASSPHRASE_S2K;
           r->u.s2k = s2k;
           r = xmalloc_clear( sizeof *r );
           r->key = pPASSPHRASE_S2K;
           r->u.s2k = s2k;
-          r->next = para;
-          para = r;
+          append_to_parameter (para, r);
         }
 
       if (canceled)
         }
 
       if (canceled)
@@ -2978,26 +3028,30 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
           STRING2KEY *s2k;
           DEK *dek;
 
           STRING2KEY *s2k;
           DEK *dek;
 
-          s2k = xmalloc_secure ( sizeof *s2k );
+          s2k = xmalloc ( sizeof *s2k );
           s2k->mode = opt.s2k_mode;
           s2k->hash_algo = S2K_DIGEST_ALGO;
           set_next_passphrase ( r->u.value );
           dek = passphrase_to_dek (NULL, 0, opt.s2k_cipher_algo, s2k, 2,
                                    NULL, NULL);
           s2k->mode = opt.s2k_mode;
           s2k->hash_algo = S2K_DIGEST_ALGO;
           set_next_passphrase ( r->u.value );
           dek = passphrase_to_dek (NULL, 0, opt.s2k_cipher_algo, s2k, 2,
                                    NULL, NULL);
-          set_next_passphrase (NULL );
-          assert (dek);
+          if (!dek)
+            {
+              log_error ("%s:%d: error post processing the passphrase\n",
+                         fname, r->lnr );
+              xfree (s2k);
+              return -1;
+            }
+          set_next_passphrase (NULL);
           memset (r->u.value, 0, strlen(r->u.value));
 
           r = xmalloc_clear (sizeof *r);
           r->key = pPASSPHRASE_S2K;
           r->u.s2k = s2k;
           memset (r->u.value, 0, strlen(r->u.value));
 
           r = xmalloc_clear (sizeof *r);
           r->key = pPASSPHRASE_S2K;
           r->u.s2k = s2k;
-          r->next = para;
-          para = r;
+          append_to_parameter (para, r);
           r = xmalloc_clear (sizeof *r);
           r->key = pPASSPHRASE_DEK;
           r->u.dek = dek;
           r = xmalloc_clear (sizeof *r);
           r->key = pPASSPHRASE_DEK;
           r->u.dek = dek;
-          r->next = para;
-          para = r;
+          append_to_parameter (para, r);
         }
     }
 
         }
     }
 
@@ -3035,8 +3089,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
       r = xmalloc_clear( sizeof *r + 20 );
       r->key = pSUBKEYEXPIRE;
       r->u.expire = seconds;
       r = xmalloc_clear( sizeof *r + 20 );
       r->key = pSUBKEYEXPIRE;
       r->u.expire = seconds;
-      r->next = para;
-      para = r;
+      append_to_parameter (para, r);
     }
 
   do_generate_keypair( para, outctrl, card );
     }
 
   do_generate_keypair( para, outctrl, card );
@@ -3057,9 +3110,11 @@ read_parameter_file( const char *fname )
     } keywords[] = {
        { "Key-Type",       pKEYTYPE},
        { "Key-Length",     pKEYLENGTH },
     } keywords[] = {
        { "Key-Type",       pKEYTYPE},
        { "Key-Length",     pKEYLENGTH },
+       { "Key-Curve",      pKEYCURVE },
        { "Key-Usage",      pKEYUSAGE },
        { "Subkey-Type",    pSUBKEYTYPE },
        { "Subkey-Length",  pSUBKEYLENGTH },
        { "Key-Usage",      pKEYUSAGE },
        { "Subkey-Type",    pSUBKEYTYPE },
        { "Subkey-Length",  pSUBKEYLENGTH },
+       { "Subkey-Curve",   pSUBKEYCURVE },
        { "Subkey-Usage",   pSUBKEYUSAGE },
        { "Name-Real",      pNAMEREAL },
        { "Name-Email",     pNAMEEMAIL },
        { "Subkey-Usage",   pSUBKEYUSAGE },
        { "Name-Real",      pNAMEREAL },
        { "Name-Email",     pNAMEEMAIL },
@@ -3097,7 +3152,7 @@ read_parameter_file( const char *fname )
         gpg_err_set_errno (EPERM);
       }
     if (!fp) {
         gpg_err_set_errno (EPERM);
       }
     if (!fp) {
-      log_error (_("can't open `%s': %s\n"), fname, strerror(errno) );
+      log_error (_("can't open '%s': %s\n"), fname, strerror(errno) );
       return;
     }
     iobuf_ioctl (fp, IOBUF_IOCTL_NO_CACHE, 1, NULL);
       return;
     }
     iobuf_ioctl (fp, IOBUF_IOCTL_NO_CACHE, 1, NULL);
@@ -3162,7 +3217,7 @@ read_parameter_file( const char *fname )
               /* Ignore this command.  */
            }
            else
               /* Ignore this command.  */
            }
            else
-               log_info("skipping control `%s' (%s)\n", keyword, value );
+               log_info("skipping control '%s' (%s)\n", keyword, value );
 
 
            continue;
 
 
            continue;
@@ -3339,6 +3394,7 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
   else
     {
       int subkey_algo;
   else
     {
       int subkey_algo;
+      char *curve = NULL;
 
       /* Fixme: To support creating a primary key by keygrip we better
          also define the keyword for the parameter file.  Note that
 
       /* Fixme: To support creating a primary key by keygrip we better
          also define the keyword for the parameter file.  Note that
@@ -3354,12 +3410,24 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
           sprintf( r->u.value, "%d", algo );
           r->next = para;
           para = r;
           sprintf( r->u.value, "%d", algo );
           r->next = para;
           para = r;
-         nbits = ask_keysize (algo, 0);
-         r = xmalloc_clear( sizeof *r + 20 );
-         r->key = pKEYLENGTH;
-         sprintf( r->u.value, "%u", nbits);
-         r->next = para;
-         para = r;
+          if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
+            {
+              curve = ask_curve ();
+              r = xmalloc_clear (sizeof *r + strlen (curve));
+              r->key = pKEYCURVE;
+              strcpy (r->u.value, curve);
+              r->next = para;
+              para = r;
+            }
+          else
+            {
+              nbits = ask_keysize (algo, 0);
+              r = xmalloc_clear( sizeof *r + 20 );
+              r->key = pKEYLENGTH;
+              sprintf( r->u.value, "%u", nbits);
+              r->next = para;
+              para = r;
+            }
           r = xmalloc_clear( sizeof *r + 20 );
           r->key = pKEYUSAGE;
           strcpy( r->u.value, "sign" );
           r = xmalloc_clear( sizeof *r + 20 );
           r->key = pKEYUSAGE;
           strcpy( r->u.value, "sign" );
@@ -3399,12 +3467,27 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
           nbits = 0;
         }
 
           nbits = 0;
         }
 
-      nbits = ask_keysize (both? subkey_algo : algo, nbits);
-      r = xmalloc_clear( sizeof *r + 20 );
-      r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
-      sprintf( r->u.value, "%u", nbits);
-      r->next = para;
-      para = r;
+      if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
+        {
+          if (!both)
+            curve = ask_curve ();
+          r = xmalloc_clear (sizeof *r + strlen (curve));
+          r->key = both? pSUBKEYCURVE : pKEYCURVE;
+          strcpy (r->u.value, curve);
+          r->next = para;
+          para = r;
+        }
+      else
+        {
+          nbits = ask_keysize (both? subkey_algo : algo, nbits);
+          r = xmalloc_clear( sizeof *r + 20 );
+          r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
+          sprintf( r->u.value, "%u", nbits);
+          r->next = para;
+          para = r;
+        }
+
+      xfree (curve);
     }
 
   expire = ask_expire_interval(0,NULL);
     }
 
   expire = ask_expire_interval(0,NULL);
@@ -3590,7 +3673,7 @@ do_generate_keypair (struct para_data_s *para,
             outctrl->pub.stream = iobuf_create( outctrl->pub.fname );
           if (!outctrl->pub.stream)
             {
             outctrl->pub.stream = iobuf_create( outctrl->pub.fname );
           if (!outctrl->pub.stream)
             {
-              log_error(_("can't create `%s': %s\n"), outctrl->pub.newfname,
+              log_error(_("can't create '%s': %s\n"), outctrl->pub.newfname,
                         strerror(errno) );
               return;
             }
                         strerror(errno) );
               return;
             }
@@ -3602,7 +3685,7 @@ do_generate_keypair (struct para_data_s *para,
         }
       assert( outctrl->pub.stream );
       if (opt.verbose)
         }
       assert( outctrl->pub.stream );
       if (opt.verbose)
-        log_info (_("writing public key to `%s'\n"), outctrl->pub.fname );
+        log_info (_("writing public key to '%s'\n"), outctrl->pub.fname );
     }
 
 
     }
 
 
@@ -3629,6 +3712,7 @@ do_generate_keypair (struct para_data_s *para,
   if (!card)
     err = do_create (get_parameter_algo( para, pKEYTYPE, NULL ),
                      get_parameter_uint( para, pKEYLENGTH ),
   if (!card)
     err = do_create (get_parameter_algo( para, pKEYTYPE, NULL ),
                      get_parameter_uint( para, pKEYLENGTH ),
+                     get_parameter_value (para, pKEYCURVE),
                      pub_root,
                      timestamp,
                      get_parameter_u32( para, pKEYEXPIRE ), 0,
                      pub_root,
                      timestamp,
                      get_parameter_u32( para, pKEYEXPIRE ), 0,
@@ -3680,6 +3764,7 @@ do_generate_keypair (struct para_data_s *para,
         {
           err = do_create (get_parameter_algo (para, pSUBKEYTYPE, NULL),
                            get_parameter_uint (para, pSUBKEYLENGTH),
         {
           err = do_create (get_parameter_algo (para, pSUBKEYTYPE, NULL),
                            get_parameter_uint (para, pSUBKEYLENGTH),
+                           get_parameter_value (para, pSUBKEYCURVE),
                            pub_root,
                            timestamp,
                            get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
                            pub_root,
                            timestamp,
                            get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
@@ -3738,7 +3823,7 @@ do_generate_keypair (struct para_data_s *para,
 
       if (!err && opt.verbose)
         {
 
       if (!err && opt.verbose)
         {
-          log_info (_("writing public key to `%s'\n"),
+          log_info (_("writing public key to '%s'\n"),
                     keydb_get_resource_name (pub_hd));
         }
 
                     keydb_get_resource_name (pub_hd));
         }
 
@@ -3746,7 +3831,7 @@ do_generate_keypair (struct para_data_s *para,
         {
           err = keydb_insert_keyblock (pub_hd, pub_root);
           if (err)
         {
           err = keydb_insert_keyblock (pub_hd, pub_root);
           if (err)
-            log_error (_("error writing public keyring `%s': %s\n"),
+            log_error (_("error writing public keyring '%s': %s\n"),
                        keydb_get_resource_name (pub_hd), g10_errstr(err));
         }
 
                        keydb_get_resource_name (pub_hd), g10_errstr(err));
         }
 
@@ -3826,7 +3911,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
   int algo;
   unsigned int use;
   u32 expire;
   int algo;
   unsigned int use;
   u32 expire;
-  unsigned int nbits;
+  unsigned int nbits = 0;
+  char *curve = NULL;
   u32 cur_time;
   char *hexgrip = NULL;
   char *serialno = NULL;
   u32 cur_time;
   char *hexgrip = NULL;
   char *serialno = NULL;
@@ -3880,7 +3966,14 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
   hexgrip = NULL;
   algo = ask_algo (ctrl, 1, NULL, &use, &hexgrip);
   assert (algo);
   hexgrip = NULL;
   algo = ask_algo (ctrl, 1, NULL, &use, &hexgrip);
   assert (algo);
-  nbits = hexgrip? 0 : ask_keysize (algo, 0);
+
+  if (hexgrip)
+    nbits = 0;
+  else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
+    curve = ask_curve ();
+  else
+    nbits = ask_keysize (algo, 0);
+
   expire = ask_expire_interval (0, NULL);
   if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay",
                                                _("Really create? (y/N) ")))
   expire = ask_expire_interval (0, NULL);
   if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay",
                                                _("Really create? (y/N) ")))
@@ -3893,7 +3986,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
     err = do_create_from_keygrip (ctrl, algo, hexgrip,
                                   keyblock, cur_time, expire, 1);
   else
     err = do_create_from_keygrip (ctrl, algo, hexgrip,
                                   keyblock, cur_time, expire, 1);
   else
-    err = do_create (algo, nbits, keyblock, cur_time, expire, 1, 0, NULL);
+    err = do_create (algo, nbits, curve,
+                     keyblock, cur_time, expire, 1, 0, NULL);
   if (err)
     goto leave;
 
   if (err)
     goto leave;
 
@@ -3910,6 +4004,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
   write_status_text (STATUS_KEY_CREATED, "S");
 
  leave:
   write_status_text (STATUS_KEY_CREATED, "S");
 
  leave:
+  xfree (curve);
   xfree (hexgrip);
   xfree (serialno);
   if (err)
   xfree (hexgrip);
   xfree (serialno);
   if (err)
@@ -4206,7 +4301,7 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
     if (!fp)
       {
         rc = gpg_error_from_syserror ();
     if (!fp)
       {
         rc = gpg_error_from_syserror ();
-       log_error (_("can't create backup file `%s': %s\n"),
+       log_error (_("can't create backup file '%s': %s\n"),
                    fname, strerror(errno) );
         xfree (fname);
         free_secret_key (sk_unprotected);
                    fname, strerror(errno) );
         xfree (fname);
         free_secret_key (sk_unprotected);
@@ -4232,7 +4327,7 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
 
         iobuf_close (fp);
         iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
 
         iobuf_close (fp);
         iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
-        log_info (_("NOTE: backup of card key saved to `%s'\n"), fname);
+        log_info (_("NOTE: backup of card key saved to '%s'\n"), fname);
 
         fingerprint_from_sk (sk, array, &n);
         p = fprbuf = xmalloc (MAX_FINGERPRINT_LEN*2 + 1 + 1);
 
         fingerprint_from_sk (sk, array, &n);
         p = fprbuf = xmalloc (MAX_FINGERPRINT_LEN*2 + 1 + 1);