summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app-crypt/gnupg/files/gnupg-2.2.42-bug923248-insecure-backup.patch')
-rw-r--r--app-crypt/gnupg/files/gnupg-2.2.42-bug923248-insecure-backup.patch292
1 files changed, 292 insertions, 0 deletions
diff --git a/app-crypt/gnupg/files/gnupg-2.2.42-bug923248-insecure-backup.patch b/app-crypt/gnupg/files/gnupg-2.2.42-bug923248-insecure-backup.patch
new file mode 100644
index 000000000000..76d6d94c40b1
--- /dev/null
+++ b/app-crypt/gnupg/files/gnupg-2.2.42-bug923248-insecure-backup.patch
@@ -0,0 +1,292 @@
+https://bugs.gentoo.org/923248
+https://dev.gnupg.org/T6944
+https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=commit;h=3b69d8bf7146b8d10737d0cfea9c97affc60ad73
+
+From 3b69d8bf7146b8d10737d0cfea9c97affc60ad73 Mon Sep 17 00:00:00 2001
+From: Werner Koch <wk@gnupg.org>
+Date: Wed, 24 Jan 2024 11:29:24 +0100
+Subject: [PATCH] gpg: Fix leftover unprotected card backup key.
+
+* agent/command.c (cmd_learn): Add option --reallyforce.
+* agent/findkey.c (agent_write_private_key): Implement reallyforce.
+Also add arg reallyforce and pass it along the call chain.
+
+* g10/call-agent.c (agent_scd_learn): Pass --reallyforce with a
+special force value.
+* g10/keygen.c (card_store_key_with_backup): Use that force value.
+--
+
+This was a regression in 2.2.42. We took the easy path to fix it by
+getting the behaviour back to what we did prior to 2.2.42. With GnuPG
+2.4.4 we use an entire different and safer approach by introducing an
+ephemeral private key store.
+
+GnuPG-bug-id: 6944
+--- a/agent/agent.h
++++ b/agent/agent.h
+@@ -422,7 +422,8 @@ void start_command_handler_ssh (ctrl_t, gnupg_fd_t);
+ gpg_error_t agent_modify_description (const char *in, const char *comment,
+ const gcry_sexp_t key, char **result);
+ int agent_write_private_key (const unsigned char *grip,
+- const void *buffer, size_t length, int force,
++ const void *buffer, size_t length,
++ int force, int reallyforce,
+ const char *serialno, const char *keyref,
+ const char *dispserialno, time_t timestamp);
+ gpg_error_t agent_key_from_file (ctrl_t ctrl,
+@@ -548,6 +549,7 @@ gpg_error_t s2k_hash_passphrase (const char *passphrase, int hashalgo,
+ gpg_error_t agent_write_shadow_key (const unsigned char *grip,
+ const char *serialno, const char *keyid,
+ const unsigned char *pkbuf, int force,
++ int reallyforce,
+ const char *dispserialno);
+
+
+@@ -628,7 +630,8 @@ void agent_card_killscd (void);
+
+
+ /*-- learncard.c --*/
+-int agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force);
++int agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context,
++ int force, int reallyforce);
+
+
+ /*-- cvt-openpgp.c --*/
+--- a/agent/command-ssh.c
++++ b/agent/command-ssh.c
+@@ -2499,7 +2499,7 @@ card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn)
+
+ /* (Shadow)-key is not available in our key storage. */
+ agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno);
+- err = agent_write_shadow_key (grip, serialno, authkeyid, pkbuf, 0,
++ err = agent_write_shadow_key (grip, serialno, authkeyid, pkbuf, 0, 0,
+ dispserialno);
+ xfree (dispserialno);
+ if (err)
+@@ -3159,7 +3159,7 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
+
+ /* Store this key to our key storage. We do not store a creation
+ * timestamp because we simply do not know. */
+- err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0,
++ err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0, 0,
+ NULL, NULL, NULL, 0);
+ if (err)
+ goto out;
+--- a/agent/command.c
++++ b/agent/command.c
+@@ -1042,7 +1042,7 @@ cmd_readkey (assuan_context_t ctx, char *line)
+ /* Shadow-key is or is not available in our key storage. In
+ * any case we need to check whether we need to update with
+ * a new display-s/n or whatever. */
+- rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0,
++ rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0, 0,
+ dispserialno);
+ if (rc)
+ goto leave;
+@@ -1855,16 +1855,18 @@ cmd_learn (assuan_context_t ctx, char *line)
+ {
+ ctrl_t ctrl = assuan_get_pointer (ctx);
+ gpg_error_t err;
+- int send, sendinfo, force;
++ int send, sendinfo, force, reallyforce;
+
+ send = has_option (line, "--send");
+ sendinfo = send? 1 : has_option (line, "--sendinfo");
+ force = has_option (line, "--force");
++ reallyforce = has_option (line, "--reallyforce");
+
+ if (ctrl->restricted)
+ return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
+
+- err = agent_handle_learn (ctrl, send, sendinfo? ctx : NULL, force);
++ err = agent_handle_learn (ctrl, send, sendinfo? ctx : NULL,
++ force, reallyforce);
+ return leave_cmd (ctx, err);
+ }
+
+@@ -2427,11 +2429,11 @@ cmd_import_key (assuan_context_t ctx, char *line)
+ err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
+ ctrl->s2k_count);
+ if (!err)
+- err = agent_write_private_key (grip, finalkey, finalkeylen, force,
++ err = agent_write_private_key (grip, finalkey, finalkeylen, force, 0,
+ NULL, NULL, NULL, opt_timestamp);
+ }
+ else
+- err = agent_write_private_key (grip, key, realkeylen, force,
++ err = agent_write_private_key (grip, key, realkeylen, force, 0,
+ NULL, NULL, NULL, opt_timestamp);
+
+ leave:
+--- a/agent/cvt-openpgp.c
++++ b/agent/cvt-openpgp.c
+@@ -1070,7 +1070,7 @@ convert_from_openpgp_native (ctrl_t ctrl,
+ &protectedkey, &protectedkeylen,
+ ctrl->s2k_count))
+ agent_write_private_key (grip, protectedkey, protectedkeylen,
+- 1/*force*/, NULL, NULL, NULL, 0);
++ 1/*force*/, 0, NULL, NULL, NULL, 0);
+ xfree (protectedkey);
+ }
+ else
+@@ -1079,7 +1079,7 @@ convert_from_openpgp_native (ctrl_t ctrl,
+ agent_write_private_key (grip,
+ *r_key,
+ gcry_sexp_canon_len (*r_key, 0, NULL,NULL),
+- 1/*force*/, NULL, NULL, NULL, 0);
++ 1/*force*/, 0, NULL, NULL, NULL, 0);
+ }
+ }
+
+--- a/agent/findkey.c
++++ b/agent/findkey.c
+@@ -82,7 +82,8 @@ fname_from_keygrip (const unsigned char *grip, int for_new)
+ * recorded as creation date. */
+ int
+ agent_write_private_key (const unsigned char *grip,
+- const void *buffer, size_t length, int force,
++ const void *buffer, size_t length,
++ int force, int reallyforce,
+ const char *serialno, const char *keyref,
+ const char *dispserialno,
+ time_t timestamp)
+@@ -165,10 +166,13 @@ agent_write_private_key (const unsigned char *grip,
+ /* Check that we do not update a regular key with a shadow key. */
+ if (is_regular && gpg_err_code (is_shadowed_key (key)) == GPG_ERR_TRUE)
+ {
+- log_info ("updating regular key file '%s'"
+- " by a shadow key inhibited\n", oldfname);
+- err = 0; /* Simply ignore the error. */
+- goto leave;
++ if (!reallyforce)
++ {
++ log_info ("updating regular key file '%s'"
++ " by a shadow key inhibited\n", oldfname);
++ err = 0; /* Simply ignore the error. */
++ goto leave;
++ }
+ }
+ /* Check that we update a regular key only in force mode. */
+ if (is_regular && !force)
+@@ -1704,12 +1708,13 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text,
+ * Shadow key is created by an S-expression public key in PKBUF and
+ * card's SERIALNO and the IDSTRING. With FORCE passed as true an
+ * existing key with the given GRIP will get overwritten. If
+- * DISPSERIALNO is not NULL the human readable s/n will also be
+- * recorded in the key file. */
++ * REALLYFORCE is also true, even a private key will be overwritten by
++ * a shadown key. If DISPSERIALNO is not NULL the human readable s/n
++ * will also be recorded in the key file. */
+ gpg_error_t
+ agent_write_shadow_key (const unsigned char *grip,
+ const char *serialno, const char *keyid,
+- const unsigned char *pkbuf, int force,
++ const unsigned char *pkbuf, int force, int reallyforce,
+ const char *dispserialno)
+ {
+ gpg_error_t err;
+@@ -1737,7 +1742,7 @@ agent_write_shadow_key (const unsigned char *grip,
+ }
+
+ len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
+- err = agent_write_private_key (grip, shdkey, len, force,
++ err = agent_write_private_key (grip, shdkey, len, force, reallyforce,
+ serialno, keyid, dispserialno, 0);
+ xfree (shdkey);
+ if (err)
+--- a/agent/genkey.c
++++ b/agent/genkey.c
+@@ -69,7 +69,7 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
+ buf = p;
+ }
+
+- rc = agent_write_private_key (grip, buf, len, force,
++ rc = agent_write_private_key (grip, buf, len, force, 0,
+ NULL, NULL, NULL, timestamp);
+ xfree (buf);
+ return rc;
+--- a/agent/learncard.c
++++ b/agent/learncard.c
+@@ -297,9 +297,12 @@ send_cert_back (ctrl_t ctrl, const char *id, void *assuan_context)
+ }
+
+ /* Perform the learn operation. If ASSUAN_CONTEXT is not NULL and
+- SEND is true all new certificates are send back via Assuan. */
++ SEND is true all new certificates are send back via Assuan. If
++ REALLYFORCE is true a private key will be overwritten by a stub
++ key. */
+ int
+-agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
++agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context,
++ int force, int reallyforce)
+ {
+ int rc;
+ struct kpinfo_cb_parm_s parm;
+@@ -414,7 +417,7 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
+
+ agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno);
+ rc = agent_write_shadow_key (grip, serialno, item->id, pubkey,
+- force, dispserialno);
++ force, reallyforce, dispserialno);
+ xfree (dispserialno);
+ }
+ xfree (pubkey);
+--- a/agent/protect-tool.c
++++ b/agent/protect-tool.c
+@@ -807,13 +807,15 @@ agent_askpin (ctrl_t ctrl,
+ * to stdout. */
+ int
+ agent_write_private_key (const unsigned char *grip,
+- const void *buffer, size_t length, int force,
++ const void *buffer, size_t length,
++ int force, int reallyforce,
+ const char *serialno, const char *keyref,
+ const char *dispserialno, time_t timestamp)
+ {
+ char hexgrip[40+4+1];
+ char *p;
+
++ (void)reallyforce;
+ (void)force;
+ (void)timestamp;
+ (void)serialno;
+--- a/g10/call-agent.c
++++ b/g10/call-agent.c
+@@ -745,6 +745,11 @@ learn_status_cb (void *opaque, const char *line)
+ * card-util.c
+ * keyedit_menu
+ * card_store_key_with_backup (Woth force to remove secret key data)
++ *
++ * If force has the value 2 the --reallyforce option is also used.
++ * This is to make sure the sshadow key overwrites the private key.
++ * Note that this option is gnupg 2.2 specific because since 2.4.4 an
++ * ephemeral private key store is used instead.
+ */
+ int
+ agent_scd_learn (struct agent_card_info_s *info, int force)
+@@ -764,6 +769,7 @@ agent_scd_learn (struct agent_card_info_s *info, int force)
+
+ parm.ctx = agent_ctx;
+ rc = assuan_transact (agent_ctx,
++ force == 2? "LEARN --sendinfo --force --reallyforce" :
+ force ? "LEARN --sendinfo --force" : "LEARN --sendinfo",
+ dummy_data_cb, NULL, default_inq_cb, &parm,
+ learn_status_cb, info);
+--- a/g10/keygen.c
++++ b/g10/keygen.c
+@@ -5201,8 +5201,11 @@ card_store_key_with_backup (ctrl_t ctrl, PKT_public_key *sub_psk,
+ if (err)
+ log_error ("writing card key to backup file: %s\n", gpg_strerror (err));
+ else
+- /* Remove secret key data in agent side. */
+- agent_scd_learn (NULL, 1);
++ {
++ /* Remove secret key data in agent side. We use force 2 here to
++ * allow overwriting of the temporary private key. */
++ agent_scd_learn (NULL, 2);
++ }
+
+ leave:
+ xfree (ecdh_param_str);
+--
+2.30.2