aboutsummaryrefslogtreecommitdiffstats
path: root/g10/keygen.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--g10/keygen.c424
1 files changed, 314 insertions, 110 deletions
diff --git a/g10/keygen.c b/g10/keygen.c
index f9cbf21a8..2ef80a755 100644
--- a/g10/keygen.c
+++ b/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,88 +2018,47 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
}
-/* 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. */
-static unsigned
-ask_keysize (int algo, unsigned int primary_keysize)
+static void
+get_keysize_range (int algo,
+ unsigned int *min, unsigned int *def, unsigned int *max)
{
- unsigned int nbits;
- unsigned int min = 1024;
- unsigned int def = DEFAULT_STD_KEYSIZE;
- unsigned int max = 4096;
- int for_subkey = !!primary_keysize;
- int autocomp = 0;
-
- if (primary_keysize && !opt.expert)
- {
- /* Deduce the subkey size from the primary key size. */
- if (algo == PUBKEY_ALGO_DSA && primary_keysize > 3072)
- nbits = 3072; /* For performance reasons we don't support more
- than 3072 bit DSA. However we won't see this
- case anyway because DSA can't be used as an
- encryption subkey ;-). */
- else
- nbits = primary_keysize;
- autocomp = 1;
- goto leave;
- }
+ *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;
+ *min = opt.expert? 768 : 1024;
+ *def=2048;
+ *max=3072;
break;
case PUBKEY_ALGO_ECDSA:
case PUBKEY_ALGO_ECDH:
- min=256;
- def=256;
- max=521;
+ *min=256;
+ *def=256;
+ *max=521;
break;
case PUBKEY_ALGO_EDDSA:
- min=255;
- def=255;
- max=441;
+ *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);
-
- for (;;)
- {
- char *prompt, *answer;
-
- if (for_subkey)
- prompt = xasprintf (_("What keysize do you want "
- "for the subkey? (%u) "), def);
- else
- prompt = xasprintf (_("What keysize do you want? (%u) "), def);
- answer = cpr_get ("keygen.size", prompt);
- cpr_kill_prompt ();
- nbits = *answer? atoi (answer): def;
- xfree(prompt);
- xfree(answer);
-
- if(nbits<min || nbits>max)
- tty_printf(_("%s keysizes must be in the range %u-%u\n"),
- openpgp_pk_algo_name (algo), min, max);
- else
- break;
- }
-
- tty_printf (_("Requested keysize is %u bits\n"), nbits);
- leave:
+/* 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 (!autocomp)
+ if (!silent)
tty_printf (_("rounded up to %u bits\n"), nbits);
}
else if (algo == PUBKEY_ALGO_EDDSA)
@@ -2109,7 +2069,7 @@ ask_keysize (int algo, unsigned int primary_keysize)
nbits = 255;
else
nbits = 441;
- if (!autocomp)
+ if (!silent)
tty_printf (_("rounded to %u bits\n"), nbits);
}
}
@@ -2123,14 +2083,14 @@ ask_keysize (int algo, unsigned int primary_keysize)
nbits = 384;
else
nbits = 521;
- if (!autocomp)
+ if (!silent)
tty_printf (_("rounded to %u bits\n"), nbits);
}
}
else if ((nbits % 32))
{
nbits = ((nbits + 31) / 32) * 32;
- if (!autocomp)
+ if (!silent)
tty_printf (_("rounded up to %u bits\n"), nbits );
}
@@ -2138,6 +2098,66 @@ ask_keysize (int algo, unsigned int 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
+ subkey. */
+static unsigned
+ask_keysize (int algo, unsigned int primary_keysize)
+{
+ unsigned int nbits;
+ 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. */
+ if (algo == PUBKEY_ALGO_DSA && primary_keysize > 3072)
+ nbits = 3072; /* For performance reasons we don't support more
+ than 3072 bit DSA. However we won't see this
+ case anyway because DSA can't be used as an
+ encryption subkey ;-). */
+ else
+ nbits = primary_keysize;
+ autocomp = 1;
+ goto leave;
+ }
+
+ tty_printf(_("%s keys may be between %u and %u bits long.\n"),
+ openpgp_pk_algo_name (algo), min, max);
+
+ for (;;)
+ {
+ char *prompt, *answer;
+
+ if (for_subkey)
+ prompt = xasprintf (_("What keysize do you want "
+ "for the subkey? (%u) "), def);
+ else
+ prompt = xasprintf (_("What keysize do you want? (%u) "), def);
+ answer = cpr_get ("keygen.size", prompt);
+ cpr_kill_prompt ();
+ nbits = *answer? atoi (answer): def;
+ xfree(prompt);
+ xfree(answer);
+
+ if(nbits<min || nbits>max)
+ tty_printf(_("%s keysizes must be in the range %u-%u\n"),
+ openpgp_pk_algo_name (algo), min, max);
+ else
+ break;
+ }
+
+ tty_printf (_("Requested keysize is %u bits\n"), nbits);
+
+ leave:
+ nbits = fixup_keysize (nbits, algo, autocomp);
+ return nbits;
+}
+
+
/* Ask for the curve. ALGO is the selected algorithm which this
function may adjust. Returns a malloced string with the name of
the curve. BOTH tells that gpg creates a primary and subkey. */
@@ -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;
-
- 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 */
- }
+ struct para_data_s *r = get_parameter( para, key );
+ int i;
+
+ if (!r)
+ return 0; /* none (this is an optional parameter)*/
+
+ 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,
}
+gpg_error_t
+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. */
+ 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)
+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);
+ if (interactive)
+ {
+ 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) ")))
+ 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 = gpg_error (GPG_ERR_CANCELED);
- goto leave;
+ 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)