new file mode 100644
@@ -0,0 +1,628 @@
+From 871125fea8ce0370a972bf65f7d1de63f619b06c Mon Sep 17 00:00:00 2001
+From: Julien Rische <jrische@redhat.com>
+Date: Thu, 22 Aug 2024 17:15:50 +0200
+Subject: [PATCH] Generate and verify message MACs in libkrad
+
+Implement some of the measures specified in
+draft-ietf-radext-deprecating-radius-03 for mitigating the BlastRADIUS
+attack (CVE-2024-3596):
+
+* Include a Message-Authenticator MAC as the first attribute when
+ generating a packet of type Access-Request, Access-Reject,
+ Access-Accept, or Access-Challenge (sections 5.2.1 and 5.2.4), if
+ the secret is non-empty. (An empty secret indicates the use of Unix
+ domain socket transport.)
+
+* Validate the Message-Authenticator MAC in received packets, if
+ present.
+
+FreeRADIUS enforces Message-Authenticator as of versions 3.2.5 and
+3.0.27. libkrad must generate Message-Authenticator attributes in
+order to remain compatible with these implementations.
+
+[ghudson@mit.edu: adjusted style and naming; simplified some
+functions; edited commit message]
+
+ticket: 9142 (new)
+tags: pullup
+target_version: 1.21-next
+
+CVE: CVE-2024-3596
+Upstream-Status: Backport [https://github.com/krb5/krb5/commit/871125fea8ce0370a972bf65f7d1de63f619b06c]
+Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
+---
+ src/include/k5-int.h | 5 +
+ src/lib/crypto/krb/checksum_hmac_md5.c | 28 ++++
+ src/lib/crypto/libk5crypto.exports | 1 +
+ src/lib/krad/attr.c | 17 ++
+ src/lib/krad/attrset.c | 58 +++++--
+ src/lib/krad/internal.h | 7 +-
+ src/lib/krad/packet.c | 205 +++++++++++++++++++++++--
+ src/lib/krad/t_attrset.c | 2 +-
+ src/lib/krad/t_daemon.py | 3 +-
+ src/lib/krad/t_packet.c | 11 ++
+ src/tests/t_otp.py | 3 +
+ 11 files changed, 309 insertions(+), 31 deletions(-)
+
+diff --git a/src/include/k5-int.h b/src/include/k5-int.h
+index 2f7791b..55706b7 100644
+--- a/src/include/k5-int.h
++++ b/src/include/k5-int.h
+@@ -2404,4 +2404,9 @@ krb5_boolean
+ k5_sname_compare(krb5_context context, krb5_const_principal sname,
+ krb5_const_principal princ);
+
++/* Generate an HMAC-MD5 keyed checksum as specified by RFC 2104. */
++krb5_error_code
++k5_hmac_md5(const krb5_data *key, const krb5_crypto_iov *data, size_t num_data,
++ krb5_data *output);
++
+ #endif /* _KRB5_INT_H */
+diff --git a/src/lib/crypto/krb/checksum_hmac_md5.c b/src/lib/crypto/krb/checksum_hmac_md5.c
+index ec024f3..a809388 100644
+--- a/src/lib/crypto/krb/checksum_hmac_md5.c
++++ b/src/lib/crypto/krb/checksum_hmac_md5.c
+@@ -92,3 +92,31 @@ cleanup:
+ free(hash_iov);
+ return ret;
+ }
++
++krb5_error_code
++k5_hmac_md5(const krb5_data *key, const krb5_crypto_iov *data, size_t num_data,
++ krb5_data *output)
++{
++ krb5_error_code ret;
++ const struct krb5_hash_provider *hash = &krb5int_hash_md5;
++ krb5_keyblock keyblock = { 0 };
++ krb5_data hashed_key;
++ uint8_t hkeybuf[16];
++ krb5_crypto_iov iov;
++
++ /* Hash the key if it is longer than the block size. */
++ if (key->length > hash->blocksize) {
++ hashed_key = make_data(hkeybuf, sizeof(hkeybuf));
++ iov.flags = KRB5_CRYPTO_TYPE_DATA;
++ iov.data = *key;
++ ret = hash->hash(&iov, 1, &hashed_key);
++ if (ret)
++ return ret;
++ key = &hashed_key;
++ }
++
++ keyblock.magic = KV5M_KEYBLOCK;
++ keyblock.length = key->length;
++ keyblock.contents = (uint8_t *)key->data;
++ return krb5int_hmac_keyblock(hash, &keyblock, data, num_data, output);
++}
+diff --git a/src/lib/crypto/libk5crypto.exports b/src/lib/crypto/libk5crypto.exports
+index 052f4d4..2b27028 100644
+--- a/src/lib/crypto/libk5crypto.exports
++++ b/src/lib/crypto/libk5crypto.exports
+@@ -103,3 +103,4 @@ krb5_c_prfplus
+ krb5_c_derive_prfplus
+ k5_enctype_to_ssf
+ krb5int_c_deprecated_enctype
++k5_hmac_md5
+diff --git a/src/lib/krad/attr.c b/src/lib/krad/attr.c
+index 9c13d9d..4ad3212 100644
+--- a/src/lib/krad/attr.c
++++ b/src/lib/krad/attr.c
+@@ -122,6 +122,23 @@ static const attribute_record attributes[UCHAR_MAX] = {
+ {"NAS-Port-Type", 4, 4, NULL, NULL},
+ {"Port-Limit", 4, 4, NULL, NULL},
+ {"Login-LAT-Port", 1, MAX_ATTRSIZE, NULL, NULL},
++ {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */
++ {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */
++ {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */
++ {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */
++ {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */
++ {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */
++ {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */
++ {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */
++ {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */
++ {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */
++ {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */
++ {NULL, 0, 0, NULL, NULL}, /* Password-Retry */
++ {NULL, 0, 0, NULL, NULL}, /* Prompt */
++ {NULL, 0, 0, NULL, NULL}, /* Connect-Info */
++ {NULL, 0, 0, NULL, NULL}, /* Configuration-Token */
++ {NULL, 0, 0, NULL, NULL}, /* EAP-Message */
++ {"Message-Authenticator", MD5_DIGEST_SIZE, MD5_DIGEST_SIZE, NULL, NULL},
+ };
+
+ /* Encode User-Password attribute. */
+diff --git a/src/lib/krad/attrset.c b/src/lib/krad/attrset.c
+index f309f15..488bfce 100644
+--- a/src/lib/krad/attrset.c
++++ b/src/lib/krad/attrset.c
+@@ -164,14 +164,42 @@ krad_attrset_copy(const krad_attrset *set, krad_attrset **copy)
+ return 0;
+ }
+
++/* Place an encoded attributes into outbuf at position *i. Increment *i by the
++ * length of the encoding. */
++static krb5_error_code
++append_attr(krb5_context ctx, const char *secret,
++ const uint8_t *auth, krad_attr type, const krb5_data *data,
++ uint8_t outbuf[MAX_ATTRSETSIZE], size_t *i)
++{
++ uint8_t buffer[MAX_ATTRSIZE];
++ size_t attrlen;
++ krb5_error_code retval;
++
++ retval = kr_attr_encode(ctx, secret, auth, type, data, buffer, &attrlen);
++ if (retval)
++ return retval;
++
++ if (attrlen > MAX_ATTRSETSIZE - *i - 2)
++ return EMSGSIZE;
++
++ outbuf[(*i)++] = type;
++ outbuf[(*i)++] = attrlen + 2;
++ memcpy(outbuf + *i, buffer, attrlen);
++ *i += attrlen;
++
++ return 0;
++}
++
+ krb5_error_code
+ kr_attrset_encode(const krad_attrset *set, const char *secret,
+- const unsigned char *auth,
++ const uint8_t *auth, krb5_boolean add_msgauth,
+ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen)
+ {
+- unsigned char buffer[MAX_ATTRSIZE];
+ krb5_error_code retval;
+- size_t i = 0, attrlen;
++ krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator");
++ const uint8_t zeroes[MD5_DIGEST_SIZE] = { 0 };
++ krb5_data zerodata;
++ size_t i = 0;
+ attr *a;
+
+ if (set == NULL) {
+@@ -179,19 +207,21 @@ kr_attrset_encode(const krad_attrset *set, const char *secret,
+ return 0;
+ }
+
+- K5_TAILQ_FOREACH(a, &set->list, list) {
+- retval = kr_attr_encode(set->ctx, secret, auth, a->type, &a->attr,
+- buffer, &attrlen);
+- if (retval != 0)
++ if (add_msgauth) {
++ /* Encode Message-Authenticator as the first attribute, per
++ * draft-ietf-radext-deprecating-radius-03 section 5.2. */
++ zerodata = make_data((uint8_t *)zeroes, MD5_DIGEST_SIZE);
++ retval = append_attr(set->ctx, secret, auth, msgauth_type, &zerodata,
++ outbuf, &i);
++ if (retval)
+ return retval;
++ }
+
+- if (i + attrlen + 2 > MAX_ATTRSETSIZE)
+- return EMSGSIZE;
+-
+- outbuf[i++] = a->type;
+- outbuf[i++] = attrlen + 2;
+- memcpy(&outbuf[i], buffer, attrlen);
+- i += attrlen;
++ K5_TAILQ_FOREACH(a, &set->list, list) {
++ retval = append_attr(set->ctx, secret, auth, a->type, &a->attr,
++ outbuf, &i);
++ if (retval)
++ return retval;
+ }
+
+ *outlen = i;
+diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h
+index 7619563..e2a16c7 100644
+--- a/src/lib/krad/internal.h
++++ b/src/lib/krad/internal.h
+@@ -43,6 +43,8 @@
+ #define UCHAR_MAX 255
+ #endif
+
++#define MD5_DIGEST_SIZE 16
++
+ /* RFC 2865 */
+ #define MAX_ATTRSIZE (UCHAR_MAX - 2)
+ #define MAX_ATTRSETSIZE (KRAD_PACKET_SIZE_MAX - 20)
+@@ -65,10 +67,11 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
+ krad_attr type, const krb5_data *in,
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
+
+-/* Encode the attributes into the buffer. */
++/* Encode set into outbuf. If add_msgauth is true, include a zeroed
++ * Message-Authenticator as the first attribute. */
+ krb5_error_code
+ kr_attrset_encode(const krad_attrset *set, const char *secret,
+- const unsigned char *auth,
++ const uint8_t *auth, krb5_boolean add_msgauth,
+ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen);
+
+ /* Decode attributes from a buffer. */
+diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c
+index c597174..539af5a 100644
+--- a/src/lib/krad/packet.c
++++ b/src/lib/krad/packet.c
+@@ -36,6 +36,7 @@
+ typedef unsigned char uchar;
+
+ /* RFC 2865 */
++#define MSGAUTH_SIZE (2 + MD5_DIGEST_SIZE)
+ #define OFFSET_CODE 0
+ #define OFFSET_ID 1
+ #define OFFSET_LENGTH 2
+@@ -222,6 +223,106 @@ packet_set_attrset(krb5_context ctx, const char *secret, krad_packet *pkt)
+ return kr_attrset_decode(ctx, &tmp, secret, pkt_auth(pkt), &pkt->attrset);
+ }
+
++/* Determine if a packet requires a Message-Authenticator attribute. */
++static inline krb5_boolean
++requires_msgauth(const char *secret, krad_code code)
++{
++ /* If no secret is provided, assume that the transport is a UNIX socket.
++ * Message-Authenticator is required only on UDP and TCP connections. */
++ if (*secret == '\0')
++ return FALSE;
++
++ /*
++ * Per draft-ietf-radext-deprecating-radius-03 sections 5.2.1 and 5.2.4,
++ * Message-Authenticator is required in Access-Request packets and all
++ * potential responses when UDP or TCP transport is used.
++ */
++ return code == krad_code_name2num("Access-Request") ||
++ code == krad_code_name2num("Access-Reject") ||
++ code == krad_code_name2num("Access-Accept") ||
++ code == krad_code_name2num("Access-Challenge");
++}
++
++/* Check if the packet has a Message-Authenticator attribute. */
++static inline krb5_boolean
++has_pkt_msgauth(const krad_packet *pkt)
++{
++ krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator");
++
++ return krad_attrset_get(pkt->attrset, msgauth_type, 0) != NULL;
++}
++
++/* Return the beginning of the Message-Authenticator attribute in pkt, or NULL
++ * if no such attribute is present. */
++static const uint8_t *
++lookup_msgauth_addr(const krad_packet *pkt)
++{
++ krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator");
++ size_t i;
++ uint8_t *p;
++
++ i = OFFSET_ATTR;
++ while (i + 2 < pkt->pkt.length) {
++ p = (uint8_t *)offset(&pkt->pkt, i);
++ if (msgauth_type == *p)
++ return p;
++ i += p[1];
++ }
++
++ return NULL;
++}
++
++/*
++ * Calculate the message authenticator MAC for pkt as specified in RFC 2869
++ * section 5.14, placing the result in mac_out. Use the provided authenticator
++ * auth, which may be from pkt or from a corresponding request.
++ */
++static krb5_error_code
++calculate_mac(const char *secret, const krad_packet *pkt,
++ const uint8_t auth[AUTH_FIELD_SIZE],
++ uint8_t mac_out[MD5_DIGEST_SIZE])
++{
++ uint8_t zeroed_msgauth[MSGAUTH_SIZE];
++ krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator");
++ const uint8_t *msgauth_attr, *msgauth_end, *pkt_end;
++ krb5_crypto_iov input[5];
++ krb5_data ksecr, mac;
++
++ msgauth_attr = lookup_msgauth_addr(pkt);
++ if (msgauth_attr == NULL)
++ return EINVAL;
++ msgauth_end = msgauth_attr + MSGAUTH_SIZE;
++ pkt_end = (const uint8_t *)pkt->pkt.data + pkt->pkt.length;
++
++ /* Read code, id, and length from the packet. */
++ input[0].flags = KRB5_CRYPTO_TYPE_DATA;
++ input[0].data = make_data(pkt->pkt.data, OFFSET_AUTH);
++
++ /* Read the provided authenticator. */
++ input[1].flags = KRB5_CRYPTO_TYPE_DATA;
++ input[1].data = make_data((uint8_t *)auth, AUTH_FIELD_SIZE);
++
++ /* Read any attributes before Message-Authenticator. */
++ input[2].flags = KRB5_CRYPTO_TYPE_DATA;
++ input[2].data = make_data(pkt_attr(pkt), msgauth_attr - pkt_attr(pkt));
++
++ /* Read Message-Authenticator with the data bytes all set to zero, per RFC
++ * 2869 section 5.14. */
++ zeroed_msgauth[0] = msgauth_type;
++ zeroed_msgauth[1] = MSGAUTH_SIZE;
++ memset(zeroed_msgauth + 2, 0, MD5_DIGEST_SIZE);
++ input[3].flags = KRB5_CRYPTO_TYPE_DATA;
++ input[3].data = make_data(zeroed_msgauth, MSGAUTH_SIZE);
++
++ /* Read any attributes after Message-Authenticator. */
++ input[4].flags = KRB5_CRYPTO_TYPE_DATA;
++ input[4].data = make_data((uint8_t *)msgauth_end, pkt_end - msgauth_end);
++
++ mac = make_data(mac_out, MD5_DIGEST_SIZE);
++ ksecr = string2data((char *)secret);
++ return k5_hmac_md5(&ksecr, input, 5, &mac);
++}
++
+ ssize_t
+ krad_packet_bytes_needed(const krb5_data *buffer)
+ {
+@@ -255,6 +356,7 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code,
+ krad_packet *pkt;
+ uchar id;
+ size_t attrset_len;
++ krb5_boolean msgauth_required;
+
+ pkt = packet_new();
+ if (pkt == NULL) {
+@@ -274,9 +376,13 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code,
+ if (retval != 0)
+ goto error;
+
++ /* Determine if Message-Authenticator is required. */
++ msgauth_required = (*secret != '\0' &&
++ code == krad_code_name2num("Access-Request"));
++
+ /* Encode the attributes. */
+- retval = kr_attrset_encode(set, secret, pkt_auth(pkt), pkt_attr(pkt),
+- &attrset_len);
++ retval = kr_attrset_encode(set, secret, pkt_auth(pkt), msgauth_required,
++ pkt_attr(pkt), &attrset_len);
+ if (retval != 0)
+ goto error;
+
+@@ -285,6 +391,13 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code,
+ pkt_code_set(pkt, code);
+ pkt_len_set(pkt, pkt->pkt.length);
+
++ if (msgauth_required) {
++ /* Calculate and set the Message-Authenticator MAC. */
++ retval = calculate_mac(secret, pkt, pkt_auth(pkt), pkt_attr(pkt) + 2);
++ if (retval != 0)
++ goto error;
++ }
++
+ /* Copy the attrset for future use. */
+ retval = packet_set_attrset(ctx, secret, pkt);
+ if (retval != 0)
+@@ -307,14 +420,18 @@ krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code,
+ krb5_error_code retval;
+ krad_packet *pkt;
+ size_t attrset_len;
++ krb5_boolean msgauth_required;
+
+ pkt = packet_new();
+ if (pkt == NULL)
+ return ENOMEM;
+
++ /* Determine if Message-Authenticator is required. */
++ msgauth_required = requires_msgauth(secret, code);
++
+ /* Encode the attributes. */
+- retval = kr_attrset_encode(set, secret, pkt_auth(request), pkt_attr(pkt),
+- &attrset_len);
++ retval = kr_attrset_encode(set, secret, pkt_auth(request),
++ msgauth_required, pkt_attr(pkt), &attrset_len);
+ if (retval != 0)
+ goto error;
+
+@@ -330,6 +447,18 @@ krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code,
+ if (retval != 0)
+ goto error;
+
++ if (msgauth_required) {
++ /*
++ * Calculate and replace the Message-Authenticator MAC. Per RFC 2869
++ * section 5.14, use the authenticator from the request, not from the
++ * response.
++ */
++ retval = calculate_mac(secret, pkt, pkt_auth(request),
++ pkt_attr(pkt) + 2);
++ if (retval != 0)
++ goto error;
++ }
++
+ /* Copy the attrset for future use. */
+ retval = packet_set_attrset(ctx, secret, pkt);
+ if (retval != 0)
+@@ -343,6 +472,34 @@ error:
+ return retval;
+ }
+
++/* Verify the Message-Authenticator value in pkt, using the provided
++ * authenticator (which may be from pkt or from a corresponding request). */
++static krb5_error_code
++verify_msgauth(const char *secret, const krad_packet *pkt,
++ const uint8_t auth[AUTH_FIELD_SIZE])
++{
++ uint8_t mac[MD5_DIGEST_SIZE];
++ krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator");
++ const krb5_data *msgauth;
++ krb5_error_code retval;
++
++ msgauth = krad_packet_get_attr(pkt, msgauth_type, 0);
++ if (msgauth == NULL)
++ return ENODATA;
++
++ retval = calculate_mac(secret, pkt, auth, mac);
++ if (retval)
++ return retval;
++
++ if (msgauth->length != MD5_DIGEST_SIZE)
++ return EMSGSIZE;
++
++ if (k5_bcmp(mac, msgauth->data, MD5_DIGEST_SIZE) != 0)
++ return EBADMSG;
++
++ return 0;
++}
++
+ /* Decode a packet. */
+ static krb5_error_code
+ decode_packet(krb5_context ctx, const char *secret, const krb5_data *buffer,
+@@ -394,21 +551,35 @@ krad_packet_decode_request(krb5_context ctx, const char *secret,
+ krad_packet **reqpkt)
+ {
+ const krad_packet *tmp = NULL;
++ krad_packet *req;
+ krb5_error_code retval;
+
+- retval = decode_packet(ctx, secret, buffer, reqpkt);
+- if (cb != NULL && retval == 0) {
++ retval = decode_packet(ctx, secret, buffer, &req);
++ if (retval)
++ return retval;
++
++ /* Verify Message-Authenticator if present. */
++ if (has_pkt_msgauth(req)) {
++ retval = verify_msgauth(secret, req, pkt_auth(req));
++ if (retval) {
++ krad_packet_free(req);
++ return retval;
++ }
++ }
++
++ if (cb != NULL) {
+ for (tmp = (*cb)(data, FALSE); tmp != NULL; tmp = (*cb)(data, FALSE)) {
+ if (pkt_id_get(*reqpkt) == pkt_id_get(tmp))
+ break;
+ }
+- }
+
+- if (cb != NULL && (retval != 0 || tmp != NULL))
+- (*cb)(data, TRUE);
++ if (tmp != NULL)
++ (*cb)(data, TRUE);
++ }
+
++ *reqpkt = req;
+ *duppkt = tmp;
+- return retval;
++ return 0;
+ }
+
+ krb5_error_code
+@@ -435,9 +606,17 @@ krad_packet_decode_response(krb5_context ctx, const char *secret,
+ break;
+ }
+
+- /* If the authenticator matches, then the response is valid. */
+- if (memcmp(pkt_auth(*rsppkt), auth, sizeof(auth)) == 0)
+- break;
++ /* Verify the response authenticator. */
++ if (k5_bcmp(pkt_auth(*rsppkt), auth, sizeof(auth)) != 0)
++ continue;
++
++ /* Verify Message-Authenticator if present. */
++ if (has_pkt_msgauth(*rsppkt)) {
++ if (verify_msgauth(secret, *rsppkt, pkt_auth(tmp)) != 0)
++ continue;
++ }
++
++ break;
+ }
+ }
+
+diff --git a/src/lib/krad/t_attrset.c b/src/lib/krad/t_attrset.c
+index 7928335..fd11ee5 100644
+--- a/src/lib/krad/t_attrset.c
++++ b/src/lib/krad/t_attrset.c
+@@ -62,7 +62,7 @@ main()
+ noerror(krad_attrset_add(set, krad_attr_name2num("User-Password"), &tmp));
+
+ /* Encode attrset. */
+- noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len));
++ noerror(kr_attrset_encode(set, "foo", auth, FALSE, buffer, &encode_len));
+ krad_attrset_free(set);
+
+ /* Manually encode User-Name. */
+diff --git a/src/lib/krad/t_daemon.py b/src/lib/krad/t_daemon.py
+index 4a3de07..647d489 100755
+--- a/src/lib/krad/t_daemon.py
++++ b/src/lib/krad/t_daemon.py
+@@ -40,6 +40,7 @@ DICTIONARY = """
+ ATTRIBUTE\tUser-Name\t1\tstring
+ ATTRIBUTE\tUser-Password\t2\toctets
+ ATTRIBUTE\tNAS-Identifier\t32\tstring
++ATTRIBUTE\tMessage-Authenticator\t80\toctets
+ """
+
+ class TestServer(server.Server):
+@@ -52,7 +53,7 @@ class TestServer(server.Server):
+ if key == "User-Password":
+ passwd = [pkt.PwDecrypt(x) for x in pkt[key]]
+
+- reply = self.CreateReplyPacket(pkt)
++ reply = self.CreateReplyPacket(pkt, message_authenticator=True)
+ if passwd == ['accept']:
+ reply.code = packet.AccessAccept
+ else:
+diff --git a/src/lib/krad/t_packet.c b/src/lib/krad/t_packet.c
+index c224891..104b650 100644
+--- a/src/lib/krad/t_packet.c
++++ b/src/lib/krad/t_packet.c
+@@ -172,6 +172,9 @@ main(int argc, const char **argv)
+ krb5_data username, password;
+ krb5_boolean auth = FALSE;
+ krb5_context ctx;
++ const krad_packet *dupreq;
++ const krb5_data *encpkt;
++ krad_packet *decreq;
+
+ username = string2data("testUser");
+
+@@ -184,9 +187,17 @@ main(int argc, const char **argv)
+
+ password = string2data("accept");
+ noerror(make_packet(ctx, &username, &password, &packets[ACCEPT_PACKET]));
++ encpkt = krad_packet_encode(packets[ACCEPT_PACKET]);
++ noerror(krad_packet_decode_request(ctx, "foo", encpkt, NULL, NULL,
++ &dupreq, &decreq));
++ krad_packet_free(decreq);
+
+ password = string2data("reject");
+ noerror(make_packet(ctx, &username, &password, &packets[REJECT_PACKET]));
++ encpkt = krad_packet_encode(packets[REJECT_PACKET]);
++ noerror(krad_packet_decode_request(ctx, "foo", encpkt, NULL, NULL,
++ &dupreq, &decreq));
++ krad_packet_free(decreq);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+diff --git a/src/tests/t_otp.py b/src/tests/t_otp.py
+index c3b820a..dd5cdc5 100755
+--- a/src/tests/t_otp.py
++++ b/src/tests/t_otp.py
+@@ -49,6 +49,7 @@ ATTRIBUTE User-Name 1 string
+ ATTRIBUTE User-Password 2 octets
+ ATTRIBUTE Service-Type 6 integer
+ ATTRIBUTE NAS-Identifier 32 string
++ATTRIBUTE Message-Authenticator 80 octets
+ '''
+
+ class RadiusDaemon(Process):
+@@ -97,6 +98,8 @@ class RadiusDaemon(Process):
+ reply.code = packet.AccessReject
+ replyq['reply'] = False
+
++ reply.add_message_authenticator()
++
+ outq.put(replyq)
+ if addr is None:
+ sock.send(reply.ReplyPacket())
+--
+2.50.1
+
@@ -30,6 +30,7 @@ SRC_URI = "http://web.mit.edu/kerberos/dist/${BPN}/${SHRT_VER}/${BP}.tar.gz \
file://krb5-admin-server.service \
file://CVE-2024-26458_CVE-2024-26461.patch;striplevel=2 \
file://CVE-2025-24528.patch;striplevel=2 \
+ file://CVE-2024-3596.patch;striplevel=2 \
"
SRC_URI[sha256sum] = "b7a4cd5ead67fb08b980b21abd150ff7217e85ea320c9ed0c6dadd304840ad35"
Upstream-Status: Backport from https://github.com/krb5/krb5/commit/871125fea8ce0370a972bf65f7d1de63f619b06c Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> --- .../krb5/krb5/CVE-2024-3596.patch | 628 ++++++++++++++++++ .../recipes-connectivity/krb5/krb5_1.21.3.bb | 1 + 2 files changed, 629 insertions(+) create mode 100644 meta-oe/recipes-connectivity/krb5/krb5/CVE-2024-3596.patch