about summary refs log tree commit diff
path: root/pkgs/tools/security/gnupg
diff options
context:
space:
mode:
authorStig Palmquist <stig@stig.io>2022-07-06 14:06:19 +0200
committerStig Palmquist <stig@stig.io>2022-07-06 14:09:39 +0200
commit22e81f39ace64964bae3b6c89662d1221a11324c (patch)
treeba4a0c2a4d892e161f65edf8a36e143968da5645 /pkgs/tools/security/gnupg
parent3d0e70ae2ad9a6545eb70b067b5c081eba45ee6c (diff)
gnupg: add patch disallowing compressed signatures and certificates
https://seclists.org/oss-sec/2022/q3/9
https://seclists.org/oss-sec/2022/q3/27
Diffstat (limited to 'pkgs/tools/security/gnupg')
-rw-r--r--pkgs/tools/security/gnupg/23.nix3
-rw-r--r--pkgs/tools/security/gnupg/v3-0001-Disallow-compressed-signatures-and-certificates.patch216
2 files changed, 219 insertions, 0 deletions
diff --git a/pkgs/tools/security/gnupg/23.nix b/pkgs/tools/security/gnupg/23.nix
index b07a3550c76dd..13364f5498a8e 100644
--- a/pkgs/tools/security/gnupg/23.nix
+++ b/pkgs/tools/security/gnupg/23.nix
@@ -37,6 +37,9 @@ stdenv.mkDerivation rec {
 
     # Patch from upstream 34c649b36013, https://dev.gnupg.org/T6027
     ./CVE-2022-34903-g10-fix-garbled-status-messages-in-NOTATION_DATA.patch
+
+    # Patch for DoS vuln from https://seclists.org/oss-sec/2022/q3/27
+    ./v3-0001-Disallow-compressed-signatures-and-certificates.patch
   ];
   postPatch = ''
     sed -i 's,\(hkps\|https\)://keyserver.ubuntu.com,hkps://keys.openpgp.org,g' configure configure.ac doc/dirmngr.texi doc/gnupg.info-1
