summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVijay Anusuri <vanusuri@mvista.com>2024-07-03 18:22:07 +0530
committerArmin Kuster <akuster808@gmail.com>2024-07-17 20:06:58 -0400
commite532396d479fb97dd62be67bee0a640a99f76544 (patch)
tree73d0e5efe08ae73a2c1a526cf61625b331aeb623
parent04d41e058acf19b82bf6559d6ccbbed73f9bc4d3 (diff)
downloadmeta-openembedded-e532396d479fb97dd62be67bee0a640a99f76544.tar.gz
krb5: Fix for CVE-2024-37370 and CVE-2024-37371
Upstream-Status: Backport [https://github.com/krb5/krb5/commit/548da160b52b25a106e9f6077d6a42c2c049586c & https://github.com/krb5/krb5/commit/55fbf435edbe2e92dd8101669b1ce7144bc96fef] Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> Signed-off-by: Armin Kuster <akuster808@gmail.com>
-rw-r--r--meta-oe/recipes-connectivity/krb5/krb5/CVE-2024-37370_37371-pre1.patch168
-rw-r--r--meta-oe/recipes-connectivity/krb5/krb5/CVE-2024-37370_37371.patch538
-rw-r--r--meta-oe/recipes-connectivity/krb5/krb5_1.17.2.bb2
3 files changed, 708 insertions, 0 deletions
diff --git a/meta-oe/recipes-connectivity/krb5/krb5/CVE-2024-37370_37371-pre1.patch b/meta-oe/recipes-connectivity/krb5/krb5/CVE-2024-37370_37371-pre1.patch
new file mode 100644
index 0000000000..36536461a5
--- /dev/null
+++ b/meta-oe/recipes-connectivity/krb5/krb5/CVE-2024-37370_37371-pre1.patch
@@ -0,0 +1,168 @@
1From 548da160b52b25a106e9f6077d6a42c2c049586c Mon Sep 17 00:00:00 2001
2From: Greg Hudson <ghudson@mit.edu>
3Date: Tue, 7 Mar 2023 00:19:33 -0500
4Subject: [PATCH] Add a simple DER support header
5
6Upstream-Status: Backport from [https://github.com/krb5/krb5/commit/548da160b52b25a106e9f6077d6a42c2c049586c]
7Comment: to backport fix for CVE-2024-37370 CVE-2024-37371, Add a simple DER support header
8Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
9---
10 src/include/k5-der.h | 149 +++++++++++++++++++++++++++++++++++++++++++
11 1 file changed, 149 insertions(+)
12 create mode 100644 src/include/k5-der.h
13
14diff --git a/src/include/k5-der.h b/src/include/k5-der.h
15new file mode 100644
16index 0000000000..b8371d9b4d
17--- /dev/null
18+++ b/src/include/k5-der.h
19@@ -0,0 +1,149 @@
20+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
21+/* include/k5-der.h - Distinguished Encoding Rules (DER) declarations */
22+/*
23+ * Copyright (C) 2023 by the Massachusetts Institute of Technology.
24+ * All rights reserved.
25+ *
26+ * Redistribution and use in source and binary forms, with or without
27+ * modification, are permitted provided that the following conditions
28+ * are met:
29+ *
30+ * * Redistributions of source code must retain the above copyright
31+ * notice, this list of conditions and the following disclaimer.
32+ *
33+ * * Redistributions in binary form must reproduce the above copyright
34+ * notice, this list of conditions and the following disclaimer in
35+ * the documentation and/or other materials provided with the
36+ * distribution.
37+ *
38+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
39+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
40+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
41+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
42+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
43+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
44+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
45+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
47+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
49+ * OF THE POSSIBILITY OF SUCH DAMAGE.
50+ */
51+
52+/*
53+ * Most ASN.1 encoding and decoding is done using the table-driven framework in
54+ * libkrb5. When that is not an option, these helpers can be used to encode
55+ * and decode simple types.
56+ */
57+
58+#ifndef K5_DER_H
59+#define K5_DER_H
60+
61+#include <stdint.h>
62+#include <stdbool.h>
63+#include "k5-buf.h"
64+#include "k5-input.h"
65+
66+/* Return the number of bytes needed to encode len as a DER encoding length. */
67+static inline size_t
68+k5_der_len_len(size_t len)
69+{
70+ size_t llen;
71+
72+ if (len < 128)
73+ return 1;
74+ llen = 1;
75+ while (len > 0) {
76+ len >>= 8;
77+ llen++;
78+ }
79+ return llen;
80+}
81+
82+/* Return the number of bytes needed to encode a DER value (with identifier
83+ * byte and length) for a given contents length. */
84+static inline size_t
85+k5_der_value_len(size_t contents_len)
86+{
87+ return 1 + k5_der_len_len(contents_len) + contents_len;
88+}
89+
90+/* Add a DER identifier byte (composed by the caller, including the ASN.1
91+ * class, tag, and constructed bit) and length. */
92+static inline void
93+k5_der_add_taglen(struct k5buf *buf, uint8_t idbyte, size_t len)
94+{
95+ uint8_t *p;
96+ size_t llen = k5_der_len_len(len);
97+
98+ p = k5_buf_get_space(buf, 1 + llen);
99+ if (p == NULL)
100+ return;
101+ *p++ = idbyte;
102+ if (len < 128) {
103+ *p = len;
104+ } else {
105+ *p = 0x80 | (llen - 1);
106+ /* Encode the length bytes backwards so the most significant byte is
107+ * first. */
108+ p += llen;
109+ while (len > 0) {
110+ *--p = len & 0xFF;
111+ len >>= 8;
112+ }
113+ }
114+}
115+
116+/* Add a DER value (identifier byte, length, and contents). */
117+static inline void
118+k5_der_add_value(struct k5buf *buf, uint8_t idbyte, const void *contents,
119+ size_t len)
120+{
121+ k5_der_add_taglen(buf, idbyte, len);
122+ k5_buf_add_len(buf, contents, len);
123+}
124+
125+/*
126+ * If the next byte in in matches idbyte and the subsequent DER length is
127+ * valid, advance in past the value, set *contents_out to the value contents,
128+ * and return true. Otherwise return false. Only set an error on in if the
129+ * next bytes matches idbyte but the ensuing length is invalid. contents_out
130+ * may be aliased to in; it will only be written to on successful decoding of a
131+ * value.
132+ */
133+static inline bool
134+k5_der_get_value(struct k5input *in, uint8_t idbyte,
135+ struct k5input *contents_out)
136+{
137+ uint8_t lenbyte, i;
138+ size_t len;
139+ const void *bytes;
140+
141+ /* Do nothing if in is empty or the next byte doesn't match idbyte. */
142+ if (in->status || in->len == 0 || *in->ptr != idbyte)
143+ return false;
144+
145+ /* Advance past the identifier byte and decode the length. */
146+ (void)k5_input_get_byte(in);
147+ lenbyte = k5_input_get_byte(in);
148+ if (lenbyte < 128) {
149+ len = lenbyte;
150+ } else {
151+ len = 0;
152+ for (i = 0; i < (lenbyte & 0x7F); i++) {
153+ if (len > (SIZE_MAX >> 8)) {
154+ k5_input_set_status(in, EOVERFLOW);
155+ return false;
156+ }
157+ len = (len << 8) | k5_input_get_byte(in);
158+ }
159+ }
160+
161+ bytes = k5_input_get_bytes(in, len);
162+ if (bytes == NULL)
163+ return false;
164+ k5_input_init(contents_out, bytes, len);
165+ return true;
166+}
167+
168+#endif /* K5_DER_H */
diff --git a/meta-oe/recipes-connectivity/krb5/krb5/CVE-2024-37370_37371.patch b/meta-oe/recipes-connectivity/krb5/krb5/CVE-2024-37370_37371.patch
new file mode 100644
index 0000000000..31db93c42c
--- /dev/null
+++ b/meta-oe/recipes-connectivity/krb5/krb5/CVE-2024-37370_37371.patch
@@ -0,0 +1,538 @@
1From 55fbf435edbe2e92dd8101669b1ce7144bc96fef Mon Sep 17 00:00:00 2001
2From: Greg Hudson <ghudson@mit.edu>
3Date: Fri, 14 Jun 2024 10:56:12 -0400
4Subject: [PATCH] Fix vulnerabilities in GSS message token handling
5
6In gss_krb5int_unseal_token_v3() and gss_krb5int_unseal_v3_iov(),
7verify the Extra Count field of CFX wrap tokens against the encrypted
8header. Reported by Jacob Champion.
9
10In gss_krb5int_unseal_token_v3(), check for a decrypted plaintext
11length too short to contain the encrypted header and extra count
12bytes. Reported by Jacob Champion.
13
14In kg_unseal_iov_token(), separately track the header IOV length and
15complete token length when parsing the token's ASN.1 wrapper. This
16fix contains modified versions of functions from k5-der.h and
17util_token.c; this duplication will be cleaned up in a future commit.
18
19CVE-2024-37370:
20
21In MIT krb5 release 1.3 and later, an attacker can modify the
22plaintext Extra Count field of a confidential GSS krb5 wrap token,
23causing the unwrapped token to appear truncated to the application.
24
25CVE-2024-37371:
26
27In MIT krb5 release 1.3 and later, an attacker can cause invalid
28memory reads by sending message tokens with invalid length fields.
29
30(cherry picked from commit b0a2f8a5365f2eec3e27d78907de9f9d2c80505a)
31
32ticket: 9128
33version_fixed: 1.21.3
34
35Upstream-Status: Backport [https://github.com/krb5/krb5/commit/55fbf435edbe2e92dd8101669b1ce7144bc96fef]
36CVE: CVE-2024-37370 CVE-2024-37371
37Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
38---
39 src/lib/gssapi/krb5/k5sealv3.c | 5 +
40 src/lib/gssapi/krb5/k5sealv3iov.c | 3 +-
41 src/lib/gssapi/krb5/k5unsealiov.c | 80 +++++++++-
42 src/tests/gssapi/t_invalid.c | 233 +++++++++++++++++++++++++-----
43 4 files changed, 275 insertions(+), 46 deletions(-)
44
45diff --git a/src/lib/gssapi/krb5/k5sealv3.c b/src/lib/gssapi/krb5/k5sealv3.c
46index 25d9f27..48fc508 100644
47--- a/src/lib/gssapi/krb5/k5sealv3.c
48+++ b/src/lib/gssapi/krb5/k5sealv3.c
49@@ -409,10 +409,15 @@ gss_krb5int_unseal_token_v3(krb5_context *contextptr,
50 /* Don't use bodysize here! Use the fact that
51 cipher.ciphertext.length has been adjusted to the
52 correct length. */
53+ if (plain.length < 16 + ec) {
54+ free(plain.data);
55+ goto defective;
56+ }
57 althdr = (unsigned char *)plain.data + plain.length - 16;
58 if (load_16_be(althdr) != KG2_TOK_WRAP_MSG
59 || althdr[2] != ptr[2]
60 || althdr[3] != ptr[3]
61+ || load_16_be(althdr+4) != ec
62 || memcmp(althdr+8, ptr+8, 8)) {
63 free(plain.data);
64 goto defective;
65diff --git a/src/lib/gssapi/krb5/k5sealv3iov.c b/src/lib/gssapi/krb5/k5sealv3iov.c
66index a73edb6..b0b0c0f 100644
67--- a/src/lib/gssapi/krb5/k5sealv3iov.c
68+++ b/src/lib/gssapi/krb5/k5sealv3iov.c
69@@ -403,9 +403,10 @@ gss_krb5int_unseal_v3_iov(krb5_context context,
70 if (load_16_be(althdr) != KG2_TOK_WRAP_MSG
71 || althdr[2] != ptr[2]
72 || althdr[3] != ptr[3]
73+ || load_16_be(althdr + 4) != ec
74 || memcmp(althdr + 8, ptr + 8, 8) != 0) {
75 *minor_status = 0;
76- return GSS_S_BAD_SIG;
77+ return GSS_S_DEFECTIVE_TOKEN;
78 }
79 } else {
80 /* Verify checksum: note EC is checksum size here, not padding */
81diff --git a/src/lib/gssapi/krb5/k5unsealiov.c b/src/lib/gssapi/krb5/k5unsealiov.c
82index f15d2db..5cbb896 100644
83--- a/src/lib/gssapi/krb5/k5unsealiov.c
84+++ b/src/lib/gssapi/krb5/k5unsealiov.c
85@@ -25,6 +25,7 @@
86 */
87
88 #include "k5-int.h"
89+#include "k5-der.h"
90 #include "gssapiP_krb5.h"
91
92 static OM_uint32
93@@ -295,6 +296,73 @@ cleanup:
94 return retval;
95 }
96
97+/* Similar to k5_der_get_value(), but output an unchecked content length
98+ * instead of a k5input containing the contents. */
99+static inline bool
100+get_der_tag(struct k5input *in, uint8_t idbyte, size_t *len_out)
101+{
102+ uint8_t lenbyte, i;
103+ size_t len;
104+
105+ /* Do nothing if in is empty or the next byte doesn't match idbyte. */
106+ if (in->status || in->len == 0 || *in->ptr != idbyte)
107+ return false;
108+
109+ /* Advance past the identifier byte and decode the length. */
110+ (void)k5_input_get_byte(in);
111+ lenbyte = k5_input_get_byte(in);
112+ if (lenbyte < 128) {
113+ len = lenbyte;
114+ } else {
115+ len = 0;
116+ for (i = 0; i < (lenbyte & 0x7F); i++) {
117+ if (len > (SIZE_MAX >> 8)) {
118+ k5_input_set_status(in, EOVERFLOW);
119+ return false;
120+ }
121+ len = (len << 8) | k5_input_get_byte(in);
122+ }
123+ }
124+
125+ if (in->status)
126+ return false;
127+
128+ *len_out = len;
129+ return true;
130+}
131+
132+/*
133+ * Similar to g_verify_token_header() without toktype or flags, but do not read
134+ * more than *header_len bytes of ASN.1 wrapper, and on output set *header_len
135+ * to the remaining number of header bytes. Verify the outer DER tag's length
136+ * against token_len, which may be larger (but not smaller) than *header_len.
137+ */
138+static gss_int32
139+verify_detached_wrapper(const gss_OID_desc *mech, size_t *header_len,
140+ uint8_t **header_in, size_t token_len)
141+{
142+ struct k5input in, mech_der;
143+ gss_OID_desc toid;
144+ size_t len;
145+
146+ k5_input_init(&in, *header_in, *header_len);
147+
148+ if (get_der_tag(&in, 0x60, &len)) {
149+ if (len != token_len - (in.ptr - *header_in))
150+ return G_BAD_TOK_HEADER;
151+ if (!k5_der_get_value(&in, 0x06, &mech_der))
152+ return G_BAD_TOK_HEADER;
153+ toid.elements = (uint8_t *)mech_der.ptr;
154+ toid.length = mech_der.len;
155+ if (!g_OID_equal(&toid, mech))
156+ return G_WRONG_MECH;
157+ }
158+
159+ *header_in = (uint8_t *)in.ptr;
160+ *header_len = in.len;
161+ return 0;
162+}
163+
164 /*
165 * Caller must provide TOKEN | DATA | PADDING | TRAILER, except
166 * for DCE in which case it can just provide TOKEN | DATA (must
167@@ -315,8 +383,7 @@ kg_unseal_iov_token(OM_uint32 *minor_status,
168 gss_iov_buffer_t header;
169 gss_iov_buffer_t padding;
170 gss_iov_buffer_t trailer;
171- size_t input_length;
172- unsigned int bodysize;
173+ size_t input_length, hlen;
174 int toktype2;
175
176 header = kg_locate_header_iov(iov, iov_count, toktype);
177@@ -346,15 +413,14 @@ kg_unseal_iov_token(OM_uint32 *minor_status,
178 input_length += trailer->buffer.length;
179 }
180
181- code = g_verify_token_header(ctx->mech_used,
182- &bodysize, &ptr, -1,
183- input_length, 0);
184+ hlen = header->buffer.length;
185+ code = verify_detached_wrapper(ctx->mech_used, &hlen, &ptr, input_length);
186 if (code != 0) {
187 *minor_status = code;
188 return GSS_S_DEFECTIVE_TOKEN;
189 }
190
191- if (bodysize < 2) {
192+ if (hlen < 2) {
193 *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
194 return GSS_S_DEFECTIVE_TOKEN;
195 }
196@@ -362,7 +428,7 @@ kg_unseal_iov_token(OM_uint32 *minor_status,
197 toktype2 = load_16_be(ptr);
198
199 ptr += 2;
200- bodysize -= 2;
201+ hlen -= 2;
202
203 switch (toktype2) {
204 case KG2_TOK_MIC_MSG:
205diff --git a/src/tests/gssapi/t_invalid.c b/src/tests/gssapi/t_invalid.c
206index 2a332a8..e70ace6 100644
207--- a/src/tests/gssapi/t_invalid.c
208+++ b/src/tests/gssapi/t_invalid.c
209@@ -36,31 +36,41 @@
210 *
211 * 1. A pre-CFX wrap or MIC token processed with a CFX-only context causes a
212 * null pointer dereference. (The token must use SEAL_ALG_NONE or it will
213- * be rejected.)
214+ * be rejected.) This vulnerability also applies to IOV unwrap.
215 *
216- * 2. A pre-CFX wrap or MIC token with fewer than 24 bytes after the ASN.1
217+ * 2. A CFX wrap token with a different value of EC between the plaintext and
218+ * encrypted copies will be erroneously accepted, which allows a message
219+ * truncation attack. This vulnerability also applies to IOV unwrap.
220+ *
221+ * 3. A CFX wrap token with a plaintext length fewer than 16 bytes causes an
222+ * access before the beginning of the input buffer, possibly leading to a
223+ * crash.
224+ *
225+ * 4. A CFX wrap token with a plaintext EC value greater than the plaintext
226+ * length - 16 causes an integer underflow when computing the result length,
227+ * likely causing a crash.
228+ *
229+ * 5. An IOV unwrap operation will overrun the header buffer if an ASN.1
230+ * wrapper longer than the header buffer is present.
231+ *
232+ * 6. A pre-CFX wrap or MIC token with fewer than 24 bytes after the ASN.1
233 * header causes an input buffer overrun, usually leading to either a segv
234 * or a GSS_S_DEFECTIVE_TOKEN error due to garbage algorithm, filler, or
235- * sequence number values.
236+ * sequence number values. This vulnerability also applies to IOV unwrap.
237 *
238- * 3. A pre-CFX wrap token with fewer than 16 + cksumlen bytes after the ASN.1
239+ * 7. A pre-CFX wrap token with fewer than 16 + cksumlen bytes after the ASN.1
240 * header causes an integer underflow when computing the ciphertext length,
241 * leading to an allocation error on 32-bit platforms or a segv on 64-bit
242 * platforms. A pre-CFX MIC token of this size causes an input buffer
243 * overrun when comparing the checksum, perhaps leading to a segv.
244 *
245- * 4. A pre-CFX wrap token with fewer than conflen + padlen bytes in the
246+ * 8. A pre-CFX wrap token with fewer than conflen + padlen bytes in the
247 * ciphertext (where padlen is the last byte of the decrypted ciphertext)
248 * causes an integer underflow when computing the original message length,
249 * leading to an allocation error.
250 *
251- * 5. In the mechglue, truncated encapsulation in the initial context token can
252+ * 9. In the mechglue, truncated encapsulation in the initial context token can
253 * cause input buffer overruns in gss_accept_sec_context().
254- *
255- * Vulnerabilities #1 and #2 also apply to IOV unwrap, although tokens with
256- * fewer than 16 bytes after the ASN.1 header will be rejected.
257- * Vulnerabilities #2 and #5 can only be robustly detected using a
258- * memory-checking environment such as valgrind.
259 */
260
261 #include "k5-int.h"
262@@ -120,17 +130,25 @@ struct test {
263 }
264 };
265
266-/* Fake up enough of a CFX GSS context for gss_unwrap, using an AES key. */
267+static void *
268+ealloc(size_t len)
269+{
270+ void *ptr = calloc(len, 1);
271+
272+ if (ptr == NULL)
273+ abort();
274+ return ptr;
275+}
276+
277+/* Fake up enough of a CFX GSS context for gss_unwrap, using an AES key.
278+ * The context takes ownership of subkey. */
279 static gss_ctx_id_t
280-make_fake_cfx_context()
281+make_fake_cfx_context(krb5_key subkey)
282 {
283 gss_union_ctx_id_t uctx;
284 krb5_gss_ctx_id_t kgctx;
285- krb5_keyblock kb;
286
287- kgctx = calloc(1, sizeof(*kgctx));
288- if (kgctx == NULL)
289- abort();
290+ kgctx = ealloc(sizeof(*kgctx));
291 kgctx->established = 1;
292 kgctx->proto = 1;
293 if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)
294@@ -139,15 +157,10 @@ make_fake_cfx_context()
295 kgctx->sealalg = -1;
296 kgctx->signalg = -1;
297
298- kb.enctype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
299- kb.length = 16;
300- kb.contents = (unsigned char *)"1234567887654321";
301- if (krb5_k_create_key(NULL, &kb, &kgctx->subkey) != 0)
302- abort();
303+ kgctx->subkey = subkey;
304+ kgctx->cksumtype = CKSUMTYPE_HMAC_SHA1_96_AES128;
305
306- uctx = calloc(1, sizeof(*uctx));
307- if (uctx == NULL)
308- abort();
309+ uctx = ealloc(sizeof(*uctx));
310 uctx->mech_type = &mech_krb5;
311 uctx->internal_ctx_id = (gss_ctx_id_t)kgctx;
312 return (gss_ctx_id_t)uctx;
313@@ -163,9 +176,7 @@ make_fake_context(const struct test *test)
314 unsigned char encbuf[8];
315 size_t i;
316
317- kgctx = calloc(1, sizeof(*kgctx));
318- if (kgctx == NULL)
319- abort();
320+ kgctx = ealloc(sizeof(*kgctx));
321 kgctx->established = 1;
322 if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)
323 abort();
324@@ -192,9 +203,7 @@ make_fake_context(const struct test *test)
325 if (krb5_k_create_key(NULL, &kb, &kgctx->enc) != 0)
326 abort();
327
328- uctx = calloc(1, sizeof(*uctx));
329- if (uctx == NULL)
330- abort();
331+ uctx = ealloc(sizeof(*uctx));
332 uctx->mech_type = &mech_krb5;
333 uctx->internal_ctx_id = (gss_ctx_id_t)kgctx;
334 return (gss_ctx_id_t)uctx;
335@@ -224,9 +233,7 @@ make_token(unsigned char *token, size_t len, gss_buffer_t out)
336
337 assert(mech_krb5.length == 9);
338 assert(len + 11 < 128);
339- wrapped = malloc(len + 13);
340- if (wrapped == NULL)
341- abort();
342+ wrapped = ealloc(len + 13);
343 wrapped[0] = 0x60;
344 wrapped[1] = len + 11;
345 wrapped[2] = 0x06;
346@@ -237,6 +244,18 @@ make_token(unsigned char *token, size_t len, gss_buffer_t out)
347 out->value = wrapped;
348 }
349
350+/* Create a 16-byte header for a CFX confidential wrap token to be processed by
351+ * the fake CFX context. */
352+static void
353+write_cfx_header(uint16_t ec, uint8_t *out)
354+{
355+ memset(out, 0, 16);
356+ store_16_be(KG2_TOK_WRAP_MSG, out);
357+ out[2] = FLAG_WRAP_CONFIDENTIAL;
358+ out[3] = 0xFF;
359+ store_16_be(ec, out + 4);
360+}
361+
362 /* Unwrap a superficially valid RFC 1964 token with a CFX-only context, with
363 * regular and IOV unwrap. */
364 static void
365@@ -268,6 +287,134 @@ test_bogus_1964_token(gss_ctx_id_t ctx)
366 free(in.value);
367 }
368
369+static void
370+test_cfx_altered_ec(gss_ctx_id_t ctx, krb5_key subkey)
371+{
372+ OM_uint32 major, minor;
373+ uint8_t tokbuf[128], plainbuf[24];
374+ krb5_data plain;
375+ krb5_enc_data cipher;
376+ gss_buffer_desc in, out;
377+ gss_iov_buffer_desc iov[2];
378+
379+ /* Construct a header with a plaintext EC value of 3. */
380+ write_cfx_header(3, tokbuf);
381+
382+ /* Encrypt a plaintext and a copy of the header with the EC value 0. */
383+ memcpy(plainbuf, "truncate", 8);
384+ memcpy(plainbuf + 8, tokbuf, 16);
385+ store_16_be(0, plainbuf + 12);
386+ plain = make_data(plainbuf, 24);
387+ cipher.ciphertext.data = (char *)tokbuf + 16;
388+ cipher.ciphertext.length = sizeof(tokbuf) - 16;
389+ cipher.enctype = subkey->keyblock.enctype;
390+ if (krb5_k_encrypt(NULL, subkey, KG_USAGE_INITIATOR_SEAL, NULL,
391+ &plain, &cipher) != 0)
392+ abort();
393+
394+ /* Verify that the token is rejected by gss_unwrap(). */
395+ in.value = tokbuf;
396+ in.length = 16 + cipher.ciphertext.length;
397+ major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
398+ if (major != GSS_S_DEFECTIVE_TOKEN)
399+ abort();
400+ (void)gss_release_buffer(&minor, &out);
401+
402+ /* Verify that the token is rejected by gss_unwrap_iov(). */
403+ iov[0].type = GSS_IOV_BUFFER_TYPE_STREAM;
404+ iov[0].buffer = in;
405+ iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
406+ major = gss_unwrap_iov(&minor, ctx, NULL, NULL, iov, 2);
407+ if (major != GSS_S_DEFECTIVE_TOKEN)
408+ abort();
409+}
410+
411+static void
412+test_cfx_short_plaintext(gss_ctx_id_t ctx, krb5_key subkey)
413+{
414+ OM_uint32 major, minor;
415+ uint8_t tokbuf[128], zerobyte = 0;
416+ krb5_data plain;
417+ krb5_enc_data cipher;
418+ gss_buffer_desc in, out;
419+
420+ write_cfx_header(0, tokbuf);
421+
422+ /* Encrypt a single byte, with no copy of the header. */
423+ plain = make_data(&zerobyte, 1);
424+ cipher.ciphertext.data = (char *)tokbuf + 16;
425+ cipher.ciphertext.length = sizeof(tokbuf) - 16;
426+ cipher.enctype = subkey->keyblock.enctype;
427+ if (krb5_k_encrypt(NULL, subkey, KG_USAGE_INITIATOR_SEAL, NULL,
428+ &plain, &cipher) != 0)
429+ abort();
430+
431+ /* Verify that the token is rejected by gss_unwrap(). */
432+ in.value = tokbuf;
433+ in.length = 16 + cipher.ciphertext.length;
434+ major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
435+ if (major != GSS_S_DEFECTIVE_TOKEN)
436+ abort();
437+ (void)gss_release_buffer(&minor, &out);
438+}
439+
440+static void
441+test_cfx_large_ec(gss_ctx_id_t ctx, krb5_key subkey)
442+{
443+ OM_uint32 major, minor;
444+ uint8_t tokbuf[128] = { 0 }, plainbuf[20];
445+ krb5_data plain;
446+ krb5_enc_data cipher;
447+ gss_buffer_desc in, out;
448+
449+ /* Construct a header with an EC value of 5. */
450+ write_cfx_header(5, tokbuf);
451+
452+ /* Encrypt a 4-byte plaintext plus the header. */
453+ memcpy(plainbuf, "abcd", 4);
454+ memcpy(plainbuf + 4, tokbuf, 16);
455+ plain = make_data(plainbuf, 20);
456+ cipher.ciphertext.data = (char *)tokbuf + 16;
457+ cipher.ciphertext.length = sizeof(tokbuf) - 16;
458+ cipher.enctype = subkey->keyblock.enctype;
459+ if (krb5_k_encrypt(NULL, subkey, KG_USAGE_INITIATOR_SEAL, NULL,
460+ &plain, &cipher) != 0)
461+ abort();
462+
463+ /* Verify that the token is rejected by gss_unwrap(). */
464+ in.value = tokbuf;
465+ in.length = 16 + cipher.ciphertext.length;
466+ major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
467+ if (major != GSS_S_DEFECTIVE_TOKEN)
468+ abort();
469+ (void)gss_release_buffer(&minor, &out);
470+}
471+
472+static void
473+test_iov_large_asn1_wrapper(gss_ctx_id_t ctx)
474+{
475+ OM_uint32 minor, major;
476+ uint8_t databuf[10] = { 0 };
477+ gss_iov_buffer_desc iov[2];
478+
479+ /*
480+ * In this IOV array, the header contains a DER tag with a dangling eight
481+ * bytes of length field. The data IOV indicates a total token length
482+ * sufficient to contain the length bytes.
483+ */
484+ iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
485+ iov[0].buffer.value = ealloc(2);
486+ iov[0].buffer.length = 2;
487+ memcpy(iov[0].buffer.value, "\x60\x88", 2);
488+ iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
489+ iov[1].buffer.value = databuf;
490+ iov[1].buffer.length = 10;
491+ major = gss_unwrap_iov(&minor, ctx, NULL, NULL, iov, 2);
492+ if (major != GSS_S_DEFECTIVE_TOKEN)
493+ abort();
494+ free(iov[0].buffer.value);
495+}
496+
497 /* Process wrap and MIC tokens with incomplete headers. */
498 static void
499 test_short_header(gss_ctx_id_t ctx)
500@@ -417,9 +564,7 @@ try_accept(void *value, size_t len)
501 gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
502
503 /* Copy the provided value to make input overruns more obvious. */
504- in.value = malloc(len);
505- if (in.value == NULL)
506- abort();
507+ in.value = ealloc(len);
508 memcpy(in.value, value, len);
509 in.length = len;
510 (void)gss_accept_sec_context(&minor, &ctx, GSS_C_NO_CREDENTIAL, &in,
511@@ -454,11 +599,23 @@ test_short_encapsulation()
512 int
513 main(int argc, char **argv)
514 {
515+ krb5_keyblock kb;
516+ krb5_key cfx_subkey;
517 gss_ctx_id_t ctx;
518 size_t i;
519
520- ctx = make_fake_cfx_context();
521+ kb.enctype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
522+ kb.length = 16;
523+ kb.contents = (unsigned char *)"1234567887654321";
524+ if (krb5_k_create_key(NULL, &kb, &cfx_subkey) != 0)
525+ abort();
526+
527+ ctx = make_fake_cfx_context(cfx_subkey);
528 test_bogus_1964_token(ctx);
529+ test_cfx_altered_ec(ctx, cfx_subkey);
530+ test_cfx_short_plaintext(ctx, cfx_subkey);
531+ test_cfx_large_ec(ctx, cfx_subkey);
532+ test_iov_large_asn1_wrapper(ctx);
533 free_fake_context(ctx);
534
535 for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
536--
5372.25.1
538
diff --git a/meta-oe/recipes-connectivity/krb5/krb5_1.17.2.bb b/meta-oe/recipes-connectivity/krb5/krb5_1.17.2.bb
index a92066171b..ef256179fe 100644
--- a/meta-oe/recipes-connectivity/krb5/krb5_1.17.2.bb
+++ b/meta-oe/recipes-connectivity/krb5/krb5_1.17.2.bb
@@ -34,6 +34,8 @@ SRC_URI = "http://web.mit.edu/kerberos/dist/${BPN}/${SHRT_VER}/${BP}.tar.gz \
34 file://CVE-2021-37750.patch;striplevel=2 \ 34 file://CVE-2021-37750.patch;striplevel=2 \
35 file://CVE-2022-42898.patch;striplevel=2 \ 35 file://CVE-2022-42898.patch;striplevel=2 \
36 file://CVE-2023-36054.patch;striplevel=2 \ 36 file://CVE-2023-36054.patch;striplevel=2 \
37 file://CVE-2024-37370_37371-pre1.patch;striplevel=2 \
38 file://CVE-2024-37370_37371.patch;striplevel=2 \
37" 39"
38SRC_URI[md5sum] = "aa4337fffa3b61f22dbd0167f708818f" 40SRC_URI[md5sum] = "aa4337fffa3b61f22dbd0167f708818f"
39SRC_URI[sha256sum] = "1a4bba94df92f6d39a197a10687653e8bfbc9a2076e129f6eb92766974f86134" 41SRC_URI[sha256sum] = "1a4bba94df92f6d39a197a10687653e8bfbc9a2076e129f6eb92766974f86134"