gpg: New option --default-new-key-algo.
authorWerner Koch <wk@gnupg.org>
Fri, 2 Dec 2016 18:43:36 +0000 (19:43 +0100)
committerWerner Koch <wk@gnupg.org>
Fri, 2 Dec 2016 18:47:40 +0000 (19:47 +0100)
* common/openpgp-oid.c (openpgp_is_curve_supported): Add optional arg
R_ALGO and change all callers.
* common/util.h (GPG_ERR_UNKNOWN_FLAG): New error code.
* g10/options.h (struct opt): Add field DEF_NEW_KEY_ALGO.
* g10/gpg.c (oDefaultNewKeyAlgo): New enum.
(opts): New option "--default-new-key-algo".
(main): Set the option.
* g10/keygen.c: Remove DEFAULT_STD_ FUTURE_STD_ constants and replace
them by ...
(DEFAULT_STD_KEY_PARAM, FUTURE_STD_KEY_PARAM): new string constants.
(get_keysize_range): Remove arg R_DEF and return that value instead.
Change all callers.
(gen_rsa): Use get_keysize_range instead of the removed
DEFAULT_STD_KEYSIZE.
(parse_key_parameter_part): New function.
(parse_key_parameter_string): New function.
(quick_generate_keypair): Refactor using parse_key_parameter_string.
(generate_keypair): Ditto.
(parse_algo_usage_expire): Ditto.
--

This new option is intended to be used in the forthcoming
--set-profile command of gpgconf.  It allows to provide a gpg
configuration with custom defaults for a new key using the simple
commands which use the default algorithm set.

Signed-off-by: Werner Koch <wk@gnupg.org>
NEWS
common/openpgp-oid.c
common/util.h
doc/gpg.texi
g10/call-agent.c
g10/gpg.c
g10/keygen.c
g10/options.h
scd/app-openpgp.c

diff --git a/NEWS b/NEWS
index 2031008..d11c5ff 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,8 @@
 Noteworthy changes in version 2.1.17 (unreleased)
 -------------------------------------------------
 
+ * gpg: New option --default-new-key-algo.
+
 
 Noteworthy changes in version 2.1.16 (2016-11-18)
 -------------------------------------------------
index 270bdf1..e7c68f2 100644 (file)
@@ -411,17 +411,21 @@ openpgp_enum_curves (int *iterp)
 }
 
 
-/* Return the Libgcrypt name for for the gpg curve NAME if supported.
- * If R_ALGO is not NULL the required OpenPGP public key algo or 0 is
- * stored at that address.  NULL is returned if the curev is not
- * supported. */
+/* Return the Libgcrypt name for the gpg curve NAME if supported.  If
+ * R_ALGO is not NULL the required OpenPGP public key algo or 0 is
+ * stored at that address.  If R_NBITS is not NULL the nominal bitsize
+ * of the curves is stored there.  NULL is returned if the curve is
+ * not supported. */
 const char *
