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@gnupg.org>
This commit is contained in:
Werner Koch 2016-06-02 15:54:48 +02:00
parent d837f6b0ea
commit 8f2a053a0f
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
5 changed files with 512 additions and 155 deletions

View File

@ -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.
@item --quick-addkey @code{fpr} [@code{algo} [@code{usage} [@code{expire}]]]
@opindex quick-addkey
Directly add a subkey to the key identified by the fingerprint
@code{fpr}. Without the optional arguments an encryption subkey is
added. If any of the arguments are given a more specific subkey is
added.
@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

View File

@ -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:

View File

@ -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)

View File

@ -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,6 +2018,86 @@ 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)
{
*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;
break;
case PUBKEY_ALGO_ECDSA:
case PUBKEY_ALGO_ECDH:
*min=256;
*def=256;
*max=521;
break;
case PUBKEY_ALGO_EDDSA:
*min=255;
*def=255;
*max=441;
break;
}
}
/* 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 (!silent)
tty_printf (_("rounded up to %u bits\n"), nbits);
}
else if (algo == PUBKEY_ALGO_EDDSA)
{
if (nbits != 255 && nbits != 441)
{
if (nbits < 256)
nbits = 255;
else
nbits = 441;
if (!silent)
tty_printf (_("rounded to %u bits\n"), nbits);
}
}
else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
{
if (nbits != 256 && nbits != 384 && nbits != 521)
{
if (nbits < 256)
nbits = 256;
else if (nbits < 384)
nbits = 384;
else
nbits = 521;
if (!silent)
tty_printf (_("rounded to %u bits\n"), nbits);
}
}
else if ((nbits % 32))
{
nbits = ((nbits + 31) / 32) * 32;
if (!silent)
tty_printf (_("rounded up to %u bits\n"), nbits );
}
return nbits;
}
/* 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. */
@ -2024,12 +2105,12 @@ static unsigned
ask_keysize (int algo, unsigned int primary_keysize)
{
unsigned int nbits;
unsigned int min = 1024;
unsigned int def = DEFAULT_STD_KEYSIZE;
unsigned int max = 4096;
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. */
@ -2044,29 +2125,6 @@ ask_keysize (int algo, unsigned int primary_keysize)
goto leave;
}
/* Deviations from the standard values. */
switch(algo)
{
case PUBKEY_ALGO_DSA:
min = opt.expert? 768 : 1024;
def=2048;
max=3072;
break;
case PUBKEY_ALGO_ECDSA:
case PUBKEY_ALGO_ECDH:
min=256;
def=256;
max=521;
break;
case PUBKEY_ALGO_EDDSA:
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);
@ -2095,45 +2153,7 @@ ask_keysize (int algo, unsigned int primary_keysize)
tty_printf (_("Requested keysize is %u bits\n"), nbits);
leave:
if (algo == PUBKEY_ALGO_DSA && (nbits % 64))
{
nbits = ((nbits + 63) / 64) * 64;
if (!autocomp)
tty_printf (_("rounded up to %u bits\n"), nbits);
}
else if (algo == PUBKEY_ALGO_EDDSA)
{
if (nbits != 255 && nbits != 441)
{
if (nbits < 256)
nbits = 255;
else
nbits = 441;
if (!autocomp)
tty_printf (_("rounded to %u bits\n"), nbits);
}
}
else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
{
if (nbits != 256 && nbits != 384 && nbits != 521)
{
if (nbits < 256)
nbits = 256;
else if (nbits < 384)
nbits = 384;
else
nbits = 521;
if (!autocomp)
tty_printf (_("rounded to %u bits\n"), nbits);
}
}
else if ((nbits % 32))
{
nbits = ((nbits + 31) / 32) * 32;
if (!autocomp)
tty_printf (_("rounded up to %u bits\n"), nbits );
}
nbits = fixup_keysize (nbits, algo, autocomp);
return nbits;
}
@ -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;
struct para_data_s *r = get_parameter( para, key );
int i;
if( !r )
return 0; /* none (this is an optional parameter)*/
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 */
}
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,
}
/* Add a new subkey to an existing key. Returns 0 if a new key has
been generated and put into the keyblocks. */
gpg_error_t
generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
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. If any of ALGOSTR,
USAGESTR, or EXPIRESTR is NULL interactive mode is used. */
gpg_error_t
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);
expire = ask_expire_interval (0, NULL);
if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay",
_("Really create? (y/N) ")))
if (interactive)
{
err = gpg_error (GPG_ERR_CANCELED);
goto leave;
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) ")))
{
err = gpg_error (GPG_ERR_CANCELED);
goto leave;
}
}
else /* Unattended mode. */
{
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)

View File

@ -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);