mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-08 12:44:23 +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 ''}
|
for it. To create a key without any protection @code{--passphrase ''}
|
||||||
may be used.
|
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
|
@item --gen-key
|
||||||
@opindex gen-key
|
@opindex gen-key
|
||||||
Generate a new key pair using the current default parameters. This is
|
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
|
mode. See the manual section ``Unattended key generation'' on how
|
||||||
to use this.
|
to use this.
|
||||||
|
|
||||||
|
|
||||||
@item --gen-revoke @code{name}
|
@item --gen-revoke @code{name}
|
||||||
@opindex gen-revoke
|
@opindex gen-revoke
|
||||||
Generate a revocation certificate for the complete key. To only 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,
|
aQuickSignKey,
|
||||||
aQuickLSignKey,
|
aQuickLSignKey,
|
||||||
aQuickAddUid,
|
aQuickAddUid,
|
||||||
|
aQuickAddKey,
|
||||||
aListConfig,
|
aListConfig,
|
||||||
aListGcryptConfig,
|
aListGcryptConfig,
|
||||||
aGPGConfList,
|
aGPGConfList,
|
||||||
@ -426,6 +427,7 @@ static ARGPARSE_OPTS opts[] = {
|
|||||||
N_("quickly generate a new key pair")),
|
N_("quickly generate a new key pair")),
|
||||||
ARGPARSE_c (aQuickAddUid, "quick-adduid",
|
ARGPARSE_c (aQuickAddUid, "quick-adduid",
|
||||||
N_("quickly add a new user-id")),
|
N_("quickly add a new user-id")),
|
||||||
|
ARGPARSE_c (aQuickAddKey, "quick-addkey", "@"),
|
||||||
ARGPARSE_c (aFullKeygen, "full-gen-key" ,
|
ARGPARSE_c (aFullKeygen, "full-gen-key" ,
|
||||||
N_("full featured key pair generation")),
|
N_("full featured key pair generation")),
|
||||||
ARGPARSE_c (aGenRevoke, "gen-revoke",N_("generate a revocation certificate")),
|
ARGPARSE_c (aGenRevoke, "gen-revoke",N_("generate a revocation certificate")),
|
||||||
@ -2433,6 +2435,7 @@ main (int argc, char **argv)
|
|||||||
case aStore:
|
case aStore:
|
||||||
case aQuickKeygen:
|
case aQuickKeygen:
|
||||||
case aQuickAddUid:
|
case aQuickAddUid:
|
||||||
|
case aQuickAddKey:
|
||||||
case aExportOwnerTrust:
|
case aExportOwnerTrust:
|
||||||
case aImportOwnerTrust:
|
case aImportOwnerTrust:
|
||||||
case aRebuildKeydbCaches:
|
case aRebuildKeydbCaches:
|
||||||
@ -3775,6 +3778,7 @@ main (int argc, char **argv)
|
|||||||
case aDeleteSecretAndPublicKeys:
|
case aDeleteSecretAndPublicKeys:
|
||||||
case aQuickKeygen:
|
case aQuickKeygen:
|
||||||
case aQuickAddUid:
|
case aQuickAddUid:
|
||||||
|
case aQuickAddKey:
|
||||||
case aFullKeygen:
|
case aFullKeygen:
|
||||||
case aKeygen:
|
case aKeygen:
|
||||||
case aImport:
|
case aImport:
|
||||||
@ -4148,6 +4152,30 @@ main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
case aFastImport:
|
||||||
opt.import_options |= IMPORT_FAST;
|
opt.import_options |= IMPORT_FAST;
|
||||||
case aImport:
|
case aImport:
|
||||||
|
178
g10/keyedit.c
178
g10/keyedit.c
@ -1,6 +1,6 @@
|
|||||||
/* keyedit.c - Edit properties of a key
|
/* keyedit.c - Edit properties of a key
|
||||||
* Copyright (C) 1998-2010 Free Software Foundation, Inc.
|
* 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
|
* Copyright (C) 2015, 2016 g10 Code GmbH
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
@ -2349,7 +2349,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case cmdADDKEY:
|
case cmdADDKEY:
|
||||||
if (!generate_subkeypair (ctrl, keyblock))
|
if (!generate_subkeypair (ctrl, keyblock, NULL, NULL, NULL))
|
||||||
{
|
{
|
||||||
redisplay = 1;
|
redisplay = 1;
|
||||||
modified = 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
|
/* Unattended key signing function. If the key specifified by FPR is
|
||||||
available and FPR is the primary fingerprint all user ids of the
|
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
|
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;
|
kbnode_t keyblock = NULL;
|
||||||
KEYDB_HANDLE kdbhd = NULL;
|
KEYDB_HANDLE kdbhd = NULL;
|
||||||
int modified = 0;
|
int modified = 0;
|
||||||
KEYDB_SEARCH_DESC desc;
|
|
||||||
PKT_public_key *pk;
|
PKT_public_key *pk;
|
||||||
kbnode_t node;
|
kbnode_t node;
|
||||||
strlist_t sl;
|
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
|
/* We require a fingerprint because only this uniquely identifies a
|
||||||
key and may thus be used to select a key for unattended key
|
key and may thus be used to select a key for unattended key
|
||||||
signing. */
|
signing. */
|
||||||
if (classify_user_id (fpr, &desc, 1)
|
if (find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd))
|
||||||
|| !(desc.mode == KEYDB_SEARCH_MODE_FPR
|
goto leave;
|
||||||
|| 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 (fix_keyblock (&keyblock))
|
if (fix_keyblock (&keyblock))
|
||||||
modified++;
|
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
|
static void
|
||||||
tty_print_notations (int indent, PKT_signature * sig)
|
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
|
/* keygen.c - Generate a key pair
|
||||||
* Copyright (C) 1998-2007, 2009-2011 Free Software Foundation, Inc.
|
* 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.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -54,6 +54,7 @@
|
|||||||
#define DEFAULT_STD_CURVE NULL
|
#define DEFAULT_STD_CURVE NULL
|
||||||
#define DEFAULT_STD_SUBALGO PUBKEY_ALGO_RSA
|
#define DEFAULT_STD_SUBALGO PUBKEY_ALGO_RSA
|
||||||
#define DEFAULT_STD_SUBKEYSIZE 2048
|
#define DEFAULT_STD_SUBKEYSIZE 2048
|
||||||
|
#define DEFAULT_STD_SUBKEYUSE PUBKEY_USAGE_ENC
|
||||||
#define DEFAULT_STD_SUBCURVE NULL
|
#define DEFAULT_STD_SUBCURVE NULL
|
||||||
|
|
||||||
/* Flag bits used during key generation. */
|
/* 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
|
/* Ask for the key size. ALGO is the algorithm. If PRIMARY_KEYSIZE
|
||||||
is not 0, the function asks for the size of the encryption
|
is not 0, the function asks for the size of the encryption
|
||||||
subkey. */
|
subkey. */
|
||||||
@ -2024,12 +2105,12 @@ static unsigned
|
|||||||
ask_keysize (int algo, unsigned int primary_keysize)
|
ask_keysize (int algo, unsigned int primary_keysize)
|
||||||
{
|
{
|
||||||
unsigned int nbits;
|
unsigned int nbits;
|
||||||
unsigned int min = 1024;
|
unsigned int min, def, max;
|
||||||
unsigned int def = DEFAULT_STD_KEYSIZE;
|
|
||||||
unsigned int max = 4096;
|
|
||||||
int for_subkey = !!primary_keysize;
|
int for_subkey = !!primary_keysize;
|
||||||
int autocomp = 0;
|
int autocomp = 0;
|
||||||
|
|
||||||
|
get_keysize_range (algo, &min, &def, &max);
|
||||||
|
|
||||||
if (primary_keysize && !opt.expert)
|
if (primary_keysize && !opt.expert)
|
||||||
{
|
{
|
||||||
/* Deduce the subkey size from the primary key size. */
|
/* Deduce the subkey size from the primary key size. */
|
||||||
@ -2044,29 +2125,6 @@ ask_keysize (int algo, unsigned int primary_keysize)
|
|||||||
goto leave;
|
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"),
|
tty_printf(_("%s keys may be between %u and %u bits long.\n"),
|
||||||
openpgp_pk_algo_name (algo), min, max);
|
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);
|
tty_printf (_("Requested keysize is %u bits\n"), nbits);
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
if (algo == PUBKEY_ALGO_DSA && (nbits % 64))
|
nbits = fixup_keysize (nbits, algo, autocomp);
|
||||||
{
|
|
||||||
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 );
|
|
||||||
}
|
|
||||||
|
|
||||||
return nbits;
|
return nbits;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2885,6 +2905,50 @@ get_parameter_algo( struct para_data_s *para, enum para_name key,
|
|||||||
return i;
|
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
|
* Parse the usage parameter and set the keyflags. Returns -1 on
|
||||||
* error, 0 for no usage given or 1 for usage available.
|
* error, 0 for no usage given or 1 for usage available.
|
||||||
@ -2893,33 +2957,24 @@ static int
|
|||||||
parse_parameter_usage (const char *fname,
|
parse_parameter_usage (const char *fname,
|
||||||
struct para_data_s *para, enum para_name key)
|
struct para_data_s *para, enum para_name key)
|
||||||
{
|
{
|
||||||
struct para_data_s *r = get_parameter( para, key );
|
struct para_data_s *r = get_parameter( para, key );
|
||||||
char *p, *pn;
|
int i;
|
||||||
unsigned int use;
|
|
||||||
|
|
||||||
if( !r )
|
if (!r)
|
||||||
return 0; /* none (this is an optional parameter)*/
|
return 0; /* none (this is an optional parameter)*/
|
||||||
|
|
||||||
use = 0;
|
i = parse_usagestr (r->u.value);
|
||||||
pn = r->u.value;
|
if (i == -1)
|
||||||
while ( (p = strsep (&pn, " \t,")) ) {
|
{
|
||||||
if ( !*p)
|
log_error ("%s:%d: invalid usage list\n", fname, r->lnr );
|
||||||
;
|
return -1; /* error */
|
||||||
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 */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
r->u.usage = use;
|
|
||||||
return 1;
|
r->u.usage = i;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
parse_revocation_key (const char *fname,
|
parse_revocation_key (const char *fname,
|
||||||
struct para_data_s *para, enum para_name key)
|
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
|
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;
|
gpg_error_t err = 0;
|
||||||
|
int interactive;
|
||||||
kbnode_t node;
|
kbnode_t node;
|
||||||
PKT_public_key *pri_psk = NULL;
|
PKT_public_key *pri_psk = NULL;
|
||||||
PKT_public_key *sub_psk = NULL;
|
PKT_public_key *sub_psk = NULL;
|
||||||
@ -4278,6 +4440,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
|
|||||||
char *hexgrip = NULL;
|
char *hexgrip = NULL;
|
||||||
char *serialno = NULL;
|
char *serialno = NULL;
|
||||||
|
|
||||||
|
interactive = (!algostr || !usagestr || !expirestr);
|
||||||
|
|
||||||
/* Break out the primary key. */
|
/* Break out the primary key. */
|
||||||
node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
|
node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
|
||||||
if (!node)
|
if (!node)
|
||||||
@ -4317,32 +4481,72 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
|
|||||||
goto leave;
|
goto leave;
|
||||||
if (agent_get_keyinfo (NULL, hexgrip, &serialno))
|
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;
|
goto leave;
|
||||||
}
|
}
|
||||||
if (serialno)
|
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);
|
xfree (hexgrip);
|
||||||
hexgrip = NULL;
|
hexgrip = NULL;
|
||||||
algo = ask_algo (ctrl, 1, NULL, &use, &hexgrip);
|
if (interactive)
|
||||||
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);
|
algo = ask_algo (ctrl, 1, NULL, &use, &hexgrip);
|
||||||
goto leave;
|
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)
|
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_passwd (ctrl_t ctrl, const char *username);
|
||||||
void keyedit_quick_adduid (ctrl_t ctrl, const char *username,
|
void keyedit_quick_adduid (ctrl_t ctrl, const char *username,
|
||||||
const char *newuid);
|
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,
|
void keyedit_quick_sign (ctrl_t ctrl, const char *fpr,
|
||||||
strlist_t uids, strlist_t locusr, int local);
|
strlist_t uids, strlist_t locusr, int local);
|
||||||
void show_basic_key_info (KBNODE keyblock);
|
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,
|
gpg_error_t make_backsig (PKT_signature *sig, PKT_public_key *pk,
|
||||||
PKT_public_key *sub_pk, PKT_public_key *sub_psk,
|
PKT_public_key *sub_pk, PKT_public_key *sub_psk,
|
||||||
u32 timestamp, const char *cache_nonce);
|
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
|
#ifdef ENABLE_CARD_SUPPORT
|
||||||
gpg_error_t generate_card_subkeypair (kbnode_t pub_keyblock,
|
gpg_error_t generate_card_subkeypair (kbnode_t pub_keyblock,
|
||||||
int keyno, const char *serialno);
|
int keyno, const char *serialno);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user