-openpgp_is_curve_supported (const char *name, int *r_algo)
+openpgp_is_curve_supported (const char *name, int *r_algo,
+                            unsigned int *r_nbits)
 {
   int idx;
 
   if (r_algo)
     *r_algo = 0;
+  if (r_nbits)
+    *r_nbits = 0;
   for (idx = 0; idx < DIM (oidtable) && oidtable[idx].name; idx++)
     {
       if ((!strcmp (name, oidtable[idx].name)
@@ -430,6 +434,8 @@ openpgp_is_curve_supported (const char *name, int *r_algo)
         {
           if (r_algo)
             *r_algo = oidtable[idx].pubkey_algo;
+          if (r_nbits)
+            *r_nbits = oidtable[idx].nbits;
           return oidtable[idx].name;
         }
     }
index 2f82fb0..6e437b9 100644 (file)
@@ -39,6 +39,9 @@
  * libgpg-error version.  Define them here.
  * Example: (#if GPG_ERROR_VERSION_NUMBER < 0x011500 // 1.21)
  */
+#if GPG_ERROR_VERSION_NUMBER < 0x011a00 /* 1.26 */
+# define GPG_ERR_UNKNOWN_FLAG 309
+#endif
 
 
 /* Hash function used with libksba. */
@@ -210,7 +213,8 @@ int openpgp_oid_is_cv25519 (gcry_mpi_t a);
 const char *openpgp_curve_to_oid (const char *name, unsigned int *r_nbits);
 const char *openpgp_oid_to_curve (const char *oid, int canon);
 const char *openpgp_enum_curves (int *idxp);
-const char *openpgp_is_curve_supported (const char *name, int *r_algo);
+const char *openpgp_is_curve_supported (const char *name,
+                                        int *r_algo, unsigned int *r_nbits);
 
 
 /*-- homedir.c --*/
index e3756e9..b01d0a3 100644 (file)
@@ -1159,7 +1159,11 @@ filename given on the command line, gpg might still need to read from
 STDIN (in particular if gpg figures that the input is a
 detached signature and no data file has been specified).  Thus if you
 do not want to feed data via STDIN, you should connect STDIN to
-@file{/dev/null}.
+g@file{/dev/null}.
+
+It is highly recommended to use this option along with the options
+@option{--status-fd} and @option{--with-colons} for any unattended of
+@command{gpg}.
 
 @item --no-tty
 @opindex no-tty
@@ -3162,6 +3166,13 @@ letter d (for days), w (for weeks), m (for months), or y (for years)
 (for example "2m" for two months, or "5y" for five years), or an
 absolute date in the form YYYY-MM-DD. Defaults to "0".
 
+@item --default-new-key-algo @var{string}
+@opindex default-new-key-algo @var{string}
+This option can be used to change the default algorithms for key
+generation.  Note that the advanced key generation commands can always
+be used to specify a key algorithm directly.  Please consult the
+source code to learn the syntax of @var{string}.
+
 @item --allow-secret-key-import
 @opindex allow-secret-key-import
 This is an obsolete option and is not used anywhere.
index 1d4bd66..fd9b964 100644 (file)
@@ -624,7 +624,8 @@ learn_status_cb (void *opaque, const char *line)
         parm->key_attr[keyno].nbits = strtoul (line+n+3, NULL, 10);
       else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA
                || algo == PUBKEY_ALGO_EDDSA)
-        parm->key_attr[keyno].curve = openpgp_is_curve_supported (line+n, NULL);
+        parm->key_attr[keyno].curve = openpgp_is_curve_supported (line + n,
+                                                                  NULL, NULL);
     }
   else if (keywordlen == 12 && !memcmp (keyword, "PRIVATE-DO-", 11)
            && strchr("1234", keyword[11]))
index caa0653..7cf51f2 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -407,6 +407,7 @@ enum cmd_and_opt_values
     oPrintDANERecords,
     oTOFUDefaultPolicy,
     oTOFUDBFormat,
+    oDefaultNewKeyAlgo,
     oWeakDigest,
     oUnwrap,
     oOnlySignTextIDs,
@@ -836,6 +837,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oNoAllowMultipleMessages, "no-allow-multiple-messages", "@"),
   ARGPARSE_s_n (oAllowWeakDigestAlgos, "allow-weak-digest-algos", "@"),
 
+  ARGPARSE_s_s (oDefaultNewKeyAlgo, "default-new-key-algo", "@"),
+
   /* These two are aliases to help users of the PGP command line
      product use gpg with minimal pain.  Many commands are common
      already as they seem to have borrowed commands from us.  Now I'm
@@ -3469,6 +3472,10 @@ main (int argc, char **argv)
 
           case oNoAutostart: opt.autostart = 0; break;
 
+         case oDefaultNewKeyAlgo:
+            opt.def_new_key_algo = pargs.r.ret_str;
+            break;
+
          case oNoop: break;
 
          default:
index d249556..ad96cdd 100644 (file)
 
 /* The default algorithms.  If you change them remember to change them
    also in gpg.c:gpgconf_list.  You should also check that the value
-   is inside the bounds enforced by ask_keysize and gen_xxx.  */
-#define DEFAULT_STD_ALGO       PUBKEY_ALGO_RSA
-#define DEFAULT_STD_KEYSIZE    2048
-#define DEFAULT_STD_KEYUSE     (PUBKEY_USAGE_CERT|PUBKEY_USAGE_SIG)
-#define DEFAULT_STD_CURVE      NULL
-#define DEFAULT_STD_SUBALGO    PUBKEY_ALGO_RSA
-#define DEFAULT_STD_SUBKEYSIZE 2048
-#define DEFAULT_STD_SUBKEYUSE  PUBKEY_USAGE_ENC
-#define DEFAULT_STD_SUBCURVE   NULL
-
-#define FUTURE_STD_ALGO        PUBKEY_ALGO_EDDSA
-#define FUTURE_STD_KEYSIZE     0
-#define FUTURE_STD_KEYUSE      (PUBKEY_USAGE_CERT|PUBKEY_USAGE_SIG)
-#define FUTURE_STD_CURVE       "Ed25519"
-#define FUTURE_STD_SUBALGO     PUBKEY_ALGO_ECDH
-#define FUTURE_STD_SUBKEYSIZE  0
-#define FUTURE_STD_SUBKEYUSE   PUBKEY_USAGE_ENC
-#define FUTURE_STD_SUBCURVE    "Curve25519"
+   is inside the bounds enforced by ask_keysize and gen_xxx.  See also
+   get_keysize_range which encodes the allowed ranges.  */
+#define DEFAULT_STD_KEY_PARAM  "rsa2048/cert,sign+rsa2048/encr"
+#define FUTURE_STD_KEY_PARAM   "ed25519/cert,sign+cv25519/encr"
 
 /* Flag bits used during key generation.  */
 #define KEYGEN_FLAG_NO_PROTECTION 1
@@ -157,8 +143,12 @@ static int write_keyblock (iobuf_t out, kbnode_t node);
 static gpg_error_t gen_card_key (int keyno, int algo, int is_primary,
                                  kbnode_t pub_root, u32 *timestamp,
                                  u32 expireval);
+static unsigned int get_keysize_range (int algo,
+                                       unsigned int *min, unsigned int *max);
 
 
+\f
+
 static void
 print_status_key_created (int letter, PKT_public_key *pk, const char *handle)
 {
@@ -1602,7 +1592,7 @@ gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
   log_assert (is_RSA(algo));
 
   if (!nbits)
-    nbits = DEFAULT_STD_KEYSIZE;
+    nbits = get_keysize_range (algo, NULL, NULL);
 
   if (nbits < 1024)
     {
@@ -2056,36 +2046,46 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
 }
 
 
-static void
-get_keysize_range (int algo,
-                   unsigned int *min, unsigned int *def, unsigned int *max)
+static unsigned int
+get_keysize_range (int algo, unsigned int *min, unsigned int *max)
 {
-  *min = opt.compliance == CO_DE_VS ? 2048: 1024;
-  *def = DEFAULT_STD_KEYSIZE;
-  *max = 4096;
+  unsigned int def;
+  unsigned int dummy1, dummy2;
+
+  if (!min)
+    min = &dummy1;
+  if (!max)
+    max = &dummy2;
 
-  /* Deviations from the standard values.  */
   switch(algo)
     {
     case PUBKEY_ALGO_DSA:
       *min = opt.expert? 768 : 1024;
-      *def=2048;
       *max=3072;
+      def=2048;
       break;
 
     case PUBKEY_ALGO_ECDSA:
     case PUBKEY_ALGO_ECDH:
       *min=256;
-      *def=256;
       *max=521;
+      def=256;
       break;
 
     case PUBKEY_ALGO_EDDSA:
       *min=255;
-      *def=255;
       *max=441;
+      def=255;
+      break;
+
+    default:
+      *min = opt.compliance == CO_DE_VS ? 2048: 1024;
+      *max = 4096;
+      def = 2048;
       break;
     }
+
+  return def;
 }
 
 
@@ -2147,7 +2147,7 @@ ask_keysize (int algo, unsigned int primary_keysize)
   int for_subkey = !!primary_keysize;
   int autocomp = 0;
 
-  get_keysize_range (algo, &min, &def, &max);
+  def = get_keysize_range (algo, &min, &max);
 
   if (primary_keysize && !opt.expert)
     {
@@ -2854,6 +2854,292 @@ generate_user_id (KBNODE keyblock, const char *uidstr)
 }
 
 
+/* Helper for parse_key_parameter_string for one part of the
+ * specification string; i.e.  ALGO/FLAGS.  If STRING is NULL or empty
+ * success is returned.  On error an error code is returned.  Note
+ * that STRING may be modified by this function.  NULL may be passed
+ * for any parameter.  FOR_SUBKEY shall be true if this is used as a
+ * subkey.  */
+static gpg_error_t
+parse_key_parameter_part (char *string, int for_subkey,
+                          int *r_algo, unsigned int *r_size,
+                          unsigned int *r_keyuse,
+                          char const **r_curve)
+{
+  char *flags;
+  int algo = 0;
+  char *endp;
+  const char *curve = NULL;
+  int ecdh_or_ecdsa = 0;
+  unsigned int size;
+  int keyuse;
+  int i;
+  const char *s;
+
+  if (!string || !*string)
+    return 0; /* Success.  */
+
+  flags = strchr (string, '/');
+  if (flags)
+    *flags++ = 0;
+
+  if (strlen (string) > 3 && digitp (string+3))
+    {
+      if (!ascii_memcasecmp (string, "rsa", 3))
+        algo = PUBKEY_ALGO_RSA;
+      else if (!ascii_memcasecmp (string, "dsa", 3))
+        algo = PUBKEY_ALGO_DSA;
+      else if (!ascii_memcasecmp (string, "elg", 3))
+        algo = PUBKEY_ALGO_ELGAMAL_E;
+    }
+  if (algo)
+    {
+      size = strtoul (string+3, &endp, 10);
+      if (size < 512 || size > 16384 || *endp)
+        return gpg_error (GPG_ERR_INV_VALUE);
+    }
+  else if ((curve = openpgp_is_curve_supported (string, &algo, &size)))
+    {
+      if (!algo)
+        {
+          algo = PUBKEY_ALGO_ECDH; /* Default ECC algorithm.  */
+          ecdh_or_ecdsa = 1;       /* We may need to switch the algo.  */
+        }
+    }
+  else
+    return gpg_error (GPG_ERR_UNKNOWN_CURVE);
+
+  /* Parse the flags.  */
+  keyuse = 0;
+  if (flags)
+    {
+      char **tokens = NULL;
+
+      tokens = strtokenize (flags, ",");
+      if (!tokens)
+        return gpg_error_from_syserror ();
+
+      for (i=0; (s = tokens[i]); i++)
+        {
+          if (!*s)
+            ;
+          else if (!ascii_strcasecmp (s, "sign"))
+            keyuse |= PUBKEY_USAGE_SIG;
+          else if (!ascii_strcasecmp (s, "encrypt")
+                   || !ascii_strcasecmp (s, "encr"))
+            keyuse |= PUBKEY_USAGE_ENC;
+          else if (!ascii_strcasecmp (s, "auth"))
+            keyuse |= PUBKEY_USAGE_AUTH;
+          else if (!ascii_strcasecmp (s, "cert"))
+            keyuse |= PUBKEY_USAGE_CERT;
+          else if (!ascii_strcasecmp (s, "ecdsa"))
+            {
+              if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
+                algo = PUBKEY_ALGO_ECDSA;
+              else
+                {
+                  xfree (tokens);
+                  return gpg_error (GPG_ERR_INV_FLAG);
+                }
+              ecdh_or_ecdsa = 0;
+            }
+          else if (!ascii_strcasecmp (s, "ecdh"))
+            {
+              if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
+                algo = PUBKEY_ALGO_ECDH;
+              else
+                {
+                  xfree (tokens);
+                  return gpg_error (GPG_ERR_INV_FLAG);
+                }
+              ecdh_or_ecdsa = 0;
+            }
+          else if (!ascii_strcasecmp (s, "eddsa"))
+            {
+              /* Not required but we allow it for consistency.  */
+              if (algo == PUBKEY_ALGO_EDDSA)
+                ;
+              else
+                {
+                  xfree (tokens);
+                  return gpg_error (GPG_ERR_INV_FLAG);
+                }
+            }
+          else
+            {
+              xfree (tokens);
+              return gpg_error (GPG_ERR_UNKNOWN_FLAG);
+            }
+        }
+
+      xfree (tokens);
+    }
+
+  /* If not yet decided switch between ecdh and ecdsa.  */
+  if (ecdh_or_ecdsa && keyuse)
+    algo = (keyuse & PUBKEY_USAGE_ENC)? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA;
+  else if (ecdh_or_ecdsa)
+    algo = for_subkey? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA;
+
+  /* Set or fix key usage.  */
+  if (!keyuse)
+    {
+      if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA
+          || algo == PUBKEY_ALGO_DSA)
+        keyuse = PUBKEY_USAGE_SIG;
+      else if (algo == PUBKEY_ALGO_RSA)
+        keyuse = for_subkey? PUBKEY_USAGE_ENC : PUBKEY_USAGE_SIG;
+      else
+        keyuse = PUBKEY_USAGE_ENC;
+    }
+  else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA
+           || algo == PUBKEY_ALGO_DSA)
+    {
+      keyuse &= ~PUBKEY_USAGE_ENC; /* Forbid encryption.  */
+    }
+  else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ELGAMAL_E)
+    {
+      keyuse = PUBKEY_USAGE_ENC;   /* Allow only encryption.  */
+    }
+
+  /* Make sure a primary key can certify.  */
+  if (!for_subkey)
+    keyuse |= PUBKEY_USAGE_CERT;
+
+  /* Check that usage is actually possible.  */
+  if (/**/((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH|PUBKEY_USAGE_CERT))
+           && !pubkey_get_nsig (algo))
+       || ((keyuse & PUBKEY_USAGE_ENC)
+           && !pubkey_get_nenc (algo))
+       || (for_subkey && (keyuse & PUBKEY_USAGE_CERT)))
+    return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+
+  /* Return values.  */
+  if (r_algo)
+    *r_algo = algo;
+  if (r_size)
+    {
+      unsigned int min, def, max;
+
+      /* Make sure the keysize is in the allowed range.  */
+      def = get_keysize_range (algo, &min, &max);
+      if (!size)
+        size = def;
+      else if (size < min)
+        size = min;
+      else if (size > max)
+        size = max;
+
+      *r_size = fixup_keysize (size, algo, 1);
+    }
+  if (r_keyuse)
+    *r_keyuse = keyuse;
+  if (r_curve)
+    *r_curve = curve;
+
+  return 0;
+}
+
+/* Parse and return the standard key generation parameter.
+ * The string is expected to be in this format:
+ *
+ *   ALGO[/FLAGS][+SUBALGO[/FLAGS]]
+ *
+ * Here ALGO is a string in the same format as printed by the
+ * keylisting.  For example:
+ *
+ *   rsa3072 := RSA with 3072 bit.
+ *   dsa2048 := DSA with 2048 bit.
+ *   elg2048 := Elgamal with 2048 bit.
+ *   ed25519 := EDDSA using curve Ed25519.
+ *   cv25519 := ECDH using curve Curve25519.
+ *   nistp256:= ECDSA or ECDH using curve NIST P-256
+ *
+ * All strings with an unknown prefix are considered an elliptic
+ * curve.  Curves which have no implicit algorithm require that FLAGS
+ * is given to select whether ECDSA or ECDH is used; this can eoither
+ * be done using an algorithm keyword or usage keywords.
+ *
+ * FLAGS is a comma delimited string of keywords:
+ *
+ *   cert := Allow usage Certify
+ *   sign := Allow usage Sign
+ *   encr := Allow usage Encrypt
+ *   auth := Allow usage Authentication
+ *   encrypt := Alias for "encr"
+ *   ecdsa := Use algorithm ECDSA.
+ *   eddsa := Use algorithm EdDSA.
+ *   ecdh  := Use algorithm ECDH.
+ *
+ * There are several defaults and fallbacks depending on the
+ * algorithm.  PART can be used to select which part of STRING is
+ * used:
+ *   -1 := Both parts
+ *    0 := Only the part of the primary key
+ *    1 := Only the part of the secondary key is parsed but returned
+ *         in the args for the primary key (R_ALGO,....)
+ *
+ */
+gpg_error_t
+parse_key_parameter_string (const char *string, int part,
+                            int *r_algo, unsigned int *r_size,
+                            unsigned *r_keyuse,
+                            char const **r_curve,
+                            int *r_subalgo, unsigned int *r_subsize,
+                            unsigned *r_subkeyuse,
+                            char const **r_subcurve)
+{
+  gpg_error_t err = 0;
+  char *primary, *secondary;
+
+  if (r_algo)
+    *r_algo = 0;
+  if (r_size)
+    *r_size = 0;
+  if (r_keyuse)
+    *r_keyuse = 0;
+  if (r_curve)
+    *r_curve = NULL;
+  if (r_subalgo)
+    *r_subalgo = 0;
+  if (r_subsize)
+    *r_subsize = 0;
+  if (r_subkeyuse)
+    *r_subkeyuse = 0;
+  if (r_subcurve)
+    *r_subcurve = NULL;
+
+  if (!string || !*string
+      || !strcmp (string, "default") || !strcmp (string, "-"))
+    string = opt.def_new_key_algo? opt.def_new_key_algo : DEFAULT_STD_KEY_PARAM;
+  else if (!strcmp (string, "future-default"))
+    string = FUTURE_STD_KEY_PARAM;
+
+  primary = xstrdup (string);
+  secondary = strchr (primary, '+');
+  if (secondary)
+    *secondary++ = 0;
+  if (part == -1 || part == 0)
+    {
+      err = parse_key_parameter_part (primary, 0, r_algo, r_size,
+                                      r_keyuse, r_curve);
+      if (!err && part == -1)
+        err = parse_key_parameter_part (secondary, 1, r_subalgo, r_subsize,
+                                        r_subkeyuse, r_subcurve);
+    }
+  else if (part == 1)
+    {
+      err = parse_key_parameter_part (secondary, 1, r_algo, r_size,
+                                      r_keyuse, r_curve);
+    }
+
+  xfree (primary);
+
+  return err;
+}
+
+
+
 /* Append R to the linked list PARA.  */
 static void
 append_to_parameter (struct para_data_s *para, struct para_data_s *r)
