import UBI krb5-1.21.1-2.el9_4
This commit is contained in:
parent
9fcb007fa5
commit
6f215b1801
@ -0,0 +1,535 @@
|
|||||||
|
From 7d9b143d1749cee1dc81c6b0f5a5493534bc6630 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Fri, 14 Jun 2024 10:56:12 -0400
|
||||||
|
Subject: [PATCH] Fix vulnerabilities in GSS message token handling
|
||||||
|
|
||||||
|
In gss_krb5int_unseal_token_v3() and gss_krb5int_unseal_v3_iov(),
|
||||||
|
verify the Extra Count field of CFX wrap tokens against the encrypted
|
||||||
|
header. Reported by Jacob Champion.
|
||||||
|
|
||||||
|
In gss_krb5int_unseal_token_v3(), check for a decrypted plaintext
|
||||||
|
length too short to contain the encrypted header and extra count
|
||||||
|
bytes. Reported by Jacob Champion.
|
||||||
|
|
||||||
|
In kg_unseal_iov_token(), separately track the header IOV length and
|
||||||
|
complete token length when parsing the token's ASN.1 wrapper. This
|
||||||
|
fix contains modified versions of functions from k5-der.h and
|
||||||
|
util_token.c; this duplication will be cleaned up in a future commit.
|
||||||
|
|
||||||
|
CVE-2024-37370:
|
||||||
|
|
||||||
|
In MIT krb5 release 1.3 and later, an attacker can modify the
|
||||||
|
plaintext Extra Count field of a confidential GSS krb5 wrap token,
|
||||||
|
causing the unwrapped token to appear truncated to the application.
|
||||||
|
|
||||||
|
CVE-2024-37371:
|
||||||
|
|
||||||
|
In MIT krb5 release 1.3 and later, an attacker can cause invalid
|
||||||
|
memory reads by sending message tokens with invalid length fields.
|
||||||
|
|
||||||
|
ticket: 9128 (new)
|
||||||
|
tags: pullup
|
||||||
|
target_version: 1.21-next
|
||||||
|
|
||||||
|
(cherry picked from commit b0a2f8a5365f2eec3e27d78907de9f9d2c80505a)
|
||||||
|
---
|
||||||
|
src/lib/gssapi/krb5/k5sealv3.c | 5 +
|
||||||
|
src/lib/gssapi/krb5/k5sealv3iov.c | 3 +-
|
||||||
|
src/lib/gssapi/krb5/k5unsealiov.c | 80 +++++++++-
|
||||||
|
src/tests/gssapi/t_invalid.c | 233 +++++++++++++++++++++++++-----
|
||||||
|
4 files changed, 275 insertions(+), 46 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/lib/gssapi/krb5/k5sealv3.c b/src/lib/gssapi/krb5/k5sealv3.c
|
||||||
|
index 3b4f8cb837..1fcbdfbb87 100644
|
||||||
|
--- a/src/lib/gssapi/krb5/k5sealv3.c
|
||||||
|
+++ b/src/lib/gssapi/krb5/k5sealv3.c
|
||||||
|
@@ -408,10 +408,15 @@ gss_krb5int_unseal_token_v3(krb5_context *contextptr,
|
||||||
|
/* Don't use bodysize here! Use the fact that
|
||||||
|
cipher.ciphertext.length has been adjusted to the
|
||||||
|
correct length. */
|
||||||
|
+ if (plain.length < 16 + ec) {
|
||||||
|
+ free(plain.data);
|
||||||
|
+ goto defective;
|
||||||
|
+ }
|
||||||
|
althdr = (unsigned char *)plain.data + plain.length - 16;
|
||||||
|
if (load_16_be(althdr) != KG2_TOK_WRAP_MSG
|
||||||
|
|| althdr[2] != ptr[2]
|
||||||
|
|| althdr[3] != ptr[3]
|
||||||
|
+ || load_16_be(althdr+4) != ec
|
||||||
|
|| memcmp(althdr+8, ptr+8, 8)) {
|
||||||
|
free(plain.data);
|
||||||
|
goto defective;
|
||||||
|
diff --git a/src/lib/gssapi/krb5/k5sealv3iov.c b/src/lib/gssapi/krb5/k5sealv3iov.c
|
||||||
|
index 333ee124dd..f8e90c35b4 100644
|
||||||
|
--- a/src/lib/gssapi/krb5/k5sealv3iov.c
|
||||||
|
+++ b/src/lib/gssapi/krb5/k5sealv3iov.c
|
||||||
|
@@ -402,9 +402,10 @@ gss_krb5int_unseal_v3_iov(krb5_context context,
|
||||||
|
if (load_16_be(althdr) != KG2_TOK_WRAP_MSG
|
||||||
|
|| althdr[2] != ptr[2]
|
||||||
|
|| althdr[3] != ptr[3]
|
||||||
|
+ || load_16_be(althdr + 4) != ec
|
||||||
|
|| memcmp(althdr + 8, ptr + 8, 8) != 0) {
|
||||||
|
*minor_status = 0;
|
||||||
|
- return GSS_S_BAD_SIG;
|
||||||
|
+ return GSS_S_DEFECTIVE_TOKEN;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Verify checksum: note EC is checksum size here, not padding */
|
||||||
|
diff --git a/src/lib/gssapi/krb5/k5unsealiov.c b/src/lib/gssapi/krb5/k5unsealiov.c
|
||||||
|
index 3ce2a90ce9..6a6585d9af 100644
|
||||||
|
--- a/src/lib/gssapi/krb5/k5unsealiov.c
|
||||||
|
+++ b/src/lib/gssapi/krb5/k5unsealiov.c
|
||||||
|
@@ -25,6 +25,7 @@
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "k5-int.h"
|
||||||
|
+#include "k5-der.h"
|
||||||
|
#include "gssapiP_krb5.h"
|
||||||
|
|
||||||
|
static OM_uint32
|
||||||
|
@@ -247,6 +248,73 @@ cleanup:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/* Similar to k5_der_get_value(), but output an unchecked content length
|
||||||
|
+ * instead of a k5input containing the contents. */
|
||||||
|
+static inline bool
|
||||||
|
+get_der_tag(struct k5input *in, uint8_t idbyte, size_t *len_out)
|
||||||
|
+{
|
||||||
|
+ uint8_t lenbyte, i;
|
||||||
|
+ size_t len;
|
||||||
|
+
|
||||||
|
+ /* Do nothing if in is empty or the next byte doesn't match idbyte. */
|
||||||
|
+ if (in->status || in->len == 0 || *in->ptr != idbyte)
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
+ /* Advance past the identifier byte and decode the length. */
|
||||||
|
+ (void)k5_input_get_byte(in);
|
||||||
|
+ lenbyte = k5_input_get_byte(in);
|
||||||
|
+ if (lenbyte < 128) {
|
||||||
|
+ len = lenbyte;
|
||||||
|
+ } else {
|
||||||
|
+ len = 0;
|
||||||
|
+ for (i = 0; i < (lenbyte & 0x7F); i++) {
|
||||||
|
+ if (len > (SIZE_MAX >> 8)) {
|
||||||
|
+ k5_input_set_status(in, EOVERFLOW);
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ len = (len << 8) | k5_input_get_byte(in);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (in->status)
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
+ *len_out = len;
|
||||||
|
+ return true;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Similar to g_verify_token_header() without toktype or flags, but do not read
|
||||||
|
+ * more than *header_len bytes of ASN.1 wrapper, and on output set *header_len
|
||||||
|
+ * to the remaining number of header bytes. Verify the outer DER tag's length
|
||||||
|
+ * against token_len, which may be larger (but not smaller) than *header_len.
|
||||||
|
+ */
|
||||||
|
+static gss_int32
|
||||||
|
+verify_detached_wrapper(const gss_OID_desc *mech, size_t *header_len,
|
||||||
|
+ uint8_t **header_in, size_t token_len)
|
||||||
|
+{
|
||||||
|
+ struct k5input in, mech_der;
|
||||||
|
+ gss_OID_desc toid;
|
||||||
|
+ size_t len;
|
||||||
|
+
|
||||||
|
+ k5_input_init(&in, *header_in, *header_len);
|
||||||
|
+
|
||||||
|
+ if (get_der_tag(&in, 0x60, &len)) {
|
||||||
|
+ if (len != token_len - (in.ptr - *header_in))
|
||||||
|
+ return G_BAD_TOK_HEADER;
|
||||||
|
+ if (!k5_der_get_value(&in, 0x06, &mech_der))
|
||||||
|
+ return G_BAD_TOK_HEADER;
|
||||||
|
+ toid.elements = (uint8_t *)mech_der.ptr;
|
||||||
|
+ toid.length = mech_der.len;
|
||||||
|
+ if (!g_OID_equal(&toid, mech))
|
||||||
|
+ return G_WRONG_MECH;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ *header_in = (uint8_t *)in.ptr;
|
||||||
|
+ *header_len = in.len;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Caller must provide TOKEN | DATA | PADDING | TRAILER, except
|
||||||
|
* for DCE in which case it can just provide TOKEN | DATA (must
|
||||||
|
@@ -267,8 +335,7 @@ kg_unseal_iov_token(OM_uint32 *minor_status,
|
||||||
|
gss_iov_buffer_t header;
|
||||||
|
gss_iov_buffer_t padding;
|
||||||
|
gss_iov_buffer_t trailer;
|
||||||
|
- size_t input_length;
|
||||||
|
- unsigned int bodysize;
|
||||||
|
+ size_t input_length, hlen;
|
||||||
|
int toktype2;
|
||||||
|
|
||||||
|
header = kg_locate_header_iov(iov, iov_count, toktype);
|
||||||
|
@@ -298,15 +365,14 @@ kg_unseal_iov_token(OM_uint32 *minor_status,
|
||||||
|
input_length += trailer->buffer.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
- code = g_verify_token_header(ctx->mech_used,
|
||||||
|
- &bodysize, &ptr, -1,
|
||||||
|
- input_length, 0);
|
||||||
|
+ hlen = header->buffer.length;
|
||||||
|
+ code = verify_detached_wrapper(ctx->mech_used, &hlen, &ptr, input_length);
|
||||||
|
if (code != 0) {
|
||||||
|
*minor_status = code;
|
||||||
|
return GSS_S_DEFECTIVE_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (bodysize < 2) {
|
||||||
|
+ if (hlen < 2) {
|
||||||
|
*minor_status = (OM_uint32)G_BAD_TOK_HEADER;
|
||||||
|
return GSS_S_DEFECTIVE_TOKEN;
|
||||||
|
}
|
||||||
|
@@ -314,7 +380,7 @@ kg_unseal_iov_token(OM_uint32 *minor_status,
|
||||||
|
toktype2 = load_16_be(ptr);
|
||||||
|
|
||||||
|
ptr += 2;
|
||||||
|
- bodysize -= 2;
|
||||||
|
+ hlen -= 2;
|
||||||
|
|
||||||
|
switch (toktype2) {
|
||||||
|
case KG2_TOK_MIC_MSG:
|
||||||
|
diff --git a/src/tests/gssapi/t_invalid.c b/src/tests/gssapi/t_invalid.c
|
||||||
|
index fb8fe55111..8192935099 100644
|
||||||
|
--- a/src/tests/gssapi/t_invalid.c
|
||||||
|
+++ b/src/tests/gssapi/t_invalid.c
|
||||||
|
@@ -36,31 +36,41 @@
|
||||||
|
*
|
||||||
|
* 1. A pre-CFX wrap or MIC token processed with a CFX-only context causes a
|
||||||
|
* null pointer dereference. (The token must use SEAL_ALG_NONE or it will
|
||||||
|
- * be rejected.)
|
||||||
|
+ * be rejected.) This vulnerability also applies to IOV unwrap.
|
||||||
|
*
|
||||||
|
- * 2. A pre-CFX wrap or MIC token with fewer than 24 bytes after the ASN.1
|
||||||
|
+ * 2. A CFX wrap token with a different value of EC between the plaintext and
|
||||||
|
+ * encrypted copies will be erroneously accepted, which allows a message
|
||||||
|
+ * truncation attack. This vulnerability also applies to IOV unwrap.
|
||||||
|
+ *
|
||||||
|
+ * 3. A CFX wrap token with a plaintext length fewer than 16 bytes causes an
|
||||||
|
+ * access before the beginning of the input buffer, possibly leading to a
|
||||||
|
+ * crash.
|
||||||
|
+ *
|
||||||
|
+ * 4. A CFX wrap token with a plaintext EC value greater than the plaintext
|
||||||
|
+ * length - 16 causes an integer underflow when computing the result length,
|
||||||
|
+ * likely causing a crash.
|
||||||
|
+ *
|
||||||
|
+ * 5. An IOV unwrap operation will overrun the header buffer if an ASN.1
|
||||||
|
+ * wrapper longer than the header buffer is present.
|
||||||
|
+ *
|
||||||
|
+ * 6. A pre-CFX wrap or MIC token with fewer than 24 bytes after the ASN.1
|
||||||
|
* header causes an input buffer overrun, usually leading to either a segv
|
||||||
|
* or a GSS_S_DEFECTIVE_TOKEN error due to garbage algorithm, filler, or
|
||||||
|
- * sequence number values.
|
||||||
|
+ * sequence number values. This vulnerability also applies to IOV unwrap.
|
||||||
|
*
|
||||||
|
- * 3. A pre-CFX wrap token with fewer than 16 + cksumlen bytes after the ASN.1
|
||||||
|
+ * 7. A pre-CFX wrap token with fewer than 16 + cksumlen bytes after the ASN.1
|
||||||
|
* header causes an integer underflow when computing the ciphertext length,
|
||||||
|
* leading to an allocation error on 32-bit platforms or a segv on 64-bit
|
||||||
|
* platforms. A pre-CFX MIC token of this size causes an input buffer
|
||||||
|
* overrun when comparing the checksum, perhaps leading to a segv.
|
||||||
|
*
|
||||||
|
- * 4. A pre-CFX wrap token with fewer than conflen + padlen bytes in the
|
||||||
|
+ * 8. A pre-CFX wrap token with fewer than conflen + padlen bytes in the
|
||||||
|
* ciphertext (where padlen is the last byte of the decrypted ciphertext)
|
||||||
|
* causes an integer underflow when computing the original message length,
|
||||||
|
* leading to an allocation error.
|
||||||
|
*
|
||||||
|
- * 5. In the mechglue, truncated encapsulation in the initial context token can
|
||||||
|
+ * 9. In the mechglue, truncated encapsulation in the initial context token can
|
||||||
|
* cause input buffer overruns in gss_accept_sec_context().
|
||||||
|
- *
|
||||||
|
- * Vulnerabilities #1 and #2 also apply to IOV unwrap, although tokens with
|
||||||
|
- * fewer than 16 bytes after the ASN.1 header will be rejected.
|
||||||
|
- * Vulnerabilities #2 and #5 can only be robustly detected using a
|
||||||
|
- * memory-checking environment such as valgrind.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "k5-int.h"
|
||||||
|
@@ -97,17 +107,25 @@ struct test {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
-/* Fake up enough of a CFX GSS context for gss_unwrap, using an AES key. */
|
||||||
|
+static void *
|
||||||
|
+ealloc(size_t len)
|
||||||
|
+{
|
||||||
|
+ void *ptr = calloc(len, 1);
|
||||||
|
+
|
||||||
|
+ if (ptr == NULL)
|
||||||
|
+ abort();
|
||||||
|
+ return ptr;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Fake up enough of a CFX GSS context for gss_unwrap, using an AES key.
|
||||||
|
+ * The context takes ownership of subkey. */
|
||||||
|
static gss_ctx_id_t
|
||||||
|
-make_fake_cfx_context()
|
||||||
|
+make_fake_cfx_context(krb5_key subkey)
|
||||||
|
{
|
||||||
|
gss_union_ctx_id_t uctx;
|
||||||
|
krb5_gss_ctx_id_t kgctx;
|
||||||
|
- krb5_keyblock kb;
|
||||||
|
|
||||||
|
- kgctx = calloc(1, sizeof(*kgctx));
|
||||||
|
- if (kgctx == NULL)
|
||||||
|
- abort();
|
||||||
|
+ kgctx = ealloc(sizeof(*kgctx));
|
||||||
|
kgctx->established = 1;
|
||||||
|
kgctx->proto = 1;
|
||||||
|
if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)
|
||||||
|
@@ -116,15 +134,10 @@ make_fake_cfx_context()
|
||||||
|
kgctx->sealalg = -1;
|
||||||
|
kgctx->signalg = -1;
|
||||||
|
|
||||||
|
- kb.enctype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
|
||||||
|
- kb.length = 16;
|
||||||
|
- kb.contents = (unsigned char *)"1234567887654321";
|
||||||
|
- if (krb5_k_create_key(NULL, &kb, &kgctx->subkey) != 0)
|
||||||
|
- abort();
|
||||||
|
+ kgctx->subkey = subkey;
|
||||||
|
+ kgctx->cksumtype = CKSUMTYPE_HMAC_SHA1_96_AES128;
|
||||||
|
|
||||||
|
- uctx = calloc(1, sizeof(*uctx));
|
||||||
|
- if (uctx == NULL)
|
||||||
|
- abort();
|
||||||
|
+ uctx = ealloc(sizeof(*uctx));
|
||||||
|
uctx->mech_type = &mech_krb5;
|
||||||
|
uctx->internal_ctx_id = (gss_ctx_id_t)kgctx;
|
||||||
|
return (gss_ctx_id_t)uctx;
|
||||||
|
@@ -138,9 +151,7 @@ make_fake_context(const struct test *test)
|
||||||
|
krb5_gss_ctx_id_t kgctx;
|
||||||
|
krb5_keyblock kb;
|
||||||
|
|
||||||
|
- kgctx = calloc(1, sizeof(*kgctx));
|
||||||
|
- if (kgctx == NULL)
|
||||||
|
- abort();
|
||||||
|
+ kgctx = ealloc(sizeof(*kgctx));
|
||||||
|
kgctx->established = 1;
|
||||||
|
if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)
|
||||||
|
abort();
|
||||||
|
@@ -162,9 +173,7 @@ make_fake_context(const struct test *test)
|
||||||
|
if (krb5_k_create_key(NULL, &kb, &kgctx->enc) != 0)
|
||||||
|
abort();
|
||||||
|
|
||||||
|
- uctx = calloc(1, sizeof(*uctx));
|
||||||
|
- if (uctx == NULL)
|
||||||
|
- abort();
|
||||||
|
+ uctx = ealloc(sizeof(*uctx));
|
||||||
|
uctx->mech_type = &mech_krb5;
|
||||||
|
uctx->internal_ctx_id = (gss_ctx_id_t)kgctx;
|
||||||
|
return (gss_ctx_id_t)uctx;
|
||||||
|
@@ -194,9 +203,7 @@ make_token(unsigned char *token, size_t len, gss_buffer_t out)
|
||||||
|
|
||||||
|
assert(mech_krb5.length == 9);
|
||||||
|
assert(len + 11 < 128);
|
||||||
|
- wrapped = malloc(len + 13);
|
||||||
|
- if (wrapped == NULL)
|
||||||
|
- abort();
|
||||||
|
+ wrapped = ealloc(len + 13);
|
||||||
|
wrapped[0] = 0x60;
|
||||||
|
wrapped[1] = len + 11;
|
||||||
|
wrapped[2] = 0x06;
|
||||||
|
@@ -207,6 +214,18 @@ make_token(unsigned char *token, size_t len, gss_buffer_t out)
|
||||||
|
out->value = wrapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/* Create a 16-byte header for a CFX confidential wrap token to be processed by
|
||||||
|
+ * the fake CFX context. */
|
||||||
|
+static void
|
||||||
|
+write_cfx_header(uint16_t ec, uint8_t *out)
|
||||||
|
+{
|
||||||
|
+ memset(out, 0, 16);
|
||||||
|
+ store_16_be(KG2_TOK_WRAP_MSG, out);
|
||||||
|
+ out[2] = FLAG_WRAP_CONFIDENTIAL;
|
||||||
|
+ out[3] = 0xFF;
|
||||||
|
+ store_16_be(ec, out + 4);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/* Unwrap a superficially valid RFC 1964 token with a CFX-only context, with
|
||||||
|
* regular and IOV unwrap. */
|
||||||
|
static void
|
||||||
|
@@ -238,6 +257,134 @@ test_bogus_1964_token(gss_ctx_id_t ctx)
|
||||||
|
free(in.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void
|
||||||
|
+test_cfx_altered_ec(gss_ctx_id_t ctx, krb5_key subkey)
|
||||||
|
+{
|
||||||
|
+ OM_uint32 major, minor;
|
||||||
|
+ uint8_t tokbuf[128], plainbuf[24];
|
||||||
|
+ krb5_data plain;
|
||||||
|
+ krb5_enc_data cipher;
|
||||||
|
+ gss_buffer_desc in, out;
|
||||||
|
+ gss_iov_buffer_desc iov[2];
|
||||||
|
+
|
||||||
|
+ /* Construct a header with a plaintext EC value of 3. */
|
||||||
|
+ write_cfx_header(3, tokbuf);
|
||||||
|
+
|
||||||
|
+ /* Encrypt a plaintext and a copy of the header with the EC value 0. */
|
||||||
|
+ memcpy(plainbuf, "truncate", 8);
|
||||||
|
+ memcpy(plainbuf + 8, tokbuf, 16);
|
||||||
|
+ store_16_be(0, plainbuf + 12);
|
||||||
|
+ plain = make_data(plainbuf, 24);
|
||||||
|
+ cipher.ciphertext.data = (char *)tokbuf + 16;
|
||||||
|
+ cipher.ciphertext.length = sizeof(tokbuf) - 16;
|
||||||
|
+ cipher.enctype = subkey->keyblock.enctype;
|
||||||
|
+ if (krb5_k_encrypt(NULL, subkey, KG_USAGE_INITIATOR_SEAL, NULL,
|
||||||
|
+ &plain, &cipher) != 0)
|
||||||
|
+ abort();
|
||||||
|
+
|
||||||
|
+ /* Verify that the token is rejected by gss_unwrap(). */
|
||||||
|
+ in.value = tokbuf;
|
||||||
|
+ in.length = 16 + cipher.ciphertext.length;
|
||||||
|
+ major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
|
||||||
|
+ if (major != GSS_S_DEFECTIVE_TOKEN)
|
||||||
|
+ abort();
|
||||||
|
+ (void)gss_release_buffer(&minor, &out);
|
||||||
|
+
|
||||||
|
+ /* Verify that the token is rejected by gss_unwrap_iov(). */
|
||||||
|
+ iov[0].type = GSS_IOV_BUFFER_TYPE_STREAM;
|
||||||
|
+ iov[0].buffer = in;
|
||||||
|
+ iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
|
||||||
|
+ major = gss_unwrap_iov(&minor, ctx, NULL, NULL, iov, 2);
|
||||||
|
+ if (major != GSS_S_DEFECTIVE_TOKEN)
|
||||||
|
+ abort();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+test_cfx_short_plaintext(gss_ctx_id_t ctx, krb5_key subkey)
|
||||||
|
+{
|
||||||
|
+ OM_uint32 major, minor;
|
||||||
|
+ uint8_t tokbuf[128], zerobyte = 0;
|
||||||
|
+ krb5_data plain;
|
||||||
|
+ krb5_enc_data cipher;
|
||||||
|
+ gss_buffer_desc in, out;
|
||||||
|
+
|
||||||
|
+ write_cfx_header(0, tokbuf);
|
||||||
|
+
|
||||||
|
+ /* Encrypt a single byte, with no copy of the header. */
|
||||||
|
+ plain = make_data(&zerobyte, 1);
|
||||||
|
+ cipher.ciphertext.data = (char *)tokbuf + 16;
|
||||||
|
+ cipher.ciphertext.length = sizeof(tokbuf) - 16;
|
||||||
|
+ cipher.enctype = subkey->keyblock.enctype;
|
||||||
|
+ if (krb5_k_encrypt(NULL, subkey, KG_USAGE_INITIATOR_SEAL, NULL,
|
||||||
|
+ &plain, &cipher) != 0)
|
||||||
|
+ abort();
|
||||||
|
+
|
||||||
|
+ /* Verify that the token is rejected by gss_unwrap(). */
|
||||||
|
+ in.value = tokbuf;
|
||||||
|
+ in.length = 16 + cipher.ciphertext.length;
|
||||||
|
+ major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
|
||||||
|
+ if (major != GSS_S_DEFECTIVE_TOKEN)
|
||||||
|
+ abort();
|
||||||
|
+ (void)gss_release_buffer(&minor, &out);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+test_cfx_large_ec(gss_ctx_id_t ctx, krb5_key subkey)
|
||||||
|
+{
|
||||||
|
+ OM_uint32 major, minor;
|
||||||
|
+ uint8_t tokbuf[128] = { 0 }, plainbuf[20];
|
||||||
|
+ krb5_data plain;
|
||||||
|
+ krb5_enc_data cipher;
|
||||||
|
+ gss_buffer_desc in, out;
|
||||||
|
+
|
||||||
|
+ /* Construct a header with an EC value of 5. */
|
||||||
|
+ write_cfx_header(5, tokbuf);
|
||||||
|
+
|
||||||
|
+ /* Encrypt a 4-byte plaintext plus the header. */
|
||||||
|
+ memcpy(plainbuf, "abcd", 4);
|
||||||
|
+ memcpy(plainbuf + 4, tokbuf, 16);
|
||||||
|
+ plain = make_data(plainbuf, 20);
|
||||||
|
+ cipher.ciphertext.data = (char *)tokbuf + 16;
|
||||||
|
+ cipher.ciphertext.length = sizeof(tokbuf) - 16;
|
||||||
|
+ cipher.enctype = subkey->keyblock.enctype;
|
||||||
|
+ if (krb5_k_encrypt(NULL, subkey, KG_USAGE_INITIATOR_SEAL, NULL,
|
||||||
|
+ &plain, &cipher) != 0)
|
||||||
|
+ abort();
|
||||||
|
+
|
||||||
|
+ /* Verify that the token is rejected by gss_unwrap(). */
|
||||||
|
+ in.value = tokbuf;
|
||||||
|
+ in.length = 16 + cipher.ciphertext.length;
|
||||||
|
+ major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
|
||||||
|
+ if (major != GSS_S_DEFECTIVE_TOKEN)
|
||||||
|
+ abort();
|
||||||
|
+ (void)gss_release_buffer(&minor, &out);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+test_iov_large_asn1_wrapper(gss_ctx_id_t ctx)
|
||||||
|
+{
|
||||||
|
+ OM_uint32 minor, major;
|
||||||
|
+ uint8_t databuf[10] = { 0 };
|
||||||
|
+ gss_iov_buffer_desc iov[2];
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * In this IOV array, the header contains a DER tag with a dangling eight
|
||||||
|
+ * bytes of length field. The data IOV indicates a total token length
|
||||||
|
+ * sufficient to contain the length bytes.
|
||||||
|
+ */
|
||||||
|
+ iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
|
||||||
|
+ iov[0].buffer.value = ealloc(2);
|
||||||
|
+ iov[0].buffer.length = 2;
|
||||||
|
+ memcpy(iov[0].buffer.value, "\x60\x88", 2);
|
||||||
|
+ iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
|
||||||
|
+ iov[1].buffer.value = databuf;
|
||||||
|
+ iov[1].buffer.length = 10;
|
||||||
|
+ major = gss_unwrap_iov(&minor, ctx, NULL, NULL, iov, 2);
|
||||||
|
+ if (major != GSS_S_DEFECTIVE_TOKEN)
|
||||||
|
+ abort();
|
||||||
|
+ free(iov[0].buffer.value);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/* Process wrap and MIC tokens with incomplete headers. */
|
||||||
|
static void
|
||||||
|
test_short_header(gss_ctx_id_t ctx)
|
||||||
|
@@ -387,9 +534,7 @@ try_accept(void *value, size_t len)
|
||||||
|
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
|
||||||
|
|
||||||
|
/* Copy the provided value to make input overruns more obvious. */
|
||||||
|
- in.value = malloc(len);
|
||||||
|
- if (in.value == NULL)
|
||||||
|
- abort();
|
||||||
|
+ in.value = ealloc(len);
|
||||||
|
memcpy(in.value, value, len);
|
||||||
|
in.length = len;
|
||||||
|
(void)gss_accept_sec_context(&minor, &ctx, GSS_C_NO_CREDENTIAL, &in,
|
||||||
|
@@ -424,11 +569,23 @@ test_short_encapsulation()
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
+ krb5_keyblock kb;
|
||||||
|
+ krb5_key cfx_subkey;
|
||||||
|
gss_ctx_id_t ctx;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
- ctx = make_fake_cfx_context();
|
||||||
|
+ kb.enctype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
|
||||||
|
+ kb.length = 16;
|
||||||
|
+ kb.contents = (unsigned char *)"1234567887654321";
|
||||||
|
+ if (krb5_k_create_key(NULL, &kb, &cfx_subkey) != 0)
|
||||||
|
+ abort();
|
||||||
|
+
|
||||||
|
+ ctx = make_fake_cfx_context(cfx_subkey);
|
||||||
|
test_bogus_1964_token(ctx);
|
||||||
|
+ test_cfx_altered_ec(ctx, cfx_subkey);
|
||||||
|
+ test_cfx_short_plaintext(ctx, cfx_subkey);
|
||||||
|
+ test_cfx_large_ec(ctx, cfx_subkey);
|
||||||
|
+ test_iov_large_asn1_wrapper(ctx);
|
||||||
|
free_fake_context(ctx);
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
|
||||||
|
--
|
||||||
|
2.45.1
|
||||||
|
|
@ -34,7 +34,7 @@
|
|||||||
#
|
#
|
||||||
# baserelease is what we have standardized across Fedora and what
|
# baserelease is what we have standardized across Fedora and what
|
||||||
# rpmdev-bumpspec knows how to handle.
|
# rpmdev-bumpspec knows how to handle.
|
||||||
%global baserelease 1
|
%global baserelease 2
|
||||||
|
|
||||||
# This should be e.g. beta1 or %%nil
|
# This should be e.g. beta1 or %%nil
|
||||||
%global pre_release %nil
|
%global pre_release %nil
|
||||||
@ -98,6 +98,7 @@ Patch0012: 0012-downstream-Allow-to-set-PAC-ticket-signature-as-opti.patch
|
|||||||
Patch0013: 0013-downstream-Make-PKINIT-CMS-SHA-1-signature-verificat.patch
|
Patch0013: 0013-downstream-Make-PKINIT-CMS-SHA-1-signature-verificat.patch
|
||||||
Patch0014: 0014-Enable-PKINIT-if-at-least-one-group-is-available.patch
|
Patch0014: 0014-Enable-PKINIT-if-at-least-one-group-is-available.patch
|
||||||
Patch0015: 0015-Fix-double-free-in-KDC-TGS-processing.patch
|
Patch0015: 0015-Fix-double-free-in-KDC-TGS-processing.patch
|
||||||
|
Patch0016: 0016-Fix-vulnerabilities-in-GSS-message-token-handling.patch
|
||||||
|
|
||||||
License: MIT
|
License: MIT
|
||||||
URL: https://web.mit.edu/kerberos/www/
|
URL: https://web.mit.edu/kerberos/www/
|
||||||
@ -662,6 +663,11 @@ exit 0
|
|||||||
%{_libdir}/libkadm5srv_mit.so.*
|
%{_libdir}/libkadm5srv_mit.so.*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Mon Jul 01 2024 Julien Rische <jrische@redhat.com> - 1.21.1-2
|
||||||
|
- CVE-2024-37370 CVE-2024-37371
|
||||||
|
Fix vulnerabilities in GSS message token handling
|
||||||
|
Resolves: RHEL-45401 RHEL-45390
|
||||||
|
|
||||||
* Tue Aug 08 2023 Julien Rische <jrische@redhat.com> - 1.21.1-1
|
* Tue Aug 08 2023 Julien Rische <jrische@redhat.com> - 1.21.1-1
|
||||||
- New upstream version (1.21.1)
|
- New upstream version (1.21.1)
|
||||||
- Fix double-free in KDC TGS processing (CVE-2023-39975)
|
- Fix double-free in KDC TGS processing (CVE-2023-39975)
|
||||||
|
Loading…
Reference in New Issue
Block a user