gpg: Add command --quick-gen-key
authorWerner Koch <wk@gnupg.org>
Wed, 23 Jul 2014 13:12:43 +0000 (15:12 +0200)
committerWerner Koch <wk@gnupg.org>
Wed, 23 Jul 2014 13:12:43 +0000 (15:12 +0200)
* g10/gpg.c (aQuickKeygen): New.
* g10/misc.c (is_valid_user_id): New stub.
* g10/keygen.c (quickgen_set_para): New.
(quick_generate_keypair): New.
--

Note that the validation of the specified user id has not yet been
implemented.

doc/gpg.texi
g10/gpg.c
g10/keygen.c
g10/main.h
g10/misc.c

index 3370ff2..e0b0039 100644 (file)
@@ -592,14 +592,29 @@ This section explains the main commands for key management
 
 @table @gnupgtabopt
 
+@ifset gpgtwoone
+@item --quick-gen-key @code{user-id}
+@opindex quick-gen-key
+This is simple command to generate a standard key with one user id.
+In contrast to @option{--gen-key} the key is generated directly
+without the need to answer a bunch of prompts.  Unless the option
+@option{--yes} is given, the key creation will be canceled if the
+given user id already exists in the key ring.
+
+If invoked directly on the console without any special options an
+answer to a ``Continue?'' style confirmation prompt is required.  In
+case the user id already exists in the key ring a second prompt to
+force the creation of the key will show up.
+@end ifset
+
 @item --gen-key
 @opindex gen-key
 Generate a new key pair. This command is normally only used
 interactively.
 
-There is an experimental feature which allows you to create keys in
-batch mode. See the file @file{doc/DETAILS} in the source distribution
-on how to use this.
+There is also a feature which allows you to create keys in batch
+mode. See the file @file{doc/DETAILS} in the source distribution on
+how to use this.
 
 @item --gen-revoke @code{name}
 @opindex gen-revoke
index da664be..1f840c6 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -106,6 +106,7 @@ enum cmd_and_opt_values
     aDecryptFiles,
     aClearsign,
     aStore,
+    aQuickKeygen,
     aKeygen,
     aSignEncr,
     aSignEncrSym,
@@ -406,6 +407,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aCheckKeys, "check-sigs",N_("list and check key signatures")),
   ARGPARSE_c (oFingerprint, "fingerprint", N_("list keys and fingerprints")),
   ARGPARSE_c (aListSecretKeys, "list-secret-keys", N_("list secret keys")),