@@ -2926,8 +3212,15 @@ get_parameter_algo( struct para_data_s *para, enum para_name key,
   if (!ascii_strcasecmp (r->u.value, "default"))
     {
       /* Note: If you change this default algo, remember to change it
-         also in gpg.c:gpgconf_list.  */
-      i = DEFAULT_STD_ALGO;
+       * also in gpg.c:gpgconf_list.  */
+      /* FIXME: We only allow the algo here and have a separate thing
+       * for the curve etc.  That is a ugly but demanded for backward
+       * compatibility with the batch key generation.  It would be
+       * better to make full use of parse_key_parameter_string.  */
+      parse_key_parameter_string (NULL, 0,
+                                  &i, NULL, NULL, NULL,
+                                  NULL, NULL, NULL, NULL);
+
       if (r_default)
         *r_default = 1;
     }
@@ -2952,8 +3245,8 @@ get_parameter_algo( struct para_data_s *para, enum para_name key,
 
 
 /* Parse a usage string.  The usage keywords "auth", "sign", "encr"
- * may be elimited by space, tab, or comma.  On error -1 is returned
- * instead of the usage flags/  */
+ * may be delimited by space, tab, or comma.  On error -1 is returned
+ * instead of the usage flags.  */
 static int
 parse_usagestr (const char *usagestr)
 {
@@ -3639,25 +3932,27 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
       && (!*usagestr || !strcmp (usagestr, "default")
           || !strcmp (usagestr, "-")))
     {
-      if (!strcmp (algostr, "future-default"))
-        {
-          para = quickgen_set_para (para, 0,
-                                    FUTURE_STD_ALGO, FUTURE_STD_KEYSIZE,
-                                    FUTURE_STD_CURVE, 0);
-          para = quickgen_set_para (para, 1,
-                                    FUTURE_STD_SUBALGO,  FUTURE_STD_SUBKEYSIZE,
-                                    FUTURE_STD_SUBCURVE, 0);
-        }
-      else
+      /* Use default key parameters.  */
+      int algo, subalgo;
+      unsigned int size, subsize;
+      unsigned int keyuse, subkeyuse;
+      const char *curve, *subcurve;
+
+      err = parse_key_parameter_string (algostr, -1,
+                                        &algo, &size, &keyuse, &curve,
+                                        &subalgo, &subsize, &subkeyuse,
+                                        &subcurve);
+      if (err)
         {
-          para = quickgen_set_para (para, 0,
-                                    DEFAULT_STD_ALGO, DEFAULT_STD_KEYSIZE,
-                                    DEFAULT_STD_CURVE, 0);
-          para = quickgen_set_para (para, 1,
-                                    DEFAULT_STD_SUBALGO, DEFAULT_STD_SUBKEYSIZE,
-                                    DEFAULT_STD_SUBCURVE, 0);
+          log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
+          goto leave;
         }
 
+      para = quickgen_set_para (para, 0, algo, size, curve, keyuse);
+      if (subalgo)
+        para = quickgen_set_para (para, 1,
+                                  subalgo, subsize, subcurve, subkeyuse);
+
       if (*expirestr)
         {
           u32 expire;
@@ -3736,6 +4031,7 @@ void
 generate_keypair (ctrl_t ctrl, int full, const char *fname,
                   const char *card_serialno, int card_backup_key)
 {
+  gpg_error_t err;
   unsigned int nbits;
   char *uid = NULL;
   int algo;
@@ -3768,14 +4064,14 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
   if (card_serialno)
     {
 #ifdef ENABLE_CARD_SUPPORT
-      gpg_error_t err;
       struct agent_card_info_s info;
 
       memset (&info, 0, sizeof (info));
       err = agent_scd_getattr ("KEY-ATTR", &info);
       if (err)
         {
-          log_error (_("error getting current key info: %s\n"), gpg_strerror (err));
+          log_error (_("error getting current key info: %s\n"),
+                     gpg_strerror (err));
           return;
         }
 
@@ -3978,6 +4274,11 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
     }
   else /* Default key generation.  */
     {
+      int subalgo;
+      unsigned int size, subsize;
+      unsigned int keyuse, subkeyuse;
+      const char *curve, *subcurve;
+
       tty_printf ( _("Note: Use \"%s %s\""
                      " for a full featured key generation dialog.\n"),
 #if USE_GPG2_HACK
@@ -3986,12 +4287,22 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
                    GPG_NAME
 #endif
                    , "--full-gen-key" );
-      para = quickgen_set_para (para, 0,
-                                DEFAULT_STD_ALGO, DEFAULT_STD_KEYSIZE,
-                                DEFAULT_STD_CURVE, 0);
-      para = quickgen_set_para (para, 1,
-                                DEFAULT_STD_SUBALGO, DEFAULT_STD_SUBKEYSIZE,
-                                DEFAULT_STD_SUBCURVE, 0);
+
+      err = parse_key_parameter_string (NULL, -1,
+                                        &algo, &size, &keyuse, &curve,
+                                        &subalgo, &subsize,
+                                        &subkeyuse, &subcurve);
+      if (err)
+        {
+          log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
+          return;
+        }
+      para = quickgen_set_para (para, 0, algo, size, curve, keyuse);
+      if (subalgo)
+        para = quickgen_set_para (para, 1,
+                                  subalgo, subsize, subcurve, subkeyuse);
+
+
     }
 
 
@@ -4479,87 +4790,38 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
                          int *r_algo, unsigned int *r_usage, u32 *r_expire,
                          unsigned int *r_nbits, char **r_curve)
 {
+  gpg_error_t err;
   int algo;
   unsigned int use, nbits;
   u32 expire;
   int wantuse;
-  unsigned int min, def, max;
   const char *curve = NULL;
-  int eccalgo = 0;
 
   *r_curve = NULL;
 
   nbits = 0;
+
   /* Parse the algo string.  */
-  if (!algostr || !*algostr
-      || !strcmp (algostr, "default") || !strcmp (algostr, "-"))
-    {
-      algo  = for_subkey? DEFAULT_STD_SUBALGO    : DEFAULT_STD_ALGO;
-      use   = for_subkey? DEFAULT_STD_SUBKEYUSE  : DEFAULT_STD_KEYUSE;
-      nbits = for_subkey? DEFAULT_STD_SUBKEYSIZE : DEFAULT_STD_KEYSIZE;
-      curve = for_subkey? DEFAULT_STD_SUBCURVE   : DEFAULT_STD_CURVE;
-    }
-  else if (!strcmp (algostr, "future-default"))
-    {
-      algo  = for_subkey? FUTURE_STD_SUBALGO    : FUTURE_STD_ALGO;
-      use   = for_subkey? FUTURE_STD_SUBKEYUSE  : FUTURE_STD_KEYUSE;
-      nbits = for_subkey? FUTURE_STD_SUBKEYSIZE : FUTURE_STD_KEYSIZE;
-      curve = for_subkey? FUTURE_STD_SUBCURVE   : FUTURE_STD_CURVE;
-    }
-  else if (*algostr == '&' && strlen (algostr) == 41)
+  if (algostr && *algostr == '&' && strlen (algostr) == 41)
     {
       /* Take algo from existing key.  */
       algo = check_keygrip (ctrl, algostr+1);
       /* FIXME: We need the curve name as well.  */
       return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
     }
-  else if (!strncmp (algostr, "rsa", 3))
-    {
-      algo = PUBKEY_ALGO_RSA;
-      use = for_subkey? DEFAULT_STD_SUBKEYUSE : DEFAULT_STD_KEYUSE;
-      if (algostr[3])
-        nbits = atoi (algostr + 3);
-    }
-  else if (!strncmp (algostr, "elg", 3))
-    {
-      algo = PUBKEY_ALGO_ELGAMAL_E;
-      use = PUBKEY_USAGE_ENC;
-      if (algostr[3])
-        nbits = atoi (algostr + 3);
-    }
-  else if (!strncmp (algostr, "dsa", 3))
-    {
-      algo = PUBKEY_ALGO_DSA;
-      use = PUBKEY_USAGE_SIG;
-      if (algostr[3])
-        nbits = atoi (algostr + 3);
-    }
-  else if ((curve = openpgp_is_curve_supported (algostr, &algo)))
-    {
-      if (!algo)
-        {
-          algo = PUBKEY_ALGO_ECDH; /* Default ECC algorithm.  */
-          eccalgo = 1;  /* Remember - we may need to fix it up.  */
-        }
 
-      if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA)
-        use = PUBKEY_USAGE_SIG;
-      else
-        use = PUBKEY_USAGE_ENC;
-    }
-  else
-    return gpg_error (GPG_ERR_UNKNOWN_CURVE);
+  err = parse_key_parameter_string (algostr, for_subkey? 1 : 0,
+                                    &algo, &nbits, &use, &curve,
+                                    NULL, NULL, NULL, NULL);
+  if (err)
+    return err;
 
   /* Parse the usage string.  */
   if (!usagestr || !*usagestr
       || !strcmp (usagestr, "default") || !strcmp (usagestr, "-"))
-    ; /* Keep default usage */
+    ; /* Keep usage from parse_key_parameter_string.  */
   else if ((wantuse = parse_usagestr (usagestr)) != -1)
-    {
-      use = wantuse;
-      if (eccalgo && !(use & PUBKEY_USAGE_ENC))
-        algo = PUBKEY_ALGO_ECDSA; /* Switch from ECDH to ECDSA.  */
-    }
+    use = wantuse;
   else
     return gpg_error (GPG_ERR_INV_VALUE);
 
@@ -4567,7 +4829,9 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
   if (!for_subkey)
     use |= PUBKEY_USAGE_CERT;
 
-  /* Check that usage is possible.  */
+  /* Check that usage is possible.  NB: We have the same check in
+   * parse_key_parameter_string but need it here again in case the
+   * separate usage value has been given. */
   if (/**/((use & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH|PUBKEY_USAGE_CERT))
            && !pubkey_get_nsig (algo))
        || ((use & PUBKEY_USAGE_ENC)
@@ -4580,17 +4844,6 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
   if (expire == (u32)-1 )
     return gpg_error (GPG_ERR_INV_VALUE);
 
-  /* Make sure the keysize is in the allowed range.  */
-  get_keysize_range (algo, &min, &def, &max);
-  if (!nbits)
-    nbits = def;
-  else if (nbits < min)
-    nbits = min;
-  else if (nbits > max)
-    nbits = max;
-
-  nbits = fixup_keysize (nbits, algo, 1);
-
   if (curve)
     {
       *r_curve = xtrystrdup (curve);
index 8ed2cdb..2449042 100644 (file)
@@ -120,6 +120,8 @@ struct
   const char *agent_program;
   const char *dirmngr_program;
 
+  const char *def_new_key_algo;
+
   /* Options to be passed to the gpg-agent */
   session_env_t session_env;
   char *lc_ctype;
index 8de9b80..5fa4fd2 100644 (file)
@@ -3454,7 +3454,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
 
           memcpy (curve_name, tok, toklen);
           curve_name[toklen] = 0;
-          curve = openpgp_is_curve_supported (curve_name, NULL);
+          curve = openpgp_is_curve_supported (curve_name, NULL, NULL);
           xfree (curve_name);
         }
       else if (tok && toklen == 5 && !memcmp (tok, "flags", 5))