From 48251cf9a7d3776667342f4705ac3de89bd75534 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 3 Jun 2020 16:22:42 +0200 Subject: [PATCH] gpg: Improve generation of keys stored on card (brainpool,cv25519). * g10/keygen.c (ask_key_flags_with_mask): Allow more than ECDH for legacy curves. (ask_algo): Tweak mapping of ECC to OpenPGP algos (parse_key_parameter_part): Ditto. (generate_subkeypair): Create the subkey with the time stored on the card. -- This fixes two problems with generating keys from a card: 1. The key usage is now set correctly for brainpool curves. 2. The add-key and --quick-add-key commands now also take the creation time from the time stored on the card. Without that we would need to update the creation time and fingerprint already stored on the card which is a no-go if another key has already been created using that on-card key. Note: To create a key on a card without an OpenPGP keyblock use gpg-card. Signed-off-by: Werner Koch --- g10/keygen.c | 76 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/g10/keygen.c b/g10/keygen.c index 4917a36a9..ab53a6573 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1929,8 +1929,14 @@ ask_key_flags_with_mask (int algo, int subkey, unsigned int current, } /* Mask the possible usage flags. This is for example used for a - * card based key. */ + * card based key. For ECDH we need to allows additional usages if + * they are provided. */ possible = (openpgp_pk_algo_usage (algo) & mask); + if (algo == PUBKEY_ALGO_ECDH) + possible |= (current & (PUBKEY_USAGE_ENC + |PUBKEY_USAGE_CERT + |PUBKEY_USAGE_SIG + |PUBKEY_USAGE_AUTH)); /* However, only primary keys may certify. */ if (subkey) @@ -1948,9 +1954,10 @@ ask_key_flags_with_mask (int algo, int subkey, unsigned int current, { tty_printf("\n"); tty_printf(_("Possible actions for this %s key: "), - (algo == PUBKEY_ALGO_ECDSA + (algo == PUBKEY_ALGO_ECDH + || algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA) - ? "ECDSA/EdDSA" : openpgp_pk_algo_name (algo)); + ? "ECC" : openpgp_pk_algo_name (algo)); print_key_flags(possible); tty_printf("\n"); tty_printf(_("Current allowed actions: ")); @@ -2076,7 +2083,7 @@ check_keygrip (ctrl_t ctrl, const char *hexgrip) * keygrip is then stored at this address. The caller needs to free * it. If R_CARDKEY is not NULL and the keygrip has been taken from * an active card, true is stored there; if R_KEYTIME is not NULL the - * cretion time of that key is then stored there. */ + * creation time of that key is then stored there. */ static int ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage, char **r_keygrip, int *r_cardkey, u32 *r_keytime) @@ -2308,18 +2315,24 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage, gcry_sexp_release (s_pkey); } - /* 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) - && !(kpi->usage & GCRY_PK_USAGE_ENCR)) - kpi->algo = PUBKEY_ALGO_ECDSA; - else if (algoid == GCRY_PK_ECC - && algostr && !strcmp (algostr, "ed25519") - && !(kpi->usage & GCRY_PK_USAGE_ENCR)) - kpi->algo = PUBKEY_ALGO_EDDSA; + /* 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. We need to + * distinguish between ECDH and ECDSA but we can do + * that only if we got usage flags. + * Note: Keep this in sync with parse_key_parameter_part. + */ + if (algoid == GCRY_PK_ECC && algostr) + { + if (!strcmp (algostr, "ed25519")) + kpi->algo = PUBKEY_ALGO_EDDSA; + else if (!strcmp (algostr, "cv25519")) + kpi->algo = PUBKEY_ALGO_ECDH; + else if ((kpi->usage & GCRY_PK_USAGE_ENCR)) + kpi->algo = PUBKEY_ALGO_ECDH; + else + kpi->algo = PUBKEY_ALGO_ECDSA; + } else kpi->algo = map_gcry_pk_to_openpgp (algoid); @@ -3456,17 +3469,23 @@ parse_key_parameter_part (ctrl_t ctrl, 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) - && !(kpi->usage & GCRY_PK_USAGE_ENCR)) - algo = PUBKEY_ALGO_ECDSA; - else if (algoid == GCRY_PK_ECC - && algostr && !strcmp (algostr, "ed25519") - && !(kpi->usage & GCRY_PK_USAGE_ENCR)) - algo = PUBKEY_ALGO_EDDSA; + * 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. We need to + * distinguish between ECDH and ECDSA but we can do + * that only if we got usage flags. + * Note: Keep this in sync with ask_algo. */ + if (algoid == GCRY_PK_ECC && algostr) + { + if (!strcmp (algostr, "ed25519")) + algo = PUBKEY_ALGO_EDDSA; + else if (!strcmp (algostr, "cv25519")) + algo = PUBKEY_ALGO_ECDH; + else if ((kpi->usage & GCRY_PK_USAGE_ENCR)) + algo = PUBKEY_ALGO_ECDH; + else + algo = PUBKEY_ALGO_ECDSA; + } else algo = map_gcry_pk_to_openpgp (algoid); @@ -5777,7 +5796,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr, if (interactive) { - algo = ask_algo (ctrl, 1, NULL, &use, &key_from_hexgrip, &cardkey, NULL); + algo = ask_algo (ctrl, 1, NULL, &use, &key_from_hexgrip, &cardkey, + &keytime); log_assert (algo); if (key_from_hexgrip)