[git] GnuPG - branch, master, updated. gnupg-2.1.12-44-g8f2a053

by Werner Koch cvs at cvs.gnupg.org
Thu Jun 2 16:03:31 CEST 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  8f2a053a0ffa0430d01a53b4d491a3f0fff683eb (commit)
       via  d837f6b0eadb14ea08c1c6030b4d6adaaee8778e (commit)
       via  072acb69be55e366e2da921e3953404765fa3928 (commit)
       via  c9f9fabdcc1022a5366e1c841acde55fb07105cb (commit)
      from  db1ecc8212defdd183abbb6b1407fcc8d2dc9552 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 8f2a053a0ffa0430d01a53b4d491a3f0fff683eb
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Jun 2 15:54:48 2016 +0200

    gpg: New command --quick-addkey.
    
    * g10/keygen.c (DEFAULT_STD_SUBKEYUSE): New.
    (ask_keysize): Factor code out to ...
    (get_keysize_range, fixup_keysize): new.
    (parse_parameter_usage): Factor parsing out to  ...
    (parse_usagestr): new.  Allow use of "encr" as alias for "encrypt".
    (parse_subkey_algostr_usagestr): New.
    (generate_subkeypair): Add new args.  Implement unattended mode.
    
    * g10/keyedit.c (keyedit_quick_sign): Factor some code out to ...
    (find_by_primary_fpr): new.
    (keyedit_quick_addkey): New.
    * g10/gpg.c (aQuickAddKey): New.
    (opts): Add --quick-addkey.
    (main): Implement.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/doc/gpg.texi b/doc/gpg.texi
index a09e610..9b0f1ba 100644
--- a/doc/gpg.texi
+++ b/doc/gpg.texi
@@ -620,6 +620,35 @@ supplied passphrase is used for the new key and the agent does not ask
 for it.  To create a key without any protection @code{--passphrase ''}
 may be used.
 
+ at item --quick-addkey @code{fpr} [@code{algo} [@code{usage} [@code{expire}]]]
+ at opindex quick-addkey
+Directly add a subkey to the key identified by the fingerprint
+ at code{fpr}.  Without the optional arguments an encryption subkey is
+added.  If any of the arguments are given a more specific subkey is
+added.
+
+ at code{algo} may be any of the supported algorithms or curve names given
+in the format as used by key listings.  To use the default algorithm
+the string ``default'' or ``-'' can be used. Supported algorithms are
+``rsa'', ``dsa'', ``elg'', ``ed25519'', ``cv25519'', and other ECC
+curves.  For example the string ``rsa'' adds an RSA key with the
+default key length; a string ``rsa4096'' requests that the key length
+is 4096 bits.
+
+Depending on the given @code{algo} the subkey may either be an
+encryption subkey or a signing subkey.  If an algorithm is capable of
+signing and encryption and such a subkey is desired, a @code{usage}
+string must be given.  This string is either ``default'' or ``-'' to
+keep the default or a comma delimited list of keywords: ``sign'' for a
+signing subkey, ``auth'' for an authentication subkey, and ``encr''
+for an encryption subkey (``encrypt'' can be used as alias for
+``encr'').  The valid combinations depend on the algorithm.
+
+The @code{expire} argument can be used to specify an expiration date
+for the subkey.  Several formats are supported; commonly the ISO
+YYYY-MM-DD format is used.  The values ``never'', ``none'', or ``-''
+can be used for no expiration date.
+
 @item --gen-key
 @opindex gen-key
 Generate a new key pair using the current default parameters.  This is
@@ -636,6 +665,7 @@ There is also a feature which allows you to create keys in batch
 mode. See the manual section ``Unattended key generation'' on how
 to use this.
 
+
 @item --gen-revoke @code{name}
 @opindex gen-revoke
 Generate a revocation certificate for the complete key.  To only revoke
diff --git a/g10/gpg.c b/g10/gpg.c
index a88499a..2795330 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -117,6 +117,7 @@ enum cmd_and_opt_values
     aQuickSignKey,
     aQuickLSignKey,
     aQuickAddUid,
+    aQuickAddKey,
     aListConfig,
     aListGcryptConfig,
     aGPGConfList,
@@ -426,6 +427,7 @@ static ARGPARSE_OPTS opts[] = {
               N_("quickly generate a new key pair")),
   ARGPARSE_c (aQuickAddUid,  "quick-adduid",
               N_("quickly add a new user-id")),
+  ARGPARSE_c (aQuickAddKey,  "quick-addkey", "@"),
   ARGPARSE_c (aFullKeygen,  "full-gen-key" ,
               N_("full featured key pair generation")),
   ARGPARSE_c (aGenRevoke, "gen-revoke",N_("generate a revocation certificate")),
