gnupg: add patch disallowing compressed signatures and certificates
https://seclists.org/oss-sec/2022/q3/9 https://seclists.org/oss-sec/2022/q3/27
This commit is contained in:
parent
3d0e70ae2a
commit
22e81f39ac
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
Loading…
Reference in a new issue