mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
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:
parent
d837f6b0ea
commit
8f2a053a0f
30
doc/gpg.texi
30
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.
|
||||
|
||||
@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
|
||||
|
28
g10/gpg.c
28
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:
|
||||
|
178
g10/keyedit.c
178
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)
|
||||
|
424
g10/keygen.c
424
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,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)
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user