@@ -2433,6 +2435,7 @@ main (int argc, char **argv)
 	  case aStore:
 	  case aQuickKeygen:
 	  case aQuickAddUid:
+	  case aQuickAddKey:
 	  case aExportOwnerTrust:
 	  case aImportOwnerTrust:
           case aRebuildKeydbCaches:
@@ -3775,6 +3778,7 @@ main (int argc, char **argv)
       case aDeleteSecretAndPublicKeys:
       case aQuickKeygen:
       case aQuickAddUid:
+      case aQuickAddKey:
       case aFullKeygen:
       case aKeygen:
       case aImport:
@@ -4148,6 +4152,30 @@ main (int argc, char **argv)
         }
 	break;
 
+      case aQuickAddKey:
+        {
+          const char *x_fpr, *x_algo, *x_usage, *x_expire;
+
+          if (argc < 1 || argc > 4)
+            wrong_args ("--quick-addkey FINGERPRINT [ALGO [USAGE [EXPIRE]]]");
+          x_fpr = *argv++; argc--;
+          x_algo = "";
+          x_usage = "";
+          x_expire = "";
+          if (argc)
+            {
+              x_algo = *argv++; argc--;
+              if (argc)
+                {
+                  x_usage = *argv++; argc--;
+                  if (argc)
+                    x_expire = *argv++; argc--;
+                }
+            }
+          keyedit_quick_addkey (ctrl, x_fpr, x_algo, x_usage, x_expire);
+        }
+	break;
+
       case aFastImport:
         opt.import_options |= IMPORT_FAST;
       case aImport:
diff --git a/g10/keyedit.c b/g10/keyedit.c
index c78f8a3..16dbf62 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -1,6 +1,6 @@
 /* keyedit.c - Edit properties of a key
  * Copyright (C) 1998-2010 Free Software Foundation, Inc.
- * Copyright (C) 1998-2015 Werner Koch
+ * Copyright (C) 1998-2016 Werner Koch
  * Copyright (C) 2015, 2016 g10 Code GmbH
  *
  * This file is part of GnuPG.
@@ -2349,7 +2349,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
 	  break;
 
 	case cmdADDKEY:
-	  if (!generate_subkeypair (ctrl, keyblock))
+	  if (!generate_subkeypair (ctrl, keyblock, NULL, NULL, NULL))
 	    {
 	      redisplay = 1;
 	      modified = 1;
@@ -2935,6 +2935,75 @@ keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
 }
 
 
+/* Find a keyblock by fingerprint because only this uniquely
+ * identifies a key and may thus be used to select a key for
+ * unattended subkey creation os key signing.  */
+static gpg_error_t
+find_by_primary_fpr (ctrl_t ctrl, const char *fpr,
+                     kbnode_t *r_keyblock, KEYDB_HANDLE *r_kdbhd)
+{
+  gpg_error_t err;
+  kbnode_t keyblock = NULL;
+  KEYDB_HANDLE kdbhd = NULL;
+  KEYDB_SEARCH_DESC desc;
+  byte fprbin[MAX_FINGERPRINT_LEN];
+  size_t fprlen;
+
+  *r_keyblock = NULL;
+  *r_kdbhd = NULL;
+
+  if (classify_user_id (fpr, &desc, 1)
+      || !(desc.mode == KEYDB_SEARCH_MODE_FPR
+           || desc.mode == KEYDB_SEARCH_MODE_FPR16
+           || desc.mode == KEYDB_SEARCH_MODE_FPR20))
+    {
+      log_error (_("\"%s\" is not a fingerprint\n"), fpr);
+      err = gpg_error (GPG_ERR_INV_NAME);
+      goto leave;
+    }
+  err = get_pubkey_byname (ctrl, NULL, NULL, fpr, &keyblock, &kdbhd, 1, 1);
+  if (err)
+    {
+      log_error (_("key \"%s\" not found: %s\n"), fpr, gpg_strerror (err));
+      goto leave;
+    }
+
+  /* Check that the primary fingerprint has been given. */
+  fingerprint_from_pk (keyblock->pkt->pkt.public_key, fprbin, &fprlen);
+  if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR16
+      && !memcmp (fprbin, desc.u.fpr, 16))
+    ;
+  else if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR
+           && !memcmp (fprbin, desc.u.fpr, 16)
+           && !desc.u.fpr[16]
+           && !desc.u.fpr[17]
+           && !desc.u.fpr[18]
+           && !desc.u.fpr[19])
+    ;
+  else if (fprlen == 20 && (desc.mode == KEYDB_SEARCH_MODE_FPR20
+                            || desc.mode == KEYDB_SEARCH_MODE_FPR)
+           && !memcmp (fprbin, desc.u.fpr, 20))
+    ;
+  else
+    {
+      log_error (_("\"%s\" is not the primary fingerprint\n"), fpr);
+      err = gpg_error (GPG_ERR_INV_NAME);
+      goto leave;
+    }
+
+  *r_keyblock = keyblock;
+  keyblock = NULL;
+  *r_kdbhd = kdbhd;
+  kdbhd = NULL;
+  err = 0;
+
+ leave:
+  release_kbnode (keyblock);
+  keydb_release (kdbhd);
+  return err;
+}
+
+
 /* Unattended key signing function.  If the key specifified by FPR is
    available and FPR is the primary fingerprint all user ids of the
    key are signed using the default signing key.  If UIDS is an empty
@@ -2949,7 +3018,6 @@ keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
   kbnode_t keyblock = NULL;
   KEYDB_HANDLE kdbhd = NULL;
   int modified = 0;
-  KEYDB_SEARCH_DESC desc;
   PKT_public_key *pk;
   kbnode_t node;
   strlist_t sl;
@@ -2963,47 +3031,8 @@ keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
   /* We require a fingerprint because only this uniquely identifies a
      key and may thus be used to select a key for unattended key
      signing.  */