diff --git a/pkgs/tools/security/gnupg/v3-0001-Disallow-compressed-signatures-and-certificates.patch b/pkgs/tools/security/gnupg/v3-0001-Disallow-compressed-signatures-and-certificates.patch
new file mode 100644
index 0000000000000..267085dff4c8f
--- /dev/null
+++ b/pkgs/tools/security/gnupg/v3-0001-Disallow-compressed-signatures-and-certificates.patch
@@ -0,0 +1,216 @@
+From 459b61fa21db755d6c879c3ef9ab85b3d1786c9f Mon Sep 17 00:00:00 2001
+From: Demi Marie Obenour <demi () invisiblethingslab com>
+Date: Fri, 27 May 2022 19:51:19 -0400
+Subject: [PATCH GnuPG v3] Disallow compressed signatures and certificates
+
+Compressed packets have significant attack surface, due to the potential
+for both denial of service (zip bombs and the like) and for code
+execution via memory corruption vulnerabilities in the decompressor.
+Furthermore, I am not aware of any implementation that uses them in keys
+or detached signatures.  Therefore, disallow their use in such contexts
+entirely.  This includes signatures that are part of a cleartext-signed
+message.
+
+When parsing detached signatures, forbid any packet that is not a
+signature or marker packet.  When parsing keys, return an error when
+encountering a compressed packet, instead of decompressing the packet.
+
+Furthermore, certificates, keys, and signatures are not allowed to
+contain partial-length or indeterminate-length packets.  Reject those in
+parse_packet, rather than activating the partial-length filter code.
+This is not (yet) implemented for cleartext-signed messages, as these
+messages are internally represented as inline-signed messages.
+
+GnuPG-bug-id: T5993
+Signed-off-by: Demi Marie Obenour <demiobenour () gmail com>
+---
+ g10/import.c       | 18 ++----------------
+ g10/mainproc.c     | 24 +++++++++++++++++++++---
+ g10/packet.h       |  2 ++
+ g10/parse-packet.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
+ 4 files changed, 68 insertions(+), 20 deletions(-)
+
+diff --git a/g10/import.c b/g10/import.c
+index bb0bf67934a8316130cde182cd43d56353e0171d..a8136351f6f7dae8c65634ed8e1c242d323e2009 100644
+--- a/g10/import.c
++++ b/g10/import.c
+@@ -1042,22 +1042,8 @@ read_block( IOBUF a, unsigned int options,
+       switch (pkt->pkttype)
+         {
+         case PKT_COMPRESSED:
+-          if (check_compress_algo (pkt->pkt.compressed->algorithm))
+-            {
+-              rc = GPG_ERR_COMPR_ALGO;
+-              goto ready;
+-            }
+-          else
+-            {
+-              compress_filter_context_t *cfx = xmalloc_clear( sizeof *cfx );
+-              pkt->pkt.compressed->buf = NULL;
+-              if (push_compress_filter2 (a, cfx,
+-                                         pkt->pkt.compressed->algorithm, 1))
+-                xfree (cfx); /* e.g. in case of compression_algo NONE.  */
+-            }
+-          free_packet (pkt, &parsectx);
+-          init_packet(pkt);
+-          break;
++          rc = GPG_ERR_UNEXPECTED;
++          goto ready;
+ 
+         case PKT_RING_TRUST:
+           /* Skip those packets unless we are in restore mode.  */
+diff --git a/g10/mainproc.c b/g10/mainproc.c
+index af11877aa257e46662c42b6ff573ee01c3ad1547..3629fc921b742afd131e8d8e2664b201095990f0 100644
+--- a/g10/mainproc.c
++++ b/g10/mainproc.c
+@@ -152,6 +152,7 @@ add_onepass_sig (CTX c, PACKET *pkt)
+ {
+   kbnode_t node;
+ 
++  log_assert(!(c->sigs_only && c->signed_data.used));
+   if (c->list) /* Add another packet. */
+     add_kbnode (c->list, new_kbnode (pkt));
+   else /* Insert the first one.  */
+@@ -1076,8 +1077,16 @@ proc_compressed (CTX c, PACKET *pkt)
+   int rc;
+ 
+   /*printf("zip: compressed data packet\n");*/
+-  if (c->sigs_only)
+-    rc = handle_compressed (c->ctrl, c, zd, proc_compressed_cb, c);
++  if ( literals_seen )
++    {
++      log_error ("Compressed packet follows literal data packet\n");
++      rc = GPG_ERR_UNEXPECTED;
++    }
++  else if ( c->sigs_only )
++    {
++      log_assert(!c->signed_data.used);
++      rc = handle_compressed (c->ctrl, c, zd, proc_compressed_cb, c);
++    }
+   else if( c->encrypt_only )
+     rc = handle_compressed (c->ctrl, c, zd, proc_encrypt_cb, c);
+   else
+@@ -1596,6 +1605,7 @@ do_proc_packets (CTX c, iobuf_t a)
+   c->iobuf = a;
+   init_packet(pkt);
+   init_parse_packet (&parsectx, a);
++  parsectx.sigs_only = c->sigs_only && c->signed_data.used;
+   while ((rc=parse_packet (&parsectx, pkt)) != -1)
+     {
+       any_data = 1;
+@@ -1607,6 +1617,12 @@ do_proc_packets (CTX c, iobuf_t a)
+           if (gpg_err_code (rc) == GPG_ERR_INV_PACKET
+               && opt.list_packets == 0)
+             break;
++
++          if (gpg_err_code (rc) == GPG_ERR_UNEXPECTED)
++            {
++              write_status_text( STATUS_UNEXPECTED, "0" );
++              goto leave;
++            }
+           continue;
+ 	}
+       newpkt = -1;
+@@ -1644,7 +1660,9 @@ do_proc_packets (CTX c, iobuf_t a)
+             case PKT_COMPRESSED:  rc = proc_compressed (c, pkt); break;
+             case PKT_ONEPASS_SIG: newpkt = add_onepass_sig (c, pkt); break;
+             case PKT_GPG_CONTROL: newpkt = add_gpg_control (c, pkt); break;
+-            default: newpkt = 0; break;
++            default:
++	      log_assert(!c->signed_data.used);
++	      newpkt = 0; break;
+ 	    }
+ 	}
+       else if (c->encrypt_only)
+diff --git a/g10/packet.h b/g10/packet.h
+index 5a14015a16c872fe7b0b15468598daf7a05ffc02..82dfe786b46051491e7015e64441678140defa9e 100644
+--- a/g10/packet.h
++++ b/g10/packet.h
+@@ -657,6 +657,7 @@ struct parse_packet_ctx_s
+   int free_last_pkt; /* Indicates that LAST_PKT must be freed.  */
+   int skip_meta;     /* Skip ring trust packets.  */
+   unsigned int n_parsed_packets;	/* Number of parsed packets.  */
++  int sigs_only;     /* Only accept detached signature packets */
+ };
+ typedef struct parse_packet_ctx_s *parse_packet_ctx_t;
+ 
+@@ -667,6 +668,7 @@ typedef struct parse_packet_ctx_s *parse_packet_ctx_t;
+     (a)->free_last_pkt = 0;         \
+     (a)->skip_meta = 0;             \
+     (a)->n_parsed_packets = 0;      \
++    (a)->sigs_only = 0;             \
+   } while (0)
+ 
+ #define deinit_parse_packet(a) do { \
+diff --git a/g10/parse-packet.c b/g10/parse-packet.c
+index cea1f7ebc5daec3863ae963c1ab25500f86796fe..dca66ff427ea6778e536782ec6bda83584877342 100644
+--- a/g10/parse-packet.c
++++ b/g10/parse-packet.c
+@@ -738,6 +738,20 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
+             case PKT_ENCRYPTED_MDC:
+             case PKT_ENCRYPTED_AEAD:
+             case PKT_COMPRESSED:
++              if (ctx->sigs_only)
++                {
++                  log_error (_("partial length packet of type %d in detached"
++                               " signature\n"), pkttype);
++                  rc = gpg_error (GPG_ERR_UNEXPECTED);
++                  goto leave;
++                }
++              if (onlykeypkts)
++                {
++                  log_error (_("partial length packet of type %d in keyring\n"),
++                             pkttype);
++                  rc = gpg_error (GPG_ERR_UNEXPECTED);
++                  goto leave;
++                }
+               iobuf_set_partial_body_length_mode (inp, c & 0xff);
+               pktlen = 0;	/* To indicate partial length.  */
+               partial = 1;
+@@ -775,6 +789,20 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
+ 	      rc = gpg_error (GPG_ERR_INV_PACKET);
+ 	      goto leave;
+ 	    }
++	  else if (ctx->sigs_only)
++	    {
++	      log_error (_("indeterminate length packet of type %d in detached"
++                           " signature\n"), pkttype);
++	      rc = gpg_error (GPG_ERR_UNEXPECTED);
++	      goto leave;
++	    }
++	  else if (onlykeypkts)
++	    {
++	      log_error (_("indeterminate length packet of type %d in"
++                           " keyring\n"), pkttype);
++	      rc = gpg_error (GPG_ERR_UNEXPECTED);
++	      goto leave;
++	    }
+ 	}
+       else
+ 	{
+@@ -828,7 +856,21 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
+       goto leave;
+     }
+ 
+-  if (with_uid && pkttype == PKT_USER_ID)
++  if (ctx->sigs_only)
++    switch (pkttype)
++      {
++      case PKT_SIGNATURE:
++      case PKT_MARKER:
++	break;
++      default:
++        log_error(_("Packet type %d not allowed in detached signature\n"),
++                  pkttype);
++	iobuf_skip_rest (inp, pktlen, partial);
++	*skip = 1;
++	rc = GPG_ERR_UNEXPECTED;
++	goto leave;
++      }
++  else if (with_uid && pkttype == PKT_USER_ID)
+     /* If ONLYKEYPKTS is set to 2, then we never skip user id packets,
+        even if DO_SKIP is set.  */
+     ;
+-- 
+2.36.1
+