From ea186540db5b418bc6f6e5ca90337672c9981c88 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 23 Jul 2014 15:12:43 +0200 Subject: [PATCH] gpg: Add command --quick-gen-key * 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 | 21 +++++++-- g10/gpg.c | 13 ++++++ g10/keygen.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++ g10/main.h | 2 + g10/misc.c | 14 ++++++ 5 files changed, 171 insertions(+), 3 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index 3370ff2c4..e0b0039a9 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -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 diff --git a/g10/gpg.c b/g10/gpg.c index da664be9d..1f840c6ed 100644 --- 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 ) diff --git a/g10/keygen.c b/g10/keygen.c index 450923144..d6b2dd091 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -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 diff --git a/g10/main.h b/g10/main.h index d39c7c853..4ec4bbfd0 100644 --- a/g10/main.h +++ b/g10/main.h @@ -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); diff --git a/g10/misc.c b/g10/misc.c index e219d7623..0125da4b0 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -1499,6 +1499,20 @@ is_valid_mailbox (const char *name) } +/* Check whether UID is a valid standard user id of the form + "Heinrich Heine " + 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)