-  if (classify_user_id (fpr, &desc, 1)
-      || !(desc.mode == KEYDB_SEARCH_MODE_FPR
-           || desc.mode == KEYDB_SEARCH_MODE_FPR16
-           || desc.mode == KEYDB_SEARCH_MODE_FPR20))
-    {
-      log_error (_("\"%s\" is not a fingerprint\n"), fpr);
-      goto leave;
-    }
-  err = get_pubkey_byname (ctrl, NULL, NULL, fpr, &keyblock, &kdbhd, 1, 1);
-  if (err)
-    {
-      log_error (_("key \"%s\" not found: %s\n"), fpr, gpg_strerror (err));
-      goto leave;
-    }
-
-  /* Check that the primary fingerprint has been given. */
-  {
-    byte fprbin[MAX_FINGERPRINT_LEN];
-    size_t fprlen;
-
-    fingerprint_from_pk (keyblock->pkt->pkt.public_key, fprbin, &fprlen);
-    if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR16
-        && !memcmp (fprbin, desc.u.fpr, 16))
-      ;
-    else if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR
-             && !memcmp (fprbin, desc.u.fpr, 16)
-             && !desc.u.fpr[16]
-             && !desc.u.fpr[17]
-             && !desc.u.fpr[18]
-             && !desc.u.fpr[19])
-      ;
-    else if (fprlen == 20 && (desc.mode == KEYDB_SEARCH_MODE_FPR20
-                              || desc.mode == KEYDB_SEARCH_MODE_FPR)
-             && !memcmp (fprbin, desc.u.fpr, 20))
-      ;
-    else
-      {
-        log_error (_("\"%s\" is not the primary fingerprint\n"), fpr);
-        goto leave;
-      }
-  }
+  if (find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd))
+    goto leave;
 
   if (fix_keyblock (&keyblock))
     modified++;
@@ -3129,6 +3158,67 @@ keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
 }
 
 
+/* Unattended subkey creation function.
+ *
+ */
+void
+keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
+                      const char *usagestr, const char *expirestr)
+{
+  gpg_error_t err;
+  kbnode_t keyblock;
+  KEYDB_HANDLE kdbhd;
+  int modified = 0;
+  PKT_public_key *pk;
+
+#ifdef HAVE_W32_SYSTEM
+  /* See keyedit_menu for why we need this.  */
+  check_trustdb_stale (ctrl);
+#endif
+
+  /* We require a fingerprint because only this uniquely identifies a
+   * key and may thus be used to select a key for unattended subkey
+   * creation.  */
+  if (find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd))
+    goto leave;
+
+  if (fix_keyblock (&keyblock))
+    modified++;
+
+  pk = keyblock->pkt->pkt.public_key;
+  if (pk->flags.revoked)
+    {
+      if (!opt.verbose)
+        show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1);
+      log_error ("%s%s", _("Key is revoked."), "\n");
+      goto leave;
+    }
+
+  /* Create the subkey.  Noet that the called function already prints
+   * an error message. */
+  if (!generate_subkeypair (ctrl, keyblock, algostr, usagestr, expirestr))
+    modified = 1;
+  es_fflush (es_stdout);
+
+  /* Store.  */
+  if (modified)
+    {
+      err = keydb_update_keyblock (kdbhd, keyblock);
+      if (err)
+        {
+          log_error (_("update failed: %s\n"), gpg_strerror (err));
+          goto leave;
+        }
+    }
+  else
+    log_info (_("Key not changed so no update needed.\n"));
+
+ leave:
+  release_kbnode (keyblock);
+  keydb_release (kdbhd);
+}
+
+
 

 static void
 tty_print_notations (int indent, PKT_signature * sig)
