commit:     794b312233b33ce315807bb305e0db42d530dfe7
Author:     Sam James <sam <AT> gentoo <DOT> org>
AuthorDate: Mon Jan 29 09:48:36 2024 +0000
Commit:     Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Mon Jan 29 09:48:47 2024 +0000
URL:        https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=794b3122

app-crypt/gnupg: backport insecure smartcard backup fix to 2.2.x

Bug: https://bugs.gentoo.org/923248
Signed-off-by: Sam James <sam <AT> gentoo.org>

 .../gnupg-2.2.42-bug923248-insecure-backup.patch   | 292 +++++++++++++++++++++
 app-crypt/gnupg/gnupg-2.2.42-r2.ebuild             | 182 +++++++++++++
 2 files changed, 474 insertions(+)

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 <w...@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

diff --git a/app-crypt/gnupg/gnupg-2.2.42-r2.ebuild 
b/app-crypt/gnupg/gnupg-2.2.42-r2.ebuild
new file mode 100644
index 000000000000..b46257fafc93
--- /dev/null
+++ b/app-crypt/gnupg/gnupg-2.2.42-r2.ebuild
@@ -0,0 +1,182 @@
+# Copyright 1999-2024 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=8
+
+# Maintainers should:
+# 1. Join the "Gentoo" project at https://dev.gnupg.org/project/view/27/
+# 2. Subscribe to release tasks like https://dev.gnupg.org/T6159
+# (find the one for the current release then subscribe to it +
+# any subsequent ones linked within so you're covered for a while.)
+
+VERIFY_SIG_OPENPGP_KEY_PATH=/usr/share/openpgp-keys/gnupg.asc
+# in-source builds are not supported: https://dev.gnupg.org/T6313#166339
+inherit flag-o-matic out-of-source multiprocessing systemd toolchain-funcs 
verify-sig
+
+MY_P="${P/_/-}"
+
+DESCRIPTION="The GNU Privacy Guard, a GPL OpenPGP implementation"
+HOMEPAGE="https://gnupg.org/";
+SRC_URI="mirror://gnupg/gnupg/${MY_P}.tar.bz2"
+SRC_URI+=" verify-sig? ( mirror://gnupg/gnupg/${P}.tar.bz2.sig )"
+S="${WORKDIR}/${MY_P}"
+
+LICENSE="GPL-3+"
+SLOT="0"
+KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~m68k ~mips ~ppc ~ppc64 ~riscv 
~s390 ~sparc ~x86 ~amd64-linux ~x86-linux ~arm64-macos ~ppc-macos ~x64-macos 
~x64-solaris"
+IUSE="bzip2 doc ldap nls readline selinux +smartcard ssl test tofu tools usb 
user-socket wks-server"
+RESTRICT="!test? ( test )"
+
+# Existence of executables is checked during configuration.
+# Note: On each bump, update dep bounds on each version from configure.ac!
+DEPEND="
+       >=dev-libs/libassuan-2.5.0
+       >=dev-libs/libgcrypt-1.8.0:=
+       >=dev-libs/libgpg-error-1.38
+       >=dev-libs/libksba-1.3.5
+       >=dev-libs/npth-1.2
+       >=net-misc/curl-7.10
+       sys-libs/zlib
+       bzip2? ( app-arch/bzip2 )
+       ldap? ( net-nds/openldap:= )
+       readline? ( sys-libs/readline:= )
+       smartcard? ( usb? ( virtual/libusb:1 ) )
+       ssl? ( >=net-libs/gnutls-3.0:= )
+       tofu? ( >=dev-db/sqlite-3.7 )
+"
+RDEPEND="
+       ${DEPEND}
+       nls? ( virtual/libintl )
+       selinux? ( sec-policy/selinux-gpg )
+       wks-server? ( virtual/mta )
+"
+PDEPEND="
+       app-crypt/pinentry
+"
+BDEPEND="
+       virtual/pkgconfig
+       doc? ( sys-apps/texinfo )
+       nls? ( sys-devel/gettext )
+       verify-sig? ( sec-keys/openpgp-keys-gnupg )
+"
+
+DOCS=(
+       ChangeLog NEWS README THANKS TODO VERSION
+       doc/FAQ doc/DETAILS doc/HACKING doc/TRANSLATE doc/OpenPGP doc/KEYSERVER
+)
+
+PATCHES=(
+       
"${FILESDIR}"/${PN}-2.1.20-gpgscm-Use-shorter-socket-path-lengts-to-improve-tes.patch
+       "${FILESDIR}"/${PN}-2.2.42-bug923248-insecure-backup.patch
+)
+
+src_prepare() {
+       default
+
+       # Inject SSH_AUTH_SOCK into user's sessions after enabling 
gpg-agent-ssh.socket in systemctl --user mode,
+       # idea borrowed from libdbus, see
+       #   
https://gitlab.freedesktop.org/dbus/dbus/-/blob/master/bus/systemd-user/dbus.socket.in#L6
+       #
+       # This cannot be upstreamed, as it requires determining the exact 
prefix of 'systemctl',
+       # which in turn requires discovery in Autoconf, something that upstream 
deeply resents.
+       sed -e "/DirectoryMode=/a ExecStartPost=-${EPREFIX}/bin/systemctl 
--user set-environment SSH_AUTH_SOCK=%t/gnupg/S.gpg-agent.ssh" \
+               -i doc/examples/systemd-user/gpg-agent-ssh.socket || die
+}
+
+my_src_configure() {
+       # Upstream don't support LTO, bug #854222.
+       filter-lto
+
+       local myconf=(
+               $(use_enable bzip2)
+               $(use_enable nls)
+               $(use_enable smartcard scdaemon)
+               $(use_enable ssl gnutls)
+               $(use_enable test all-tests)
+               $(use_enable test tests)
+               $(use_enable tofu)
+               $(use smartcard && use_enable usb ccid-driver || echo 
'--disable-ccid-driver')
+               $(use_enable wks-server wks-tools)
+               $(use_with ldap)
+               $(use_with readline)
+
+               # Hardcode mailprog to /usr/libexec/sendmail even if it does 
not exist.
+               # As of GnuPG 2.3, the mailprog substitution is used for the 
binary called
+               # by wks-client & wks-server; and if it's autodetected but not 
not exist at
+               # build time, then then 'gpg-wks-client --send' functionality 
will not
+               # work. This has an unwanted side-effect in stage3 builds: 
there was a
+               # [R]DEPEND on virtual/mta, which also brought in 
virtual/logger, bloating
+               # the build where the install guide previously make the user 
chose the
+               # logger & mta early in the install.
+               --with-mailprog=/usr/libexec/sendmail
+
+               --disable-ntbtls
+               --enable-gpg
+               --enable-gpgsm
+               --enable-large-secmem
+
+               CC_FOR_BUILD="$(tc-getBUILD_CC)"
+               GPG_ERROR_CONFIG="${ESYSROOT}/usr/bin/${CHOST}-gpg-error-config"
+               KSBA_CONFIG="${ESYSROOT}/usr/bin/ksba-config"
+               LIBASSUAN_CONFIG="${ESYSROOT}/usr/bin/libassuan-config"
+               LIBGCRYPT_CONFIG="${ESYSROOT}/usr/bin/${CHOST}-libgcrypt-config"
+               NPTH_CONFIG="${ESYSROOT}/usr/bin/npth-config"
+
+               $("${S}/configure" --help | grep -o -- '--without-.*-prefix')
+       )
+
+       if use prefix && use usb; then
+               # bug #649598
+               append-cppflags -I"${ESYSROOT}/usr/include/libusb-1.0"
+       fi
+
+       # bug #663142
+       if use user-socket; then
+               myconf+=( --enable-run-gnupg-user-socket )
+       fi
+
+       # glib fails and picks up clang's internal stdint.h causing weird errors
+       tc-is-clang && export 
gl_cv_absolute_stdint_h="${ESYSROOT}"/usr/include/stdint.h
+
+       econf "${myconf[@]}"
+}
+
+my_src_compile() {
+       default
+
+       use doc && emake -C doc html
+}
+
+my_src_test() {
+       export TESTFLAGS="--parallel=$(makeopts_jobs)"
+
+       default
+}
+
+my_src_install() {
+       emake DESTDIR="${D}" install
+
+       use tools && dobin \
+               tools/{gpg-zip,gpgconf,gpgsplit,gpg-check-pattern} \
+               tools/make-dns-cert
+
+       dosym gpg /usr/bin/gpg2
+       dosym gpgv /usr/bin/gpgv2
+       echo ".so man1/gpg.1" > "${ED}"/usr/share/man/man1/gpg2.1 || die
+       echo ".so man1/gpgv.1" > "${ED}"/usr/share/man/man1/gpgv2.1 || die
+
+       dodir /etc/env.d
+       echo "CONFIG_PROTECT=/usr/share/gnupg/qualified.txt" >> 
"${ED}"/etc/env.d/30gnupg || die
+
+       use doc && dodoc doc/gnupg.html/*
+}
+
+my_src_install_all() {
+       einstalldocs
+
+       use tools && dobin tools/{convert-from-106,mail-signed-keys,lspgpot}
+
+       use doc && dodoc doc/*.png
+
+       systemd_douserunit doc/examples/systemd-user/*.{service,socket}
+}

Reply via email to