diff --git a/doc/gpg.texi b/doc/gpg.texi index 212defe0c..5a2d8768a 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -683,6 +683,15 @@ 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. +To create an OpenPGP key from the keys available on the currently +inserted smartcard, the special string ``card'' can be used for +@var{algo}. If the card features an encryption and a signing key, gpg +will figure them out and creates an OpenPGP key consisting of the +usual primary key and one subkey. This works only with certain +smartcards. Note that the interactive @option{--full-gen-key} command +allows to do the same but with greater flexibility in the selection of +the smartcard keys. + Note that it is possible to create a primary key and a subkey using non-default algorithms by using ``default'' and changing the default parameters using the option @option{--default-new-key-algo}. diff --git a/g10/keygen.c b/g10/keygen.c index bd02b631f..5be251e38 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -151,7 +151,8 @@ static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey, const char *expirestr, int *r_algo, unsigned int *r_usage, u32 *r_expire, unsigned int *r_nbits, - const char **r_curve, int *r_version); + const char **r_curve, int *r_version, + char **r_keygrip); static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, struct output_control_s *outctrl, int card ); static int write_keyblock (iobuf_t out, kbnode_t node); @@ -2303,6 +2304,10 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage, && algostr && !strncmp (algostr, "nistp", 5) && !(sl->flags & GCRY_PK_USAGE_ENCR)) sl->flags |= (PUBKEY_ALGO_ECDSA << 8); + else if (algoid == GCRY_PK_ECC + && algostr && !strcmp (algostr, "ed25519") + && !(sl->flags & GCRY_PK_USAGE_ENCR)) + sl->flags = (PUBKEY_ALGO_EDDSA << 8); else sl->flags |= (map_pk_gcry_to_openpgp (algoid) << 8); @@ -3226,11 +3231,14 @@ generate_user_id (KBNODE keyblock, const char *uidstr) * the key; this is currently 4 but can be changed with the flag "v5" * to create a v5 key. */ static gpg_error_t -parse_key_parameter_part (char *string, int for_subkey, int clear_cert, +parse_key_parameter_part (ctrl_t ctrl, + char *string, int for_subkey, int clear_cert, int *r_algo, unsigned int *r_size, unsigned int *r_keyuse, - char const **r_curve, int *r_keyversion) + char const **r_curve, int *r_keyversion, + char **r_keygrip) { + gpg_error_t err; char *flags; int algo; char *endp; @@ -3241,6 +3249,8 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert, int keyversion = 4; int i; const char *s; + int from_card = 0; + char *keygrip = NULL; if (!string || !*string) return 0; /* Success. */ @@ -3250,7 +3260,9 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert, *flags++ = 0; algo = 0; - if (strlen (string) >= 3 && (digitp (string+3) || !string[3])) + if (!ascii_strcasecmp (string, "card")) + from_card = 1; + else if (strlen (string) >= 3 && (digitp (string+3) || !string[3])) { if (!ascii_memcasecmp (string, "rsa", 3)) algo = PUBKEY_ALGO_RSA; @@ -3259,7 +3271,10 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert, else if (!ascii_memcasecmp (string, "elg", 3)) algo = PUBKEY_ALGO_ELGAMAL_E; } - if (algo) + + if (from_card) + ; /* We need the flags before we can figure out the key to use. */ + else if (algo) { if (!string[3]) size = get_keysize_range (algo, NULL, NULL); @@ -3304,7 +3319,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert, keyuse |= PUBKEY_USAGE_AUTH; else if (!ascii_strcasecmp (s, "cert")) keyuse |= PUBKEY_USAGE_CERT; - else if (!ascii_strcasecmp (s, "ecdsa")) + else if (!ascii_strcasecmp (s, "ecdsa") && !from_card) { if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA) algo = PUBKEY_ALGO_ECDSA; @@ -3315,7 +3330,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert, } ecdh_or_ecdsa = 0; } - else if (!ascii_strcasecmp (s, "ecdh")) + else if (!ascii_strcasecmp (s, "ecdh") && !from_card) { if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA) algo = PUBKEY_ALGO_ECDH; @@ -3326,7 +3341,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert, } ecdh_or_ecdsa = 0; } - else if (!ascii_strcasecmp (s, "eddsa")) + else if (!ascii_strcasecmp (s, "eddsa") && !from_card) { /* Not required but we allow it for consistency. */ if (algo == PUBKEY_ALGO_EDDSA) @@ -3354,8 +3369,115 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert, xfree (tokens); } - /* If not yet decided switch between ecdh and ecdsa. */ - if (ecdh_or_ecdsa && keyuse) + /* If not yet decided switch between ecdh and ecdsa unless we want + * to read the algo from the current card. */ + if (from_card) + { + strlist_t keypairlist, sl; + char *reqkeyref; + + if (!keyuse) + keyuse = (for_subkey? PUBKEY_USAGE_ENC + /* */ : (PUBKEY_USAGE_CERT|PUBKEY_USAGE_SIG)); + + /* Access the card to make sure we have one and to show the S/N. */ + { + char *serialno; + + err = agent_scd_serialno (&serialno, NULL); + if (err) + { + log_error (_("error reading the card: %s\n"), gpg_strerror (err)); + return err; + } + if (!opt.quiet) + log_info (_("Serial number of the card: %s\n"), serialno); + xfree (serialno); + } + + err = agent_scd_keypairinfo (ctrl, NULL, &keypairlist); + if (err) + { + log_error (_("error reading the card: %s\n"), gpg_strerror (err)); + return err; + } + agent_scd_getattr_one ((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_CERT)) + ? "$SIGNKEYID":"$ENCRKEYID", &reqkeyref); + + algo = 0; /* Should already be the case. */ + for (sl=keypairlist; sl && !algo; sl = sl->next) + { + gcry_sexp_t s_pkey; + char *algostr = NULL; + enum gcry_pk_algos algoid = 0; + const char *keyref; + + if (!reqkeyref) + continue; /* Card does not provide the info (skip all). */ + + keyref = strchr (sl->d, ' '); + if (!keyref) + continue; /* Ooops. */ + keyref++; + if (strcmp (reqkeyref, keyref)) + continue; /* This is not the requested keyref. */ + + if ((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_CERT)) + && (sl->flags & (GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_CERT))) + ; /* Okay */ + else if ((keyuse & PUBKEY_USAGE_ENC) + && (sl->flags & GCRY_PK_USAGE_ENCR)) + ; /* Okay */ + else + continue; /* Not usable for us. */ + + if (agent_scd_readkey (keyref, &s_pkey)) + continue; /* Could not read the key. */ + + algostr = pubkey_algo_string (s_pkey, &algoid); + gcry_sexp_release (s_pkey); + + + /* Map to OpenPGP algo number. + * We need to tweak the algo in case GCRY_PK_ECC is returned + * because pubkey_algo_string is not aware of the OpenPGP + * algo mapping. FIXME: This is an ugly hack. */ + if (algoid == GCRY_PK_ECC + && algostr && !strncmp (algostr, "nistp", 5) + && !(sl->flags & GCRY_PK_USAGE_ENCR)) + algo = PUBKEY_ALGO_ECDSA; + else if (algoid == GCRY_PK_ECC + && algostr && !strcmp (algostr, "ed25519") + && !(sl->flags & GCRY_PK_USAGE_ENCR)) + algo = PUBKEY_ALGO_EDDSA; + else + algo = map_pk_gcry_to_openpgp (algoid); + + xfree (algostr); + xfree (keygrip); + keygrip = xtrystrdup (sl->d); + if (!keygrip) + { + err = gpg_error_from_syserror (); + xfree (reqkeyref); + free_strlist (keypairlist); + return err; + } + if ((endp = strchr (keygrip, ' '))) + *endp = 0; + } + + xfree (reqkeyref); + free_strlist (keypairlist); + if (!algo || !keygrip) + { + err = gpg_error (GPG_ERR_PUBKEY_ALGO); + log_error ("no usable key on the card: %s\n", gpg_strerror (err)); + xfree (keygrip); + return err; + } + } + else if (ecdh_or_ecdsa && keyuse) algo = (keyuse & PUBKEY_USAGE_ENC)? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA; else if (ecdh_or_ecdsa) algo = for_subkey? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA; @@ -3395,7 +3517,10 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert, || ((keyuse & PUBKEY_USAGE_ENC) && !pubkey_get_nenc (algo)) || (for_subkey && (keyuse & PUBKEY_USAGE_CERT))) - return gpg_error (GPG_ERR_WRONG_KEY_USAGE); + { + xfree (keygrip); + return gpg_error (GPG_ERR_WRONG_KEY_USAGE); + } /* Return values. */ if (r_algo) @@ -3415,6 +3540,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert, *r_size = fixup_keysize (size, algo, 1); } + if (r_keyuse) *r_keyuse = keyuse; if (r_curve) @@ -3422,6 +3548,11 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert, if (r_keyversion) *r_keyversion = keyversion; + if (r_keygrip) + *r_keygrip = keygrip; + else + xfree (keygrip); + return 0; } @@ -3443,7 +3574,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert, * * All strings with an unknown prefix are considered an elliptic * curve. Curves which have no implicit algorithm require that FLAGS - * is given to select whether ECDSA or ECDH is used; this can eoither + * is given to select whether ECDSA or ECDH is used; this can either * be done using an algorithm keyword or usage keywords. * * FLAGS is a comma delimited string of keywords: @@ -3470,16 +3601,19 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert, * */ gpg_error_t -parse_key_parameter_string (const char *string, int part, +parse_key_parameter_string (ctrl_t ctrl, + const char *string, int part, unsigned int suggested_use, int *r_algo, unsigned int *r_size, unsigned int *r_keyuse, char const **r_curve, int *r_version, + char **r_keygrip, int *r_subalgo, unsigned int *r_subsize, unsigned int *r_subkeyuse, char const **r_subcurve, - int *r_subversion) + int *r_subversion, + char **r_subkeygrip) { gpg_error_t err = 0; char *primary, *secondary; @@ -3494,6 +3628,8 @@ parse_key_parameter_string (const char *string, int part, *r_curve = NULL; if (r_version) *r_version = 4; + if (r_keygrip) + *r_keygrip = NULL; if (r_subalgo) *r_subalgo = 0; if (r_subsize) @@ -3504,6 +3640,8 @@ parse_key_parameter_string (const char *string, int part, *r_subcurve = NULL; if (r_subversion) *r_subversion = 4; + if (r_subkeygrip) + *r_subkeygrip = NULL; if (!string || !*string || !ascii_strcasecmp (string, "default") || !strcmp (string, "-")) @@ -3511,6 +3649,8 @@ parse_key_parameter_string (const char *string, int part, else if (!ascii_strcasecmp (string, "future-default") || !ascii_strcasecmp (string, "futuredefault")) string = FUTURE_STD_KEY_PARAM; + else if (!ascii_strcasecmp (string, "card")) + string = "card/cert,sign+card/encr"; primary = xstrdup (string); secondary = strchr (primary, '+'); @@ -3518,11 +3658,14 @@ parse_key_parameter_string (const char *string, int part, *secondary++ = 0; if (part == -1 || part == 0) { - err = parse_key_parameter_part (primary, 0, 0, r_algo, r_size, - r_keyuse, r_curve, r_version); + err = parse_key_parameter_part (ctrl, primary, + 0, 0, r_algo, r_size, + r_keyuse, r_curve, r_version, r_keygrip); if (!err && part == -1) - err = parse_key_parameter_part (secondary, 1, 0, r_subalgo, r_subsize, - r_subkeyuse, r_subcurve, r_subversion); + err = parse_key_parameter_part (ctrl, secondary, + 1, 0, r_subalgo, r_subsize, + r_subkeyuse, r_subcurve, r_subversion, + r_subkeygrip); } else if (part == 1) { @@ -3534,18 +3677,21 @@ parse_key_parameter_string (const char *string, int part, * to force clearing the cert usage. */ if (secondary) { - err = parse_key_parameter_part (secondary, 1, 0, + err = parse_key_parameter_part (ctrl, secondary, + 1, 0, r_algo, r_size, r_keyuse, r_curve, - r_version); + r_version, r_keygrip); if (!err && suggested_use && r_keyuse && !(suggested_use & *r_keyuse)) - err = parse_key_parameter_part (primary, 1, 1 /*(clear cert)*/, + err = parse_key_parameter_part (ctrl, primary, + 1, 1 /*(clear cert)*/, r_algo, r_size, r_keyuse, r_curve, - r_version); + r_version, r_keygrip); } else - err = parse_key_parameter_part (primary, 1, 0, + err = parse_key_parameter_part (ctrl, primary, + 1, 0, r_algo, r_size, r_keyuse, r_curve, - r_version); + r_version, r_keygrip); } xfree (primary); @@ -3610,7 +3756,7 @@ get_parameter_passphrase (struct para_data_s *para) static int -get_parameter_algo( struct para_data_s *para, enum para_name key, +get_parameter_algo (ctrl_t ctrl, struct para_data_s *para, enum para_name key, int *r_default) { int i; @@ -3632,9 +3778,9 @@ get_parameter_algo( struct para_data_s *para, enum para_name key, * for the curve etc. That is a ugly but demanded for backward * compatibility with the batch key generation. It would be * better to make full use of parse_key_parameter_string. */ - parse_key_parameter_string (NULL, 0, 0, - &i, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL); + parse_key_parameter_string (ctrl, NULL, 0, 0, + &i, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL); if (r_default) *r_default = 1; } @@ -3831,7 +3977,7 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname, r = get_parameter( para, pKEYTYPE ); if(r) { - algo = get_parameter_algo (para, pKEYTYPE, &is_default); + algo = get_parameter_algo (ctrl, para, pKEYTYPE, &is_default); if (openpgp_pk_test_algo2 (algo, PUBKEY_USAGE_SIG)) { log_error ("%s:%d: invalid algorithm\n", fname, r->lnr ); @@ -3873,7 +4019,7 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname, r = get_parameter( para, pSUBKEYTYPE ); if(r) { - algo = get_parameter_algo (para, pSUBKEYTYPE, &is_default); + algo = get_parameter_algo (ctrl, para, pSUBKEYTYPE, &is_default); if (openpgp_pk_test_algo (algo)) { log_error ("%s:%d: invalid algorithm\n", fname, r->lnr ); @@ -4241,7 +4387,7 @@ read_parameter_file (ctrl_t ctrl, const char *fname ) static struct para_data_s * quickgen_set_para (struct para_data_s *para, int for_subkey, int algo, int nbits, const char *curve, unsigned int use, - int version) + int version, const char *keygrip) { struct para_data_s *r; @@ -4263,7 +4409,15 @@ quickgen_set_para (struct para_data_s *para, int for_subkey, r->next = para; para = r; - if (curve) + if (keygrip) + { + r = xmalloc_clear (sizeof *r + strlen (keygrip)); + r->key = for_subkey? pSUBKEYGRIP : pKEYGRIP; + strcpy (r->u.value, keygrip); + r->next = para; + para = r; + } + else if (curve) { r = xmalloc_clear (sizeof *r + strlen (curve)); r->key = for_subkey? pSUBKEYCURVE : pKEYCURVE; @@ -4376,7 +4530,8 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr, if ((!*algostr || !ascii_strcasecmp (algostr, "default") || !ascii_strcasecmp (algostr, "future-default") - || !ascii_strcasecmp (algostr, "futuredefault")) + || !ascii_strcasecmp (algostr, "futuredefault") + || !ascii_strcasecmp (algostr, "card")) && (!*usagestr || !ascii_strcasecmp (usagestr, "default") || !strcmp (usagestr, "-"))) { @@ -4385,23 +4540,25 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr, unsigned int size, subsize; unsigned int keyuse, subkeyuse; const char *curve, *subcurve; + char *keygrip, *subkeygrip; - err = parse_key_parameter_string (algostr, -1, 0, + err = parse_key_parameter_string (ctrl, algostr, -1, 0, &algo, &size, &keyuse, &curve, &version, + &keygrip, &subalgo, &subsize, &subkeyuse, - &subcurve, &subversion); + &subcurve, &subversion, &subkeygrip); if (err) { log_error (_("Key generation failed: %s\n"), gpg_strerror (err)); goto leave; } - para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version); + para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version, + keygrip); if (subalgo) para = quickgen_set_para (para, 1, subalgo, subsize, subcurve, subkeyuse, - subversion); - + subversion, subkeygrip); if (*expirestr) { u32 expire; @@ -4419,6 +4576,9 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr, r->next = para; para = r; } + + xfree (keygrip); + xfree (subkeygrip); } else { @@ -4428,22 +4588,26 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr, u32 expire; unsigned int nbits; const char *curve; + char *keygrip; err = parse_algo_usage_expire (ctrl, 0, algostr, usagestr, expirestr, &algo, &use, &expire, &nbits, &curve, - &version); + &version, &keygrip); if (err) { log_error (_("Key generation failed: %s\n"), gpg_strerror (err) ); goto leave; } - para = quickgen_set_para (para, 0, algo, nbits, curve, use, version); + para = quickgen_set_para (para, 0, algo, nbits, curve, use, version, + keygrip); r = xmalloc_clear (sizeof *r + 20); r->key = pKEYEXPIRE; r->u.expire = expire; r->next = para; para = r; + + xfree (keygrip); } /* If the pinentry loopback mode is not and we have a static @@ -4756,6 +4920,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname, unsigned int size, subsize; unsigned int keyuse, subkeyuse; const char *curve, *subcurve; + char *keygrip, *subkeygrip; tty_printf ( _("Note: Use \"%s %s\"" " for a full featured key generation dialog.\n"), @@ -4766,22 +4931,27 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname, #endif , "--full-generate-key" ); - err = parse_key_parameter_string (NULL, -1, 0, + err = parse_key_parameter_string (ctrl, NULL, -1, 0, &algo, &size, &keyuse, &curve, &version, + &keygrip, &subalgo, &subsize, - &subkeyuse, &subcurve, &subversion); + &subkeyuse, &subcurve, &subversion, + &subkeygrip); if (err) { log_error (_("Key generation failed: %s\n"), gpg_strerror (err)); return; } - para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version); + para = quickgen_set_para (para, 0, + algo, size, curve, keyuse, + version, keygrip); if (subalgo) para = quickgen_set_para (para, 1, subalgo, subsize, subcurve, subkeyuse, - subversion); - + subversion, subkeygrip); + xfree (keygrip); + xfree (subkeygrip); } @@ -5065,7 +5235,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, node of the subkey but that is more work than just to pass the current timestamp. */ - algo = get_parameter_algo( para, pKEYTYPE, NULL ); + algo = get_parameter_algo (ctrl, para, pKEYTYPE, NULL ); expire = get_parameter_u32( para, pKEYEXPIRE ); key_from_hexgrip = get_parameter_value (para, pKEYGRIP); @@ -5128,7 +5298,8 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, if (!err && card && get_parameter (para, pAUTHKEYTYPE)) { - err = gen_card_key (3, get_parameter_algo( para, pAUTHKEYTYPE, NULL ), + err = gen_card_key (3, get_parameter_algo (ctrl, para, + pAUTHKEYTYPE, NULL ), 0, pub_root, ×tamp, expire, keygen_flags); if (!err) err = write_keybinding (ctrl, pub_root, pri_psk, NULL, @@ -5137,7 +5308,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, if (!err && get_parameter (para, pSUBKEYTYPE)) { - int subkey_algo = get_parameter_algo (para, pSUBKEYTYPE, NULL); + int subkey_algo = get_parameter_algo (ctrl, para, pSUBKEYTYPE, NULL); s = NULL; key_from_hexgrip = get_parameter_value (para, pSUBKEYGRIP); @@ -5232,7 +5403,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, int no_enc_rsa; PKT_public_key *pk; - no_enc_rsa = ((get_parameter_algo (para, pKEYTYPE, NULL) + no_enc_rsa = ((get_parameter_algo (ctrl, para, pKEYTYPE, NULL) == PUBKEY_ALGO_RSA) && get_parameter_uint (para, pKEYUSAGE) && !((get_parameter_uint (para, pKEYUSAGE) @@ -5265,7 +5436,8 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, if (!opt.batch - && (get_parameter_algo (para, pKEYTYPE, NULL) == PUBKEY_ALGO_DSA + && (get_parameter_algo (ctrl, para, + pKEYTYPE, NULL) == PUBKEY_ALGO_DSA || no_enc_rsa ) && !get_parameter (para, pSUBKEYTYPE) ) { @@ -5305,7 +5477,7 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey, const char *expirestr, int *r_algo, unsigned int *r_usage, u32 *r_expire, unsigned int *r_nbits, const char **r_curve, - int *r_version) + int *r_version, char **r_keygrip) { gpg_error_t err; int algo; @@ -5316,6 +5488,8 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey, const char *curve = NULL; *r_curve = NULL; + if (r_keygrip) + *r_keygrip = NULL; nbits = 0; @@ -5328,12 +5502,20 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey, return gpg_error (GPG_ERR_NOT_IMPLEMENTED); } - err = parse_key_parameter_string (algostr, for_subkey? 1 : 0, + err = parse_key_parameter_string (ctrl, algostr, for_subkey? 1 : 0, usagestr? parse_usagestr (usagestr):0, &algo, &nbits, &use, &curve, &version, - NULL, NULL, NULL, NULL, NULL); + r_keygrip, + NULL, NULL, NULL, NULL, NULL, NULL); if (err) - return err; + { + if (r_keygrip) + { + xfree (*r_keygrip); + *r_keygrip = NULL; + } + return err; + } /* Parse the usage string. */ if (!usagestr || !*usagestr @@ -5342,7 +5524,14 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey, else if ((wantuse = parse_usagestr (usagestr)) != -1) use = wantuse; else - return gpg_error (GPG_ERR_INV_VALUE); + { + if (r_keygrip) + { + xfree (*r_keygrip); + *r_keygrip = NULL; + } + return gpg_error (GPG_ERR_INV_VALUE); + } /* Make sure a primary key has the CERT usage. */ if (!for_subkey) @@ -5356,12 +5545,26 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey, || ((use & PUBKEY_USAGE_ENC) && !pubkey_get_nenc (algo)) || (for_subkey && (use & PUBKEY_USAGE_CERT))) - return gpg_error (GPG_ERR_WRONG_KEY_USAGE); + { + if (r_keygrip) + { + xfree (*r_keygrip); + *r_keygrip = NULL; + } + return gpg_error (GPG_ERR_WRONG_KEY_USAGE); + } /* Parse the expire string. */ expire = parse_expire_string (expirestr); if (expire == (u32)-1 ) - return gpg_error (GPG_ERR_INV_VALUE); + { + if (r_keygrip) + { + xfree (*r_keygrip); + *r_keygrip = NULL; + } + return gpg_error (GPG_ERR_INV_VALUE); + } if (curve) *r_curve = curve; @@ -5483,7 +5686,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr, err = parse_algo_usage_expire (ctrl, 1, algostr, usagestr, expirestr, &algo, &use, &expire, &nbits, &curve, - &version); + &version, &key_from_hexgrip); if (err) goto leave;