diff --git a/g10/keygen.c b/g10/keygen.c
index f9cbf21..2ef80a7 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -1,6 +1,6 @@
 /* keygen.c - Generate a key pair
  * Copyright (C) 1998-2007, 2009-2011  Free Software Foundation, Inc.
- * Copyright (C) 2014, 2015  Werner Koch
+ * Copyright (C) 2014, 2015, 2016  Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -54,6 +54,7 @@
 #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
 
 /* Flag bits used during key generation.  */
@@ -2017,88 +2018,47 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
 }
 
 
-/* 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 unsigned
-ask_keysize (int algo, unsigned int primary_keysize)
+static void
+get_keysize_range (int algo,
+                   unsigned int *min, unsigned int *def, unsigned int *max)
 {
-  unsigned int nbits;
-  unsigned int min = 1024;
-  unsigned int def = DEFAULT_STD_KEYSIZE;
-  unsigned int max = 4096;
-  int for_subkey = !!primary_keysize;
-  int autocomp = 0;
-
-  if (primary_keysize && !opt.expert)
-    {
-      /* Deduce the subkey size from the primary key size.  */
-      if (algo == PUBKEY_ALGO_DSA && primary_keysize > 3072)
-        nbits = 3072; /* For performance reasons we don't support more
-                         than 3072 bit DSA.  However we won't see this
-                         case anyway because DSA can't be used as an
-                         encryption subkey ;-). */
-      else
-        nbits = primary_keysize;
-      autocomp = 1;
-      goto leave;
-    }
+  *min = 1024;
+  *def = DEFAULT_STD_KEYSIZE;
+  *max = 4096;
 
   /* Deviations from the standard values.  */
   switch(algo)
     {
     case PUBKEY_ALGO_DSA:
-      min = opt.expert? 768 : 1024;
-      def=2048;
-      max=3072;
+      *min = opt.expert? 768 : 1024;
+      *def=2048;
+      *max=3072;
       break;
 
     case PUBKEY_ALGO_ECDSA:
     case PUBKEY_ALGO_ECDH:
-      min=256;
-      def=256;
-      max=521;
+      *min=256;
+      *def=256;
+      *max=521;
       break;
 
     case PUBKEY_ALGO_EDDSA:
-      min=255;
-      def=255;
-      max=441;
+      *min=255;
+      *def=255;
+      *max=441;
       break;
     }
+}
 
-  tty_printf(_("%s keys may be between %u and %u bits long.\n"),
-	     openpgp_pk_algo_name (algo), min, max);
-
-  for (;;)
-    {
-      char *prompt, *answer;
-
-      if (for_subkey)
-        prompt = xasprintf (_("What keysize do you want "
-                              "for the subkey? (%u) "), def);
-      else
-        prompt = xasprintf (_("What keysize do you want? (%u) "), def);
-      answer = cpr_get ("keygen.size", prompt);
-      cpr_kill_prompt ();
-      nbits = *answer? atoi (answer): def;
-      xfree(prompt);
-      xfree(answer);
-
-      if(nbits<min || nbits>max)
-	tty_printf(_("%s keysizes must be in the range %u-%u\n"),
-		   openpgp_pk_algo_name (algo), min, max);
-      else
-	break;
-    }
-
-  tty_printf (_("Requested keysize is %u bits\n"), nbits);
 
- leave:
+/* Return a fixed up keysize depending on ALGO.  */
+static unsigned int
+fixup_keysize (unsigned int nbits, int algo, int silent)
+{
   if (algo == PUBKEY_ALGO_DSA && (nbits % 64))
     {
       nbits = ((nbits + 63) / 64) * 64;
-      if (!autocomp)
+      if (!silent)
         tty_printf (_("rounded up to %u bits\n"), nbits);
     }
   else if (algo == PUBKEY_ALGO_EDDSA)
@@ -2109,7 +2069,7 @@ ask_keysize (int algo, unsigned int primary_keysize)
             nbits = 255;
           else
             nbits = 441;
-          if (!autocomp)
+          if (!silent)
             tty_printf (_("rounded to %u bits\n"), nbits);
         }
     }
@@ -2123,14 +2083,14 @@ ask_keysize (int algo, unsigned int primary_keysize)
             nbits = 384;
           else
             nbits = 521;