+  ARGPARSE_c (aQuickKeygen,  "quick-gen-key" ,
+              N_("quickly generate a new key pair")),
   ARGPARSE_c (aKeygen,    "gen-key",  N_("generate a new key pair")),
   ARGPARSE_c (aGenRevoke, "gen-revoke",N_("generate a revocation certificate")),
   ARGPARSE_c (aDeleteKeys,"delete-keys",
@@ -2279,6 +2282,7 @@ main (int argc, char **argv)
          case aSignKey:
          case aLSignKey:
          case aStore:
+         case aQuickKeygen:
          case aExportOwnerTrust:
          case aImportOwnerTrust:
           case aRebuildKeydbCaches:
@@ -3612,6 +3616,7 @@ main (int argc, char **argv)
       case aPasswd:
       case aDeleteSecretKeys:
       case aDeleteSecretAndPublicKeys:
+      case aQuickKeygen:
       case aKeygen:
       case aImport:
       case aExportSecret:
@@ -3895,6 +3900,14 @@ main (int argc, char **argv)
        free_strlist (sl);
        break;
 
+      case aQuickKeygen:
+        if (argc != 1 )
+          wrong_args("--gen-key user-id");
+        username = make_username (fname);
+        quick_generate_keypair (username);
+        xfree (username);
+        break;
+
       case aKeygen: /* generate a key */
        if( opt.batch ) {
            if( argc > 1 )
index 4509231..d6b2dd0 100644 (file)
@@ -1,6 +1,7 @@
 /* keygen.c - generate a key pair
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
  *               2007, 2009, 2010, 2011  Free Software Foundation, Inc.
+ * Copyright (C) 2014  Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -3408,6 +3409,129 @@ read_parameter_file( const char *fname )
 }
 
 
+/* Helper for quick_generate_keypair.  */
+static struct para_data_s *
+quickgen_set_para (struct para_data_s *para, int for_subkey,
+                   int algo, int nbits, const char *curve)
+{
+  struct para_data_s *r;
+
+  r = xmalloc_clear (sizeof *r + 20);
+  r->key = for_subkey? pSUBKEYUSAGE :  pKEYUSAGE;
+  strcpy (r->u.value, for_subkey ? "encrypt" : "sign");
+  r->next = para;
+  para = r;
+  r = xmalloc_clear (sizeof *r + 20);
+  r->key = for_subkey? pSUBKEYTYPE : pKEYTYPE;
+  sprintf (r->u.value, "%d", algo);
+  r->next = para;
+  para = r;
+
+  if (curve)
+    {
+      r = xmalloc_clear (sizeof *r + strlen (curve));
+      r->key = for_subkey? pSUBKEYCURVE : pKEYCURVE;
+      strcpy (r->u.value, curve);
+      r->next = para;
+      para = r;
+    }
+  else
+    {
+      r = xmalloc_clear (sizeof *r + 20);
+      r->key = for_subkey? pSUBKEYLENGTH : pKEYLENGTH;
+      sprintf (r->u.value, "%u", nbits);
+      r->next = para;
+      para = r;
+    }
+
+  return para;
+}
+
+
+
+/*
+ * Unattended generaion of a standard key.
+ */
+void
+quick_generate_keypair (const char *uid)
+{
+  gpg_error_t err;
+  struct para_data_s *para = NULL;
+  struct para_data_s *r;
+  struct output_control_s outctrl;
+  int use_tty;
+
+  memset (&outctrl, 0, sizeof outctrl);
+
+  use_tty = (!opt.batch && !opt.answer_yes
+             && !cpr_enabled ()
+             && gnupg_isatty (fileno (stdin))
+             && gnupg_isatty (fileno (stdout))
+             && gnupg_isatty (fileno (stderr)));
+
+  r = xmalloc_clear (sizeof *r + strlen (uid));
+  r->key = pUSERID;
+  strcpy (r->u.value, uid);
+  r->next = para;
+  para = r;
+
+  uid = trim_spaces (r->u.value);
+  if (!*uid || (!opt.allow_freeform_uid && !is_valid_user_id (uid)))
+    {
+      log_error (_("Key generation failed: %s\n"),
+                 gpg_strerror (GPG_ERR_INV_USER_ID));
+      goto leave;
+    }
+
+  /* If gpg is directly used on the console ask whether a key with the
+     given user id shall really be created.  */
+  if (use_tty)
+    {
+      tty_printf (_("About to create a key for:\n    \"%s\"\n\n"), uid);
+      if (!cpr_get_answer_is_yes_def ("quick_keygen.okay",
+                                      _("Continue? (Y/n) "), 1))
+        goto leave;
+    }
+
+  /* Check whether such a user ID already exists.  */
+  {
+    KEYDB_HANDLE kdbhd;
+    KEYDB_SEARCH_DESC desc;
+
+    memset (&desc, 0, sizeof desc);
+    desc.mode = KEYDB_SEARCH_MODE_EXACT;
+    desc.u.name = uid;
+
+    kdbhd = keydb_new ();
+    err = keydb_search (kdbhd, &desc, 1, NULL);
+    keydb_release (kdbhd);
+    if (gpg_err_code (err) != GPG_ERR_NOT_FOUND)
+      {
+        log_info (_("A key for \"%s\" already exists\n"), uid);
+        if (opt.answer_yes)
+          ;
+        else if (!use_tty
+                 || !cpr_get_answer_is_yes_def ("quick_keygen.force",
+                                                _("Create anyway? (y/N) "), 0))
+          {
+            log_inc_errorcount ();  /* we used log_info */
+            goto leave;
+          }
+        log_info (_("creating anyway\n"));
+      }
+  }
+
+  para = quickgen_set_para (para, 0, PUBKEY_ALGO_RSA, 2048, NULL);
+  para = quickgen_set_para (para, 1, PUBKEY_ALGO_RSA, 2048, NULL);
+  /* para = quickgen_set_para (para, 0, PUBKEY_ALGO_EDDSA, 0, "Ed25519"); */
+  /* para = quickgen_set_para (para, 1, PUBKEY_ALGO_ECDH,  0, "Curve25519"); */
+
+  proc_parameter_file (para, "[internal]", &outctrl, 0);
+ leave:
+  release_parameter_list (para);
+}
+
+
 /*
  * Generate a keypair (fname is only used in batch mode) If
  * CARD_SERIALNO is not NULL the function will create the keys on an
index d39c7c8..4ec4bbf 100644 (file)
@@ -154,6 +154,7 @@ int parse_options(char *str,unsigned int *options,
                  struct parse_options *opts,int noisy);
 int has_invalid_email_chars (const char *s);
 int is_valid_mailbox (const char *name);
+int is_valid_user_id (const char *uid);
 const char *get_libexecdir (void);
 int path_access(const char *file,int mode);
 
@@ -247,6 +248,7 @@ void show_basic_key_info (KBNODE keyblock);
 u32 parse_expire_string(const char *string);
 u32 ask_expire_interval(int object,const char *def_expire);
 u32 ask_expiredate(void);
+void quick_generate_keypair (const char *uid);
 void generate_keypair (ctrl_t ctrl, const char *fname,
                        const char *card_serialno, int card_backup_key);
 int keygen_set_std_prefs (const char *string,int personal);
index e219d76..0125da4 100644 (file)
@@ -1499,6 +1499,20 @@ is_valid_mailbox (const char *name)
 }
 
 
+/* Check whether UID is a valid standard user id of the form
+     "Heinrich Heine <heinrichh@duesseldorf.de>"
+   and return true if this is the case. */
+int
+is_valid_user_id (const char *uid)
+{
+  if (!uid || !*uid)
+    return 0;
+
+  return 1;
+}
+
+
+
 /* Similar to access(2), but uses PATH to find the file. */
 int
 path_access(const char *file,int mode)