From ead2982286f8ae94e96c0da09c6ed8c294711a47 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 22 Jan 2024 16:52:22 +0100 Subject: [PATCH] gpg: Use ephemeral mode for generating card keys. * g10/call-agent.c (agent_set_ephemeral_mode): New. * g10/keyedit.c (keyedit_menu) : Switch to ephemeral mode. * g10/keygen.c (do_generate_keypair): Switch to ephemeral mode for card keys with backup. -- GnuPG-bug-id: 6944 --- g10/call-agent.c | 39 +++++++++++++++++++++++++++++++++++++++ g10/call-agent.h | 4 ++++ g10/keyedit.c | 32 ++++++++++++++++++++++---------- g10/keygen.c | 48 +++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 104 insertions(+), 19 deletions(-) diff --git a/g10/call-agent.c b/g10/call-agent.c index 744c0fcb8..daf12fae7 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -3243,6 +3243,45 @@ agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc, int verify, } +/* Enable or disable the ephemeral mode. In ephemeral mode keys are + * created,searched and used in a per-session key store and not in the + * on-disk file. Set ENABLE to 1 to enable this mode, to 0 to disable + * this mode and to -1 to only query the current mode. If R_PREVIOUS + * is given the previously used state of the ephemeral mode is stored + * at that address. */ +gpg_error_t +agent_set_ephemeral_mode (ctrl_t ctrl, int enable, int *r_previous) +{ + gpg_error_t err; + + err = start_agent (ctrl, 0); + if (err) + goto leave; + + if (r_previous) + { + err = assuan_transact (agent_ctx, "GETINFO ephemeral", + NULL, NULL, NULL, NULL, NULL, NULL); + if (!err) + *r_previous = 1; + else if (gpg_err_code (err) == GPG_ERR_FALSE) + *r_previous = 0; + else + goto leave; + } + + /* Skip setting if we are only querying or if the mode is already set. */ + if (enable == -1 || (r_previous && !!*r_previous == !!enable)) + err = 0; + else + err = assuan_transact (agent_ctx, + enable? "OPTION ephemeral=1" : "OPTION ephemeral=0", + NULL, NULL, NULL, NULL, NULL, NULL); + leave: + return err; +} + + /* Return the version reported by gpg-agent. */ gpg_error_t agent_get_version (ctrl_t ctrl, char **r_version) diff --git a/g10/call-agent.h b/g10/call-agent.h index 45af95422..1e72dc03f 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -247,6 +247,10 @@ gpg_error_t agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, gpg_error_t agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc, int verify, char **cache_nonce_addr, char **passwd_nonce_addr); + +/* Set or get the ephemeral mode. */ +gpg_error_t agent_set_ephemeral_mode (ctrl_t ctrl, int enable, int *r_previous); + /* Get the version reported by gpg-agent. */ gpg_error_t agent_get_version (ctrl_t ctrl, char **r_version); diff --git a/g10/keyedit.c b/g10/keyedit.c index a12546f71..cae0f7841 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -1905,6 +1905,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, PACKET *pkt; IOBUF a; struct parse_packet_ctx_s parsectx; + int lastmode; if (!*arg_string) { @@ -1959,17 +1960,28 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, xfree (fname); node = new_kbnode (pkt); - /* Transfer it to gpg-agent which handles secret keys. */ - err = transfer_secret_keys (ctrl, NULL, node, 1, 1, 0); - - /* Treat the pkt as a public key. */ - pkt->pkttype = PKT_PUBLIC_KEY; - - /* Ask gpg-agent to store the secret key to card. */ - if (card_store_subkey (node, 0, NULL)) + err = agent_set_ephemeral_mode (ctrl, 1, &lastmode); + if (err) + log_error ("error switching to ephemeral mode: %s\n", + gpg_strerror (err)); + else { - redisplay = 1; - sec_shadowing = 1; + /* Transfer it to gpg-agent which handles secret keys. */ + err = transfer_secret_keys (ctrl, NULL, node, 1, 1, 0); + if (!err) + { + /* Treat the pkt as a public key. */ + pkt->pkttype = PKT_PUBLIC_KEY; + + /* Ask gpg-agent to store the secret key to card. */ + if (card_store_subkey (node, 0, NULL)) + { + redisplay = 1; + sec_shadowing = 1; + } + } + if (!lastmode && agent_set_ephemeral_mode (ctrl, 0, NULL)) + log_error ("error clearing the ephemeral mode\n"); } release_kbnode (node); } diff --git a/g10/keygen.c b/g10/keygen.c index 886c3b007..b263a47de 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -5754,7 +5754,6 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, if (!err && get_parameter (para, pSUBKEYTYPE)) { - const char *cardbackupkey = NULL; int subkey_algo = get_parameter_algo (ctrl, para, pSUBKEYTYPE, NULL); key_from_hexgrip = get_parameter_value (para, pSUBKEYGRIP); @@ -5769,22 +5768,57 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, pub_root, subkeytimestamp, get_parameter_u32 (para, pSUBKEYEXPIRE), 1, &keygen_flags); - else if (!card - || (cardbackupkey = get_parameter_value (para, pCARDBACKUPKEY))) + else if (get_parameter_value (para, pCARDBACKUPKEY)) { + int lastmode; unsigned int mykeygenflags = KEYGEN_FLAG_NO_PROTECTION; + err = agent_set_ephemeral_mode (ctrl, 1, &lastmode); + if (err) + log_error ("error switching to ephemeral mode: %s\n", + gpg_strerror (err)); + else + { + err = do_create (subkey_algo, + get_parameter_uint (para, pSUBKEYLENGTH), + get_parameter_value (para, pSUBKEYCURVE), + pub_root, + subkeytimestamp, + get_parameter_u32 (para, pSUBKEYEXPIRE), 1, + &mykeygenflags, + get_parameter_passphrase (para), + &cache_nonce, NULL, + NULL, NULL); + /* Get the pointer to the generated public subkey packet. */ + if (!err) + { + kbnode_t node; + + for (node = pub_root; node; node = node->next) + if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) + sub_psk = node->pkt->pkt.public_key; + log_assert (sub_psk); + err = card_store_key_with_backup (ctrl, + sub_psk, gnupg_homedir ()); + } + + /* Reset the ephemeral mode as needed. */ + if (!lastmode && agent_set_ephemeral_mode (ctrl, 0, NULL)) + log_error ("error clearing the ephemeral mode\n"); + } + } + else if (!card) + { err = do_create (subkey_algo, get_parameter_uint (para, pSUBKEYLENGTH), get_parameter_value (para, pSUBKEYCURVE), pub_root, subkeytimestamp, get_parameter_u32 (para, pSUBKEYEXPIRE), 1, - cardbackupkey? &mykeygenflags : &keygen_flags, + &keygen_flags, get_parameter_passphrase (para), &cache_nonce, NULL, NULL, NULL); - /* Get the pointer to the generated public subkey packet. */ if (!err) { kbnode_t node; @@ -5793,10 +5827,6 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) sub_psk = node->pkt->pkt.public_key; log_assert (sub_psk); - - if (cardbackupkey) - err = card_store_key_with_backup (ctrl, - sub_psk, gnupg_homedir ()); } } else