-          if (!autocomp)
+          if (!silent)
             tty_printf (_("rounded to %u bits\n"), nbits);
         }
     }
   else if ((nbits % 32))
     {
       nbits = ((nbits + 31) / 32) * 32;
-      if (!autocomp)
+      if (!silent)
         tty_printf (_("rounded up to %u bits\n"), nbits );
     }
 
@@ -2138,6 +2098,66 @@ 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 unsigned
+ask_keysize (int algo, unsigned int primary_keysize)
+{
+  unsigned int nbits;
+  unsigned int min, def, max;
+  int for_subkey = !!primary_keysize;
+  int autocomp = 0;
+
+  get_keysize_range (algo, &min, &def, &max);
+
+  if (primary_keysize && !opt.expert)
+    {
+      /* Deduce the subkey size from the primary key size.  */
+      if (algo == PUBKEY_ALGO_DSA && primary_keysize > 3072)
+        nbits = 3072; /* For performance reasons we don't support more
+                         than 3072 bit DSA.  However we won't see this
+                         case anyway because DSA can't be used as an
+                         encryption subkey ;-). */
+      else
+        nbits = primary_keysize;
+      autocomp = 1;
+      goto leave;
+    }
+
+  tty_printf(_("%s keys may be between %u and %u bits long.\n"),
+	     openpgp_pk_algo_name (algo), min, max);
+
+  for (;;)
+    {
+      char *prompt, *answer;
+
+      if (for_subkey)
+        prompt = xasprintf (_("What keysize do you want "
+                              "for the subkey? (%u) "), def);
+      else
+        prompt = xasprintf (_("What keysize do you want? (%u) "), def);
+      answer = cpr_get ("keygen.size", prompt);
+      cpr_kill_prompt ();
+      nbits = *answer? atoi (answer): def;
+      xfree(prompt);
+      xfree(answer);
+
+      if(nbits<min || nbits>max)
+	tty_printf(_("%s keysizes must be in the range %u-%u\n"),
+		   openpgp_pk_algo_name (algo), min, max);
+      else
+	break;
+    }
+
+  tty_printf (_("Requested keysize is %u bits\n"), nbits);
+
+ leave:
+  nbits = fixup_keysize (nbits, algo, autocomp);
+  return nbits;
+}
+
+
 /* Ask for the curve.  ALGO is the selected algorithm which this
    function may adjust.  Returns a malloced string with the name of
    the curve.  BOTH tells that gpg creates a primary and subkey. */
@@ -2885,6 +2905,50 @@ get_parameter_algo( struct para_data_s *para, enum para_name key,
   return i;
 }
 
+
+/* 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/  */
+static int
+parse_usagestr (const char *usagestr)
+{
+  gpg_error_t err;
+  char **tokens = NULL;
+  const char *s;
+  int i;
+  unsigned int use = 0;
+
+  tokens = strtokenize (usagestr, " \t,");
+  if (!tokens)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("strtokenize failed: %s\n", gpg_strerror (err));
+      return -1;
+    }
+
+  for (i=0; (s = tokens[i]); i++)
+    {
+      if (!*s)
+        ;
+      else if (!ascii_strcasecmp (s, "sign"))
+        use |= PUBKEY_USAGE_SIG;
+      else if (!ascii_strcasecmp (s, "encrypt")
+                || !ascii_strcasecmp (s, "encr"))
+        use |= PUBKEY_USAGE_ENC;
+      else if (!ascii_strcasecmp (s, "auth"))
+        use |= PUBKEY_USAGE_AUTH;
+      else
+        {
+          xfree (tokens);
+          return -1; /* error */
+        }
+    }
+
+  xfree (tokens);
+  return use;
+}
+
+
 /*
  * Parse the usage parameter and set the keyflags.  Returns -1 on
  * error, 0 for no usage given or 1 for usage available.
@@ -2893,33 +2957,24 @@ static int
 parse_parameter_usage (const char *fname,
                        struct para_data_s *para, enum para_name key)
 {
-    struct para_data_s *r = get_parameter( para, key );
-    char *p, *pn;
-    unsigned int use;
-
-    if( !r )
-	return 0; /* none (this is an optional parameter)*/
-
-    use = 0;
-    pn = r->u.value;
-    while ( (p = strsep (&pn, " \t,")) ) {
-        if ( !*p)
-            ;
-        else if ( !ascii_strcasecmp (p, "sign") )
-            use |= PUBKEY_USAGE_SIG;
-        else if ( !ascii_strcasecmp (p, "encrypt") )
-            use |= PUBKEY_USAGE_ENC;
-        else if ( !ascii_strcasecmp (p, "auth") )
-            use |= PUBKEY_USAGE_AUTH;
-        else {
-            log_error("%s:%d: invalid usage list\n", fname, r->lnr );
-            return -1; /* error */
-        }
+  struct para_data_s *r = get_parameter( para, key );
+  int i;
+
+  if (!r)
+    return 0; /* none (this is an optional parameter)*/
+
+  i = parse_usagestr (r->u.value);
+  if (i == -1)
+    {
+      log_error ("%s:%d: invalid usage list\n", fname, r->lnr );
+      return -1; /* error */
     }
-    r->u.usage = use;
-    return 1;
+
+  r->u.usage = i;
+  return 1;
 }
 
