base16-schemes: unstable-2024-06-21 -> unstable-2024-11-12 (#356361)
[NixPkgs.git] / pkgs / tools / security / gnupg / v3-0001-Disallow-compressed-signatures-and-certificates.patch
blob267085dff4c8fdeb0cc89a95fb1aac567cde1e9e
1 From 459b61fa21db755d6c879c3ef9ab85b3d1786c9f Mon Sep 17 00:00:00 2001
2 From: Demi Marie Obenour <demi () invisiblethingslab com>
3 Date: Fri, 27 May 2022 19:51:19 -0400
4 Subject: [PATCH GnuPG v3] Disallow compressed signatures and certificates
6 Compressed packets have significant attack surface, due to the potential
7 for both denial of service (zip bombs and the like) and for code
8 execution via memory corruption vulnerabilities in the decompressor.
9 Furthermore, I am not aware of any implementation that uses them in keys
10 or detached signatures. Therefore, disallow their use in such contexts
11 entirely. This includes signatures that are part of a cleartext-signed
12 message.
14 When parsing detached signatures, forbid any packet that is not a
15 signature or marker packet. When parsing keys, return an error when
16 encountering a compressed packet, instead of decompressing the packet.
18 Furthermore, certificates, keys, and signatures are not allowed to
19 contain partial-length or indeterminate-length packets. Reject those in
20 parse_packet, rather than activating the partial-length filter code.
21 This is not (yet) implemented for cleartext-signed messages, as these
22 messages are internally represented as inline-signed messages.
24 GnuPG-bug-id: T5993
25 Signed-off-by: Demi Marie Obenour <demiobenour () gmail com>
26 ---
27 g10/import.c | 18 ++----------------
28 g10/mainproc.c | 24 +++++++++++++++++++++---
29 g10/packet.h | 2 ++
30 g10/parse-packet.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
31 4 files changed, 68 insertions(+), 20 deletions(-)
33 diff --git a/g10/import.c b/g10/import.c
34 index bb0bf67934a8316130cde182cd43d56353e0171d..a8136351f6f7dae8c65634ed8e1c242d323e2009 100644
35 --- a/g10/import.c
36 +++ b/g10/import.c
37 @@ -1042,22 +1042,8 @@ read_block( IOBUF a, unsigned int options,
38 switch (pkt->pkttype)
40 case PKT_COMPRESSED:
41 - if (check_compress_algo (pkt->pkt.compressed->algorithm))
42 - {
43 - rc = GPG_ERR_COMPR_ALGO;
44 - goto ready;
45 - }
46 - else
47 - {
48 - compress_filter_context_t *cfx = xmalloc_clear( sizeof *cfx );
49 - pkt->pkt.compressed->buf = NULL;
50 - if (push_compress_filter2 (a, cfx,
51 - pkt->pkt.compressed->algorithm, 1))
52 - xfree (cfx); /* e.g. in case of compression_algo NONE. */
53 - }
54 - free_packet (pkt, &parsectx);
55 - init_packet(pkt);
56 - break;
57 + rc = GPG_ERR_UNEXPECTED;
58 + goto ready;
60 case PKT_RING_TRUST:
61 /* Skip those packets unless we are in restore mode. */
62 diff --git a/g10/mainproc.c b/g10/mainproc.c
63 index af11877aa257e46662c42b6ff573ee01c3ad1547..3629fc921b742afd131e8d8e2664b201095990f0 100644
64 --- a/g10/mainproc.c
65 +++ b/g10/mainproc.c
66 @@ -152,6 +152,7 @@ add_onepass_sig (CTX c, PACKET *pkt)
68 kbnode_t node;
70 + log_assert(!(c->sigs_only && c->signed_data.used));
71 if (c->list) /* Add another packet. */
72 add_kbnode (c->list, new_kbnode (pkt));
73 else /* Insert the first one. */
74 @@ -1076,8 +1077,16 @@ proc_compressed (CTX c, PACKET *pkt)
75 int rc;
77 /*printf("zip: compressed data packet\n");*/
78 - if (c->sigs_only)
79 - rc = handle_compressed (c->ctrl, c, zd, proc_compressed_cb, c);
80 + if ( literals_seen )
81 + {
82 + log_error ("Compressed packet follows literal data packet\n");
83 + rc = GPG_ERR_UNEXPECTED;
84 + }
85 + else if ( c->sigs_only )
86 + {
87 + log_assert(!c->signed_data.used);
88 + rc = handle_compressed (c->ctrl, c, zd, proc_compressed_cb, c);
89 + }
90 else if( c->encrypt_only )
91 rc = handle_compressed (c->ctrl, c, zd, proc_encrypt_cb, c);
92 else
93 @@ -1596,6 +1605,7 @@ do_proc_packets (CTX c, iobuf_t a)
94 c->iobuf = a;
95 init_packet(pkt);
96 init_parse_packet (&parsectx, a);
97 + parsectx.sigs_only = c->sigs_only && c->signed_data.used;
98 while ((rc=parse_packet (&parsectx, pkt)) != -1)
100 any_data = 1;
101 @@ -1607,6 +1617,12 @@ do_proc_packets (CTX c, iobuf_t a)
102 if (gpg_err_code (rc) == GPG_ERR_INV_PACKET
103 && opt.list_packets == 0)
104 break;
106 + if (gpg_err_code (rc) == GPG_ERR_UNEXPECTED)
108 + write_status_text( STATUS_UNEXPECTED, "0" );
109 + goto leave;
111 continue;
113 newpkt = -1;
114 @@ -1644,7 +1660,9 @@ do_proc_packets (CTX c, iobuf_t a)
115 case PKT_COMPRESSED: rc = proc_compressed (c, pkt); break;
116 case PKT_ONEPASS_SIG: newpkt = add_onepass_sig (c, pkt); break;
117 case PKT_GPG_CONTROL: newpkt = add_gpg_control (c, pkt); break;
118 - default: newpkt = 0; break;
119 + default:
120 + log_assert(!c->signed_data.used);
121 + newpkt = 0; break;
124 else if (c->encrypt_only)
125 diff --git a/g10/packet.h b/g10/packet.h
126 index 5a14015a16c872fe7b0b15468598daf7a05ffc02..82dfe786b46051491e7015e64441678140defa9e 100644
127 --- a/g10/packet.h
128 +++ b/g10/packet.h
129 @@ -657,6 +657,7 @@ struct parse_packet_ctx_s
130 int free_last_pkt; /* Indicates that LAST_PKT must be freed. */
131 int skip_meta; /* Skip ring trust packets. */
132 unsigned int n_parsed_packets; /* Number of parsed packets. */
133 + int sigs_only; /* Only accept detached signature packets */
135 typedef struct parse_packet_ctx_s *parse_packet_ctx_t;
137 @@ -667,6 +668,7 @@ typedef struct parse_packet_ctx_s *parse_packet_ctx_t;
138 (a)->free_last_pkt = 0; \
139 (a)->skip_meta = 0; \
140 (a)->n_parsed_packets = 0; \
141 + (a)->sigs_only = 0; \
142 } while (0)
144 #define deinit_parse_packet(a) do { \
145 diff --git a/g10/parse-packet.c b/g10/parse-packet.c
146 index cea1f7ebc5daec3863ae963c1ab25500f86796fe..dca66ff427ea6778e536782ec6bda83584877342 100644
147 --- a/g10/parse-packet.c
148 +++ b/g10/parse-packet.c
149 @@ -738,6 +738,20 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
150 case PKT_ENCRYPTED_MDC:
151 case PKT_ENCRYPTED_AEAD:
152 case PKT_COMPRESSED:
153 + if (ctx->sigs_only)
155 + log_error (_("partial length packet of type %d in detached"
156 + " signature\n"), pkttype);
157 + rc = gpg_error (GPG_ERR_UNEXPECTED);
158 + goto leave;
160 + if (onlykeypkts)
162 + log_error (_("partial length packet of type %d in keyring\n"),
163 + pkttype);
164 + rc = gpg_error (GPG_ERR_UNEXPECTED);
165 + goto leave;
167 iobuf_set_partial_body_length_mode (inp, c & 0xff);
168 pktlen = 0; /* To indicate partial length. */
169 partial = 1;
170 @@ -775,6 +789,20 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
171 rc = gpg_error (GPG_ERR_INV_PACKET);
172 goto leave;
174 + else if (ctx->sigs_only)
176 + log_error (_("indeterminate length packet of type %d in detached"
177 + " signature\n"), pkttype);
178 + rc = gpg_error (GPG_ERR_UNEXPECTED);
179 + goto leave;
181 + else if (onlykeypkts)
183 + log_error (_("indeterminate length packet of type %d in"
184 + " keyring\n"), pkttype);
185 + rc = gpg_error (GPG_ERR_UNEXPECTED);
186 + goto leave;
189 else
191 @@ -828,7 +856,21 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
192 goto leave;
195 - if (with_uid && pkttype == PKT_USER_ID)
196 + if (ctx->sigs_only)
197 + switch (pkttype)
199 + case PKT_SIGNATURE:
200 + case PKT_MARKER:
201 + break;
202 + default:
203 + log_error(_("Packet type %d not allowed in detached signature\n"),
204 + pkttype);
205 + iobuf_skip_rest (inp, pktlen, partial);
206 + *skip = 1;
207 + rc = GPG_ERR_UNEXPECTED;
208 + goto leave;
210 + else if (with_uid && pkttype == PKT_USER_ID)
211 /* If ONLYKEYPKTS is set to 2, then we never skip user id packets,
212 even if DO_SKIP is set. */
215 2.36.1