+
 static int
 parse_revocation_key (const char *fname,
 		      struct para_data_s *para, enum para_name key)
@@ -4260,12 +4315,119 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
 }
 
 
+gpg_error_t
+parse_subkey_algostr_usagestr (ctrl_t ctrl, const char *algostr,
+                               const char *usagestr,
+                               int *r_algo, unsigned int *r_usage,
+                               unsigned int *r_nbits, char **r_curve)
+{
+  int algo;
+  unsigned int use, nbits;
+  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 = DEFAULT_STD_SUBALGO;
+      use = DEFAULT_STD_SUBKEYUSE;
+    }
+  else if (*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 = DEFAULT_STD_SUBKEYUSE;
+      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_INV_CURVE);
+
+  /* Parse the usage string.  */
+  if (!usagestr || !*usagestr
+      || !strcmp (usagestr, "default") || !strcmp (usagestr, "-"))
+    ; /* Keep default usage */
+  else if ((wantuse = parse_usagestr (usagestr)) != -1)
+    {
+      use = wantuse;
+      if (eccalgo && !(use & PUBKEY_USAGE_ENC))
+        algo = PUBKEY_ALGO_ECDSA; /* Switch from ECDH to ECDSA.  */
+    }
+  else
+    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);
+      if (!*r_curve)
+        return gpg_error_from_syserror ();
+    }
+  *r_algo = algo;
+  *r_usage = use;
+  *r_nbits = nbits;
+  return 0;
+}
+
+
 /* Add a new subkey to an existing key.  Returns 0 if a new key has
-   been generated and put into the keyblocks.  */
+   been generated and put into the keyblocks.  If any of ALGOSTR,
+   USAGESTR, or EXPIRESTR is NULL interactive mode is used. */
 gpg_error_t
-generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
+generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
+                     const char *usagestr, const char *expirestr)
 {
   gpg_error_t err = 0;
+  int interactive;
   kbnode_t node;
   PKT_public_key *pri_psk = NULL;
   PKT_public_key *sub_psk = NULL;
@@ -4278,6 +4440,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
   char *hexgrip = NULL;
   char *serialno = NULL;
 
+  interactive = (!algostr || !usagestr || !expirestr);
+
   /* Break out the primary key.  */
   node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
   if (!node)
@@ -4317,32 +4481,72 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
     goto leave;
   if (agent_get_keyinfo (NULL, hexgrip, &serialno))
     {
-      tty_printf (_("Secret parts of primary key are not available.\n"));
+      if (interactive)
+        tty_printf (_("Secret parts of primary key are not available.\n"));
+      else
+        log_info (  _("Secret parts of primary key are not available.\n"));
+      err = gpg_error (GPG_ERR_NO_SECKEY);
       goto leave;
     }
   if (serialno)
-    tty_printf (_("Secret parts of primary key are stored on-card.\n"));
+    {
+      if (interactive)
+        tty_printf (_("Secret parts of primary key are stored on-card.\n"));
+      else
+        log_info (  _("Secret parts of primary key are stored on-card.\n"));
+    }
 
   xfree (hexgrip);
   hexgrip = NULL;
-  algo = ask_algo (ctrl, 1, NULL, &use, &hexgrip);
-  log_assert (algo);
-
-  if (hexgrip)
-    nbits = 0;
-  else if (algo == PUBKEY_ALGO_ECDSA
-           || algo == PUBKEY_ALGO_EDDSA
-           || algo == PUBKEY_ALGO_ECDH)
-    curve = ask_curve (&algo, NULL);
-  else
-    nbits = ask_keysize (algo, 0);
+  if (interactive)
+    {
+      algo = ask_algo (ctrl, 1, NULL, &use, &hexgrip);
+      log_assert (algo);
+
+      if (hexgrip)
+        nbits = 0;
+      else if (algo == PUBKEY_ALGO_ECDSA
+               || algo == PUBKEY_ALGO_EDDSA
+               || algo == PUBKEY_ALGO_ECDH)
+        curve = ask_curve (&algo, NULL);
+      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) ")))
+        {
+          err = gpg_error (GPG_ERR_CANCELED);
+          goto leave;
+        }
+    }
+  else /* Unattended mode.  */
     {
-      err = gpg_error (GPG_ERR_CANCELED);
-      goto leave;
+      err = parse_subkey_algostr_usagestr (ctrl, algostr, usagestr,
+                                           &algo, &use, &nbits, &curve);
+      if (err)
+        goto leave;
+
+      if (!expirestr || !*expirestr || !strcmp (expirestr, "none")
+          || !strcmp (expirestr, "never") || !strcmp (expirestr, "-"))
+        expire = 0;
+      else
+        expire = parse_expire_string (expirestr);
+      if (expire == (u32)-1 )
+	{
+          err = gpg_error (GPG_ERR_INV_VALUE);
+	  goto leave;
+	}
+
+      /* Check that usage is possible.  */
+      if ( ((use & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH|PUBKEY_USAGE_CERT))
+            && !pubkey_get_nsig (algo))
+           || ((use & PUBKEY_USAGE_ENC)
+               && !pubkey_get_nenc (algo)))
+        {
+          err = gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+          goto leave;
+        }
     }
 
   if (hexgrip)
diff --git a/g10/main.h b/g10/main.h
index 5b5947e..0ca4d39 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -287,6 +287,8 @@ void keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
 void keyedit_passwd (ctrl_t ctrl, const char *username);
 void keyedit_quick_adduid (ctrl_t ctrl, const char *username,
                            const char *newuid);
+void keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
+                           const char *usagestr, const char *expirestr);
 void keyedit_quick_sign (ctrl_t ctrl, const char *fpr,
                          strlist_t uids, strlist_t locusr, int local);
 void show_basic_key_info (KBNODE keyblock);
@@ -311,7 +313,10 @@ int keygen_add_revkey(PKT_signature *sig, void *opaque);
 gpg_error_t make_backsig (PKT_signature *sig, PKT_public_key *pk,
                           PKT_public_key *sub_pk, PKT_public_key *sub_psk,
                           u32 timestamp, const char *cache_nonce);
-gpg_error_t generate_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock);
+gpg_error_t generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock,
+                                 const char *algostr,
+                                 const char *usagestr,
+                                 const char *expirestr);
 #ifdef ENABLE_CARD_SUPPORT
 gpg_error_t generate_card_subkeypair (kbnode_t pub_keyblock,
                                       int keyno, const char *serialno);

commit d837f6b0eadb14ea08c1c6030b4d6adaaee8778e
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Jun 2 15:14:49 2016 +0200

    gpg: Do not abort on certain invalid packets.
    
    * g10/build-packet.c (write_fake_data): Check for non-opaque data.
    * g10/seskey.c (do_encode_md): Return NULL instead of abort.
    --
    
    The first may happen if the usage flags of an algorithm do not match
    the allowed usage.  When writing a backsig this would lead to a
    log_bug in libgcrypt due to the use of a regular MPI as opaque data.
    
    The second may happen with all kind of invalid data.  It is easy to
    avoid an abort, though.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/g10/build-packet.c b/g10/build-packet.c
index 1353a86..2745734 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -301,6 +301,8 @@ write_fake_data (IOBUF out, gcry_mpi_t a)
 
   if (!a)
     return 0;
+  if (!gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
+    return 0; /* e.g. due to generating a key with wrong usage.  */
   p = gcry_mpi_get_opaque ( a, &n);
   if (!p)
     return 0; /* For example due to a read error in
diff --git a/g10/seskey.c b/g10/seskey.c
index c41a145..e5385af 100644
--- a/g10/seskey.c
+++ b/g10/seskey.c
@@ -211,9 +211,12 @@ do_encode_md( gcry_md_hd_t md, int algo, size_t len, unsigned nbits,
     int i,n;
     gcry_mpi_t a;
 
-    if( len + asnlen + 4  > nframe )
-      log_bug ("can't encode a %d bit MD into a %d bits frame, algo=%d\n",
-               (int)(len*8), (int)nbits, algo);
+    if (len + asnlen + 4  > nframe)
+      {
+        log_error ("can't encode a %d bit MD into a %d bits frame, algo=%d\n",
+                   (int)(len*8), (int)nbits, algo);
+        return NULL;
+      }
 
     /* We encode the MD in this way:
      *

commit 072acb69be55e366e2da921e3953404765fa3928
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Jun 2 15:10:52 2016 +0200

    common: New function openpgp_is_curve_supported.
    
    * common/openpgp-oid.c: Include openpgpdefs.h.
    (oidtable): Add field pubkey_algo.
    (openpgp_is_curve_supported): New.
    --
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/common/openpgp-oid.c b/common/openpgp-oid.c
index 1b6d5f3..7c93547 100644
--- a/common/openpgp-oid.c
+++ b/common/openpgp-oid.c
@@ -35,7 +35,7 @@
 #include <assert.h>
 
 #include "util.h"
-
+#include "openpgpdefs.h"
 
 /* A table with all our supported OpenPGP curves.  */
 static struct {
@@ -43,10 +43,11 @@ static struct {
   const char *oidstr; /* IETF formatted OID.  */
   unsigned int nbits; /* Nominal bit length of the curve.  */
   const char *alias;  /* NULL or alternative name of the curve.  */
+  int pubkey_algo;    /* Required OpenPGP algo or 0 for ECDSA/ECDH.  */
 } oidtable[] = {
 
-  { "Curve25519",      "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519" },
-  { "Ed25519",         "1.3.6.1.4.1.11591.15.1", 255, "ed25519" },
+  { "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", PUBKEY_ALGO_ECDH },
+  { "Ed25519",    "1.3.6.1.4.1.11591.15.1", 255, "ed25519", PUBKEY_ALGO_EDDSA },
 
   { "NIST P-256",      "1.2.840.10045.3.1.7",    256, "nistp256" },
   { "NIST P-384",      "1.3.132.0.34",           384, "nistp384" },
@@ -408,3 +409,29 @@ openpgp_enum_curves (int *iterp)
   *iterp = idx;
   return NULL;
 }
+
+
+/* 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. */
+const char *
+openpgp_is_curve_supported (const char *name, int *r_algo)
+{
+  int idx;
+
+  if (r_algo)
+    *r_algo = 0;
+  for (idx = 0; idx < DIM (oidtable) && oidtable[idx].name; idx++)
+    {
+      if (!strcmp (name, (oidtable[idx].alias? oidtable[idx].alias
+                          /**/               : oidtable[idx].name))
+          && curve_supported_p (oidtable[idx].name))
+        {
+          if (r_algo)
+            *r_algo = oidtable[idx].pubkey_algo;
+          return oidtable[idx].name;
+        }
+    }
+  return NULL;
+}
diff --git a/common/util.h b/common/util.h
index 84a15ab..7634885 100644
--- a/common/util.h
+++ b/common/util.h
@@ -214,7 +214,7 @@ int openpgp_oid_is_crv25519 (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);
 
 
 /*-- homedir.c --*/

commit c9f9fabdcc1022a5366e1c841acde55fb07105cb
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Jun 2 15:09:42 2016 +0200

    common: Add comments on how to enable backtrace().
    
    --

diff --git a/common/logging.c b/common/logging.c
index 9175b4f..b6bafc7 100644
--- a/common/logging.c
+++ b/common/logging.c
@@ -54,7 +54,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <assert.h>
-
+/* #include <execinfo.h> */
 
 #define GNUPG_COMMON_NEED_AFLOCAL 1
 #include "util.h"
@@ -748,6 +748,19 @@ do_logv (int level, int ignore_arg_ptr, const char *fmt, va_list arg_ptr)
       if (missing_lf)
         es_putc_unlocked ('\n', logstream );
       es_funlockfile (logstream);
+      /* Using backtrace requires a configure test and to pass
+       * -rdynamic to gcc.  Thus we do not enable it now.  */
+      /* { */
+      /*   void *btbuf[20]; */
+      /*   int btidx, btlen; */
+      /*   char **btstr; */
+
+      /*   btlen = backtrace (btbuf, DIM (btbuf)); */
+      /*   btstr = backtrace_symbols (btbuf, btlen); */
+      /*   if (btstr) */
+      /*     for (btidx=0; btidx < btlen; btidx++) */
+      /*       log_debug ("[%d] %s\n", btidx, btstr[btidx]); */
+      /* } */
       abort ();
     }
   else

-----------------------------------------------------------------------

Summary of changes:
 common/logging.c     |  15 +-
 common/openpgp-oid.c |  33 +++-
 common/util.h        |   2 +-
 doc/gpg.texi         |  30 ++++
 g10/build-packet.c   |   2 +
 g10/gpg.c            |  28 ++++
 g10/keyedit.c        | 178 +++++++++++++++------
 g10/keygen.c         | 424 ++++++++++++++++++++++++++++++++++++++-------------
 g10/main.h           |   7 +-
 g10/seskey.c         |   9 +-
 10 files changed, 565 insertions(+), 163 deletions(-)


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list