diff options
| author | Hitendra Prajapati <hprajapati@mvista.com> | 2025-12-23 10:29:32 +0530 |
|---|---|---|
| committer | Gyorgy Sarvari <skandigraun@gmail.com> | 2025-12-25 10:17:01 +0100 |
| commit | 4ac316bf47260fa7b6bfba546dd38e02f9440d4b (patch) | |
| tree | 36d53d246e4dce0fd2494b409ea1da1cf221060a | |
| parent | d2894888c92700c368a7665ded60810df5d8438c (diff) | |
| download | meta-openembedded-4ac316bf47260fa7b6bfba546dd38e02f9440d4b.tar.gz | |
krb5: fix for CVE-2024-3596
Upstream-Status: Backport from https://github.com/krb5/krb5/commit/871125fea8ce0370a972bf65f7d1de63f619b06c
Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
| -rw-r--r-- | meta-oe/recipes-connectivity/krb5/krb5/CVE-2024-3596.patch | 628 | ||||
| -rw-r--r-- | meta-oe/recipes-connectivity/krb5/krb5_1.17.2.bb | 1 |
2 files changed, 629 insertions, 0 deletions
diff --git a/meta-oe/recipes-connectivity/krb5/krb5/CVE-2024-3596.patch b/meta-oe/recipes-connectivity/krb5/krb5/CVE-2024-3596.patch new file mode 100644 index 0000000000..8e74b07aef --- /dev/null +++ b/meta-oe/recipes-connectivity/krb5/krb5/CVE-2024-3596.patch | |||
| @@ -0,0 +1,628 @@ | |||
| 1 | From 871125fea8ce0370a972bf65f7d1de63f619b06c Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Julien Rische <jrische@redhat.com> | ||
| 3 | Date: Thu, 22 Aug 2024 17:15:50 +0200 | ||
| 4 | Subject: [PATCH] Generate and verify message MACs in libkrad | ||
| 5 | |||
| 6 | Implement some of the measures specified in | ||
| 7 | draft-ietf-radext-deprecating-radius-03 for mitigating the BlastRADIUS | ||
| 8 | attack (CVE-2024-3596): | ||
| 9 | |||
| 10 | * Include a Message-Authenticator MAC as the first attribute when | ||
| 11 | generating a packet of type Access-Request, Access-Reject, | ||
| 12 | Access-Accept, or Access-Challenge (sections 5.2.1 and 5.2.4), if | ||
| 13 | the secret is non-empty. (An empty secret indicates the use of Unix | ||
| 14 | domain socket transport.) | ||
| 15 | |||
| 16 | * Validate the Message-Authenticator MAC in received packets, if | ||
| 17 | present. | ||
| 18 | |||
| 19 | FreeRADIUS enforces Message-Authenticator as of versions 3.2.5 and | ||
| 20 | 3.0.27. libkrad must generate Message-Authenticator attributes in | ||
| 21 | order to remain compatible with these implementations. | ||
| 22 | |||
| 23 | [ghudson@mit.edu: adjusted style and naming; simplified some | ||
| 24 | functions; edited commit message] | ||
| 25 | |||
| 26 | ticket: 9142 (new) | ||
| 27 | tags: pullup | ||
| 28 | target_version: 1.21-next | ||
| 29 | |||
| 30 | CVE: CVE-2024-3596 | ||
| 31 | Upstream-Status: Backport [https://github.com/krb5/krb5/commit/871125fea8ce0370a972bf65f7d1de63f619b06c] | ||
| 32 | Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> | ||
| 33 | --- | ||
| 34 | src/include/k5-int.h | 5 + | ||
| 35 | src/lib/crypto/krb/checksum_hmac_md5.c | 28 ++++ | ||
| 36 | src/lib/crypto/libk5crypto.exports | 1 + | ||
| 37 | src/lib/krad/attr.c | 17 ++ | ||
| 38 | src/lib/krad/attrset.c | 58 +++++-- | ||
| 39 | src/lib/krad/internal.h | 7 +- | ||
| 40 | src/lib/krad/packet.c | 205 +++++++++++++++++++++++-- | ||
| 41 | src/lib/krad/t_attrset.c | 2 +- | ||
| 42 | src/lib/krad/t_daemon.py | 3 +- | ||
| 43 | src/lib/krad/t_packet.c | 11 ++ | ||
| 44 | src/tests/t_otp.py | 3 + | ||
| 45 | 11 files changed, 309 insertions(+), 31 deletions(-) | ||
| 46 | |||
| 47 | diff --git a/src/include/k5-int.h b/src/include/k5-int.h | ||
| 48 | index 5928c82..9b3aa13 100644 | ||
| 49 | --- a/src/include/k5-int.h | ||
| 50 | +++ b/src/include/k5-int.h | ||
| 51 | @@ -2394,4 +2394,9 @@ void k5_change_error_message_code(krb5_context ctx, krb5_error_code oldcode, | ||
| 52 | #define k5_prependmsg krb5_prepend_error_message | ||
| 53 | #define k5_wrapmsg krb5_wrap_error_message | ||
| 54 | |||
| 55 | +/* Generate an HMAC-MD5 keyed checksum as specified by RFC 2104. */ | ||
| 56 | +krb5_error_code | ||
| 57 | +k5_hmac_md5(const krb5_data *key, const krb5_crypto_iov *data, size_t num_data, | ||
| 58 | + krb5_data *output); | ||
| 59 | + | ||
| 60 | #endif /* _KRB5_INT_H */ | ||
| 61 | diff --git a/src/lib/crypto/krb/checksum_hmac_md5.c b/src/lib/crypto/krb/checksum_hmac_md5.c | ||
| 62 | index ec024f3..a809388 100644 | ||
| 63 | --- a/src/lib/crypto/krb/checksum_hmac_md5.c | ||
| 64 | +++ b/src/lib/crypto/krb/checksum_hmac_md5.c | ||
| 65 | @@ -92,3 +92,31 @@ cleanup: | ||
| 66 | free(hash_iov); | ||
| 67 | return ret; | ||
| 68 | } | ||
| 69 | + | ||
| 70 | +krb5_error_code | ||
| 71 | +k5_hmac_md5(const krb5_data *key, const krb5_crypto_iov *data, size_t num_data, | ||
| 72 | + krb5_data *output) | ||
| 73 | +{ | ||
| 74 | + krb5_error_code ret; | ||
| 75 | + const struct krb5_hash_provider *hash = &krb5int_hash_md5; | ||
| 76 | + krb5_keyblock keyblock = { 0 }; | ||
| 77 | + krb5_data hashed_key; | ||
| 78 | + uint8_t hkeybuf[16]; | ||
| 79 | + krb5_crypto_iov iov; | ||
| 80 | + | ||
| 81 | + /* Hash the key if it is longer than the block size. */ | ||
| 82 | + if (key->length > hash->blocksize) { | ||
| 83 | + hashed_key = make_data(hkeybuf, sizeof(hkeybuf)); | ||
| 84 | + iov.flags = KRB5_CRYPTO_TYPE_DATA; | ||
| 85 | + iov.data = *key; | ||
| 86 | + ret = hash->hash(&iov, 1, &hashed_key); | ||
| 87 | + if (ret) | ||
| 88 | + return ret; | ||
| 89 | + key = &hashed_key; | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + keyblock.magic = KV5M_KEYBLOCK; | ||
| 93 | + keyblock.length = key->length; | ||
| 94 | + keyblock.contents = (uint8_t *)key->data; | ||
| 95 | + return krb5int_hmac_keyblock(hash, &keyblock, data, num_data, output); | ||
| 96 | +} | ||
| 97 | diff --git a/src/lib/crypto/libk5crypto.exports b/src/lib/crypto/libk5crypto.exports | ||
| 98 | index 90afdf5..02efa3b 100644 | ||
| 99 | --- a/src/lib/crypto/libk5crypto.exports | ||
| 100 | +++ b/src/lib/crypto/libk5crypto.exports | ||
| 101 | @@ -110,3 +110,4 @@ krb5_c_prfplus | ||
| 102 | krb5_c_derive_prfplus | ||
| 103 | k5_enctype_to_ssf | ||
| 104 | krb5int_c_deprecated_enctype | ||
| 105 | +k5_hmac_md5 | ||
| 106 | diff --git a/src/lib/krad/attr.c b/src/lib/krad/attr.c | ||
| 107 | index 9c13d9d..4ad3212 100644 | ||
| 108 | --- a/src/lib/krad/attr.c | ||
| 109 | +++ b/src/lib/krad/attr.c | ||
| 110 | @@ -122,6 +122,23 @@ static const attribute_record attributes[UCHAR_MAX] = { | ||
| 111 | {"NAS-Port-Type", 4, 4, NULL, NULL}, | ||
| 112 | {"Port-Limit", 4, 4, NULL, NULL}, | ||
| 113 | {"Login-LAT-Port", 1, MAX_ATTRSIZE, NULL, NULL}, | ||
| 114 | + {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */ | ||
| 115 | + {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */ | ||
| 116 | + {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */ | ||
| 117 | + {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */ | ||
| 118 | + {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */ | ||
| 119 | + {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */ | ||
| 120 | + {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */ | ||
| 121 | + {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */ | ||
| 122 | + {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */ | ||
| 123 | + {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */ | ||
| 124 | + {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */ | ||
| 125 | + {NULL, 0, 0, NULL, NULL}, /* Password-Retry */ | ||
| 126 | + {NULL, 0, 0, NULL, NULL}, /* Prompt */ | ||
| 127 | + {NULL, 0, 0, NULL, NULL}, /* Connect-Info */ | ||
| 128 | + {NULL, 0, 0, NULL, NULL}, /* Configuration-Token */ | ||
| 129 | + {NULL, 0, 0, NULL, NULL}, /* EAP-Message */ | ||
| 130 | + {"Message-Authenticator", MD5_DIGEST_SIZE, MD5_DIGEST_SIZE, NULL, NULL}, | ||
| 131 | }; | ||
| 132 | |||
| 133 | /* Encode User-Password attribute. */ | ||
| 134 | diff --git a/src/lib/krad/attrset.c b/src/lib/krad/attrset.c | ||
| 135 | index 03c6137..f279949 100644 | ||
| 136 | --- a/src/lib/krad/attrset.c | ||
| 137 | +++ b/src/lib/krad/attrset.c | ||
| 138 | @@ -164,14 +164,42 @@ krad_attrset_copy(const krad_attrset *set, krad_attrset **copy) | ||
| 139 | return 0; | ||
| 140 | } | ||
| 141 | |||
| 142 | +/* Place an encoded attributes into outbuf at position *i. Increment *i by the | ||
| 143 | + * length of the encoding. */ | ||
| 144 | +static krb5_error_code | ||
| 145 | +append_attr(krb5_context ctx, const char *secret, | ||
| 146 | + const uint8_t *auth, krad_attr type, const krb5_data *data, | ||
| 147 | + uint8_t outbuf[MAX_ATTRSETSIZE], size_t *i) | ||
| 148 | +{ | ||
| 149 | + uint8_t buffer[MAX_ATTRSIZE]; | ||
| 150 | + size_t attrlen; | ||
| 151 | + krb5_error_code retval; | ||
| 152 | + | ||
| 153 | + retval = kr_attr_encode(ctx, secret, auth, type, data, buffer, &attrlen); | ||
| 154 | + if (retval) | ||
| 155 | + return retval; | ||
| 156 | + | ||
| 157 | + if (attrlen > MAX_ATTRSETSIZE - *i - 2) | ||
| 158 | + return EMSGSIZE; | ||
| 159 | + | ||
| 160 | + outbuf[(*i)++] = type; | ||
| 161 | + outbuf[(*i)++] = attrlen + 2; | ||
| 162 | + memcpy(outbuf + *i, buffer, attrlen); | ||
| 163 | + *i += attrlen; | ||
| 164 | + | ||
| 165 | + return 0; | ||
| 166 | +} | ||
| 167 | + | ||
| 168 | krb5_error_code | ||
| 169 | kr_attrset_encode(const krad_attrset *set, const char *secret, | ||
| 170 | - const unsigned char *auth, | ||
| 171 | + const uint8_t *auth, krb5_boolean add_msgauth, | ||
| 172 | unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen) | ||
| 173 | { | ||
| 174 | - unsigned char buffer[MAX_ATTRSIZE]; | ||
| 175 | krb5_error_code retval; | ||
| 176 | - size_t i = 0, attrlen; | ||
| 177 | + krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator"); | ||
| 178 | + const uint8_t zeroes[MD5_DIGEST_SIZE] = { 0 }; | ||
| 179 | + krb5_data zerodata; | ||
| 180 | + size_t i = 0; | ||
| 181 | attr *a; | ||
| 182 | |||
| 183 | if (set == NULL) { | ||
| 184 | @@ -179,19 +207,21 @@ kr_attrset_encode(const krad_attrset *set, const char *secret, | ||
| 185 | return 0; | ||
| 186 | } | ||
| 187 | |||
| 188 | - K5_TAILQ_FOREACH(a, &set->list, list) { | ||
| 189 | - retval = kr_attr_encode(set->ctx, secret, auth, a->type, &a->attr, | ||
| 190 | - buffer, &attrlen); | ||
| 191 | - if (retval != 0) | ||
| 192 | + if (add_msgauth) { | ||
| 193 | + /* Encode Message-Authenticator as the first attribute, per | ||
| 194 | + * draft-ietf-radext-deprecating-radius-03 section 5.2. */ | ||
| 195 | + zerodata = make_data((uint8_t *)zeroes, MD5_DIGEST_SIZE); | ||
| 196 | + retval = append_attr(set->ctx, secret, auth, msgauth_type, &zerodata, | ||
| 197 | + outbuf, &i); | ||
| 198 | + if (retval) | ||
| 199 | return retval; | ||
| 200 | + } | ||
| 201 | |||
| 202 | - if (i + attrlen + 2 > MAX_ATTRSETSIZE) | ||
| 203 | - return EMSGSIZE; | ||
| 204 | - | ||
| 205 | - outbuf[i++] = a->type; | ||
| 206 | - outbuf[i++] = attrlen + 2; | ||
| 207 | - memcpy(&outbuf[i], buffer, attrlen); | ||
| 208 | - i += attrlen; | ||
| 209 | + K5_TAILQ_FOREACH(a, &set->list, list) { | ||
| 210 | + retval = append_attr(set->ctx, secret, auth, a->type, &a->attr, | ||
| 211 | + outbuf, &i); | ||
| 212 | + if (retval) | ||
| 213 | + return retval; | ||
| 214 | } | ||
| 215 | |||
| 216 | *outlen = i; | ||
| 217 | diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h | ||
| 218 | index 996a893..8194b00 100644 | ||
| 219 | --- a/src/lib/krad/internal.h | ||
| 220 | +++ b/src/lib/krad/internal.h | ||
| 221 | @@ -43,6 +43,8 @@ | ||
| 222 | #define UCHAR_MAX 255 | ||
| 223 | #endif | ||
| 224 | |||
| 225 | +#define MD5_DIGEST_SIZE 16 | ||
| 226 | + | ||
| 227 | /* RFC 2865 */ | ||
| 228 | #define MAX_ATTRSIZE (UCHAR_MAX - 2) | ||
| 229 | #define MAX_ATTRSETSIZE (KRAD_PACKET_SIZE_MAX - 20) | ||
| 230 | @@ -65,10 +67,11 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth, | ||
| 231 | krad_attr type, const krb5_data *in, | ||
| 232 | unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen); | ||
| 233 | |||
| 234 | -/* Encode the attributes into the buffer. */ | ||
| 235 | +/* Encode set into outbuf. If add_msgauth is true, include a zeroed | ||
| 236 | + * Message-Authenticator as the first attribute. */ | ||
| 237 | krb5_error_code | ||
| 238 | kr_attrset_encode(const krad_attrset *set, const char *secret, | ||
| 239 | - const unsigned char *auth, | ||
| 240 | + const uint8_t *auth, krb5_boolean add_msgauth, | ||
| 241 | unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen); | ||
| 242 | |||
| 243 | /* Decode attributes from a buffer. */ | ||
| 244 | diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c | ||
| 245 | index c597174..539af5a 100644 | ||
| 246 | --- a/src/lib/krad/packet.c | ||
| 247 | +++ b/src/lib/krad/packet.c | ||
| 248 | @@ -36,6 +36,7 @@ | ||
| 249 | typedef unsigned char uchar; | ||
| 250 | |||
| 251 | /* RFC 2865 */ | ||
| 252 | +#define MSGAUTH_SIZE (2 + MD5_DIGEST_SIZE) | ||
| 253 | #define OFFSET_CODE 0 | ||
| 254 | #define OFFSET_ID 1 | ||
| 255 | #define OFFSET_LENGTH 2 | ||
| 256 | @@ -222,6 +223,106 @@ packet_set_attrset(krb5_context ctx, const char *secret, krad_packet *pkt) | ||
| 257 | return kr_attrset_decode(ctx, &tmp, secret, pkt_auth(pkt), &pkt->attrset); | ||
| 258 | } | ||
| 259 | |||
| 260 | +/* Determine if a packet requires a Message-Authenticator attribute. */ | ||
| 261 | +static inline krb5_boolean | ||
| 262 | +requires_msgauth(const char *secret, krad_code code) | ||
| 263 | +{ | ||
| 264 | + /* If no secret is provided, assume that the transport is a UNIX socket. | ||
| 265 | + * Message-Authenticator is required only on UDP and TCP connections. */ | ||
| 266 | + if (*secret == '\0') | ||
| 267 | + return FALSE; | ||
| 268 | + | ||
| 269 | + /* | ||
| 270 | + * Per draft-ietf-radext-deprecating-radius-03 sections 5.2.1 and 5.2.4, | ||
| 271 | + * Message-Authenticator is required in Access-Request packets and all | ||
| 272 | + * potential responses when UDP or TCP transport is used. | ||
| 273 | + */ | ||
| 274 | + return code == krad_code_name2num("Access-Request") || | ||
| 275 | + code == krad_code_name2num("Access-Reject") || | ||
| 276 | + code == krad_code_name2num("Access-Accept") || | ||
| 277 | + code == krad_code_name2num("Access-Challenge"); | ||
| 278 | +} | ||
| 279 | + | ||
| 280 | +/* Check if the packet has a Message-Authenticator attribute. */ | ||
| 281 | +static inline krb5_boolean | ||
| 282 | +has_pkt_msgauth(const krad_packet *pkt) | ||
| 283 | +{ | ||
| 284 | + krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator"); | ||
| 285 | + | ||
| 286 | + return krad_attrset_get(pkt->attrset, msgauth_type, 0) != NULL; | ||
| 287 | +} | ||
| 288 | + | ||
| 289 | +/* Return the beginning of the Message-Authenticator attribute in pkt, or NULL | ||
| 290 | + * if no such attribute is present. */ | ||
| 291 | +static const uint8_t * | ||
| 292 | +lookup_msgauth_addr(const krad_packet *pkt) | ||
| 293 | +{ | ||
| 294 | + krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator"); | ||
| 295 | + size_t i; | ||
| 296 | + uint8_t *p; | ||
| 297 | + | ||
| 298 | + i = OFFSET_ATTR; | ||
| 299 | + while (i + 2 < pkt->pkt.length) { | ||
| 300 | + p = (uint8_t *)offset(&pkt->pkt, i); | ||
| 301 | + if (msgauth_type == *p) | ||
| 302 | + return p; | ||
| 303 | + i += p[1]; | ||
| 304 | + } | ||
| 305 | + | ||
| 306 | + return NULL; | ||
| 307 | +} | ||
| 308 | + | ||
| 309 | +/* | ||
| 310 | + * Calculate the message authenticator MAC for pkt as specified in RFC 2869 | ||
| 311 | + * section 5.14, placing the result in mac_out. Use the provided authenticator | ||
| 312 | + * auth, which may be from pkt or from a corresponding request. | ||
| 313 | + */ | ||
| 314 | +static krb5_error_code | ||
| 315 | +calculate_mac(const char *secret, const krad_packet *pkt, | ||
| 316 | + const uint8_t auth[AUTH_FIELD_SIZE], | ||
| 317 | + uint8_t mac_out[MD5_DIGEST_SIZE]) | ||
| 318 | +{ | ||
| 319 | + uint8_t zeroed_msgauth[MSGAUTH_SIZE]; | ||
| 320 | + krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator"); | ||
| 321 | + const uint8_t *msgauth_attr, *msgauth_end, *pkt_end; | ||
| 322 | + krb5_crypto_iov input[5]; | ||
| 323 | + krb5_data ksecr, mac; | ||
| 324 | + | ||
| 325 | + msgauth_attr = lookup_msgauth_addr(pkt); | ||
| 326 | + if (msgauth_attr == NULL) | ||
| 327 | + return EINVAL; | ||
| 328 | + msgauth_end = msgauth_attr + MSGAUTH_SIZE; | ||
| 329 | + pkt_end = (const uint8_t *)pkt->pkt.data + pkt->pkt.length; | ||
| 330 | + | ||
| 331 | + /* Read code, id, and length from the packet. */ | ||
| 332 | + input[0].flags = KRB5_CRYPTO_TYPE_DATA; | ||
| 333 | + input[0].data = make_data(pkt->pkt.data, OFFSET_AUTH); | ||
| 334 | + | ||
| 335 | + /* Read the provided authenticator. */ | ||
| 336 | + input[1].flags = KRB5_CRYPTO_TYPE_DATA; | ||
| 337 | + input[1].data = make_data((uint8_t *)auth, AUTH_FIELD_SIZE); | ||
| 338 | + | ||
| 339 | + /* Read any attributes before Message-Authenticator. */ | ||
| 340 | + input[2].flags = KRB5_CRYPTO_TYPE_DATA; | ||
| 341 | + input[2].data = make_data(pkt_attr(pkt), msgauth_attr - pkt_attr(pkt)); | ||
| 342 | + | ||
| 343 | + /* Read Message-Authenticator with the data bytes all set to zero, per RFC | ||
| 344 | + * 2869 section 5.14. */ | ||
| 345 | + zeroed_msgauth[0] = msgauth_type; | ||
| 346 | + zeroed_msgauth[1] = MSGAUTH_SIZE; | ||
| 347 | + memset(zeroed_msgauth + 2, 0, MD5_DIGEST_SIZE); | ||
| 348 | + input[3].flags = KRB5_CRYPTO_TYPE_DATA; | ||
| 349 | + input[3].data = make_data(zeroed_msgauth, MSGAUTH_SIZE); | ||
| 350 | + | ||
| 351 | + /* Read any attributes after Message-Authenticator. */ | ||
| 352 | + input[4].flags = KRB5_CRYPTO_TYPE_DATA; | ||
| 353 | + input[4].data = make_data((uint8_t *)msgauth_end, pkt_end - msgauth_end); | ||
| 354 | + | ||
| 355 | + mac = make_data(mac_out, MD5_DIGEST_SIZE); | ||
| 356 | + ksecr = string2data((char *)secret); | ||
| 357 | + return k5_hmac_md5(&ksecr, input, 5, &mac); | ||
| 358 | +} | ||
| 359 | + | ||
| 360 | ssize_t | ||
| 361 | krad_packet_bytes_needed(const krb5_data *buffer) | ||
| 362 | { | ||
| 363 | @@ -255,6 +356,7 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code, | ||
| 364 | krad_packet *pkt; | ||
| 365 | uchar id; | ||
| 366 | size_t attrset_len; | ||
| 367 | + krb5_boolean msgauth_required; | ||
| 368 | |||
| 369 | pkt = packet_new(); | ||
| 370 | if (pkt == NULL) { | ||
| 371 | @@ -274,9 +376,13 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code, | ||
| 372 | if (retval != 0) | ||
| 373 | goto error; | ||
| 374 | |||
| 375 | + /* Determine if Message-Authenticator is required. */ | ||
| 376 | + msgauth_required = (*secret != '\0' && | ||
| 377 | + code == krad_code_name2num("Access-Request")); | ||
| 378 | + | ||
| 379 | /* Encode the attributes. */ | ||
| 380 | - retval = kr_attrset_encode(set, secret, pkt_auth(pkt), pkt_attr(pkt), | ||
| 381 | - &attrset_len); | ||
| 382 | + retval = kr_attrset_encode(set, secret, pkt_auth(pkt), msgauth_required, | ||
| 383 | + pkt_attr(pkt), &attrset_len); | ||
| 384 | if (retval != 0) | ||
| 385 | goto error; | ||
| 386 | |||
| 387 | @@ -285,6 +391,13 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code, | ||
| 388 | pkt_code_set(pkt, code); | ||
| 389 | pkt_len_set(pkt, pkt->pkt.length); | ||
| 390 | |||
| 391 | + if (msgauth_required) { | ||
| 392 | + /* Calculate and set the Message-Authenticator MAC. */ | ||
| 393 | + retval = calculate_mac(secret, pkt, pkt_auth(pkt), pkt_attr(pkt) + 2); | ||
| 394 | + if (retval != 0) | ||
| 395 | + goto error; | ||
| 396 | + } | ||
| 397 | + | ||
| 398 | /* Copy the attrset for future use. */ | ||
| 399 | retval = packet_set_attrset(ctx, secret, pkt); | ||
| 400 | if (retval != 0) | ||
| 401 | @@ -307,14 +420,18 @@ krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code, | ||
| 402 | krb5_error_code retval; | ||
| 403 | krad_packet *pkt; | ||
| 404 | size_t attrset_len; | ||
| 405 | + krb5_boolean msgauth_required; | ||
| 406 | |||
| 407 | pkt = packet_new(); | ||
| 408 | if (pkt == NULL) | ||
| 409 | return ENOMEM; | ||
| 410 | |||
| 411 | + /* Determine if Message-Authenticator is required. */ | ||
| 412 | + msgauth_required = requires_msgauth(secret, code); | ||
| 413 | + | ||
| 414 | /* Encode the attributes. */ | ||
| 415 | - retval = kr_attrset_encode(set, secret, pkt_auth(request), pkt_attr(pkt), | ||
| 416 | - &attrset_len); | ||
| 417 | + retval = kr_attrset_encode(set, secret, pkt_auth(request), | ||
| 418 | + msgauth_required, pkt_attr(pkt), &attrset_len); | ||
| 419 | if (retval != 0) | ||
| 420 | goto error; | ||
| 421 | |||
| 422 | @@ -330,6 +447,18 @@ krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code, | ||
| 423 | if (retval != 0) | ||
| 424 | goto error; | ||
| 425 | |||
| 426 | + if (msgauth_required) { | ||
| 427 | + /* | ||
| 428 | + * Calculate and replace the Message-Authenticator MAC. Per RFC 2869 | ||
| 429 | + * section 5.14, use the authenticator from the request, not from the | ||
| 430 | + * response. | ||
| 431 | + */ | ||
| 432 | + retval = calculate_mac(secret, pkt, pkt_auth(request), | ||
| 433 | + pkt_attr(pkt) + 2); | ||
| 434 | + if (retval != 0) | ||
| 435 | + goto error; | ||
| 436 | + } | ||
| 437 | + | ||
| 438 | /* Copy the attrset for future use. */ | ||
| 439 | retval = packet_set_attrset(ctx, secret, pkt); | ||
| 440 | if (retval != 0) | ||
| 441 | @@ -343,6 +472,34 @@ error: | ||
| 442 | return retval; | ||
| 443 | } | ||
| 444 | |||
| 445 | +/* Verify the Message-Authenticator value in pkt, using the provided | ||
| 446 | + * authenticator (which may be from pkt or from a corresponding request). */ | ||
| 447 | +static krb5_error_code | ||
| 448 | +verify_msgauth(const char *secret, const krad_packet *pkt, | ||
| 449 | + const uint8_t auth[AUTH_FIELD_SIZE]) | ||
| 450 | +{ | ||
| 451 | + uint8_t mac[MD5_DIGEST_SIZE]; | ||
| 452 | + krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator"); | ||
| 453 | + const krb5_data *msgauth; | ||
| 454 | + krb5_error_code retval; | ||
| 455 | + | ||
| 456 | + msgauth = krad_packet_get_attr(pkt, msgauth_type, 0); | ||
| 457 | + if (msgauth == NULL) | ||
| 458 | + return ENODATA; | ||
| 459 | + | ||
| 460 | + retval = calculate_mac(secret, pkt, auth, mac); | ||
| 461 | + if (retval) | ||
| 462 | + return retval; | ||
| 463 | + | ||
| 464 | + if (msgauth->length != MD5_DIGEST_SIZE) | ||
| 465 | + return EMSGSIZE; | ||
| 466 | + | ||
| 467 | + if (k5_bcmp(mac, msgauth->data, MD5_DIGEST_SIZE) != 0) | ||
| 468 | + return EBADMSG; | ||
| 469 | + | ||
| 470 | + return 0; | ||
| 471 | +} | ||
| 472 | + | ||
| 473 | /* Decode a packet. */ | ||
| 474 | static krb5_error_code | ||
| 475 | decode_packet(krb5_context ctx, const char *secret, const krb5_data *buffer, | ||
| 476 | @@ -394,21 +551,35 @@ krad_packet_decode_request(krb5_context ctx, const char *secret, | ||
| 477 | krad_packet **reqpkt) | ||
| 478 | { | ||
| 479 | const krad_packet *tmp = NULL; | ||
| 480 | + krad_packet *req; | ||
| 481 | krb5_error_code retval; | ||
| 482 | |||
| 483 | - retval = decode_packet(ctx, secret, buffer, reqpkt); | ||
| 484 | - if (cb != NULL && retval == 0) { | ||
| 485 | + retval = decode_packet(ctx, secret, buffer, &req); | ||
| 486 | + if (retval) | ||
| 487 | + return retval; | ||
| 488 | + | ||
| 489 | + /* Verify Message-Authenticator if present. */ | ||
| 490 | + if (has_pkt_msgauth(req)) { | ||
| 491 | + retval = verify_msgauth(secret, req, pkt_auth(req)); | ||
| 492 | + if (retval) { | ||
| 493 | + krad_packet_free(req); | ||
| 494 | + return retval; | ||
| 495 | + } | ||
| 496 | + } | ||
| 497 | + | ||
| 498 | + if (cb != NULL) { | ||
| 499 | for (tmp = (*cb)(data, FALSE); tmp != NULL; tmp = (*cb)(data, FALSE)) { | ||
| 500 | if (pkt_id_get(*reqpkt) == pkt_id_get(tmp)) | ||
| 501 | break; | ||
| 502 | } | ||
| 503 | - } | ||
| 504 | |||
| 505 | - if (cb != NULL && (retval != 0 || tmp != NULL)) | ||
| 506 | - (*cb)(data, TRUE); | ||
| 507 | + if (tmp != NULL) | ||
| 508 | + (*cb)(data, TRUE); | ||
| 509 | + } | ||
| 510 | |||
| 511 | + *reqpkt = req; | ||
| 512 | *duppkt = tmp; | ||
| 513 | - return retval; | ||
| 514 | + return 0; | ||
| 515 | } | ||
| 516 | |||
| 517 | krb5_error_code | ||
| 518 | @@ -435,9 +606,17 @@ krad_packet_decode_response(krb5_context ctx, const char *secret, | ||
| 519 | break; | ||
| 520 | } | ||
| 521 | |||
| 522 | - /* If the authenticator matches, then the response is valid. */ | ||
| 523 | - if (memcmp(pkt_auth(*rsppkt), auth, sizeof(auth)) == 0) | ||
| 524 | - break; | ||
| 525 | + /* Verify the response authenticator. */ | ||
| 526 | + if (k5_bcmp(pkt_auth(*rsppkt), auth, sizeof(auth)) != 0) | ||
| 527 | + continue; | ||
| 528 | + | ||
| 529 | + /* Verify Message-Authenticator if present. */ | ||
| 530 | + if (has_pkt_msgauth(*rsppkt)) { | ||
| 531 | + if (verify_msgauth(secret, *rsppkt, pkt_auth(tmp)) != 0) | ||
| 532 | + continue; | ||
| 533 | + } | ||
| 534 | + | ||
| 535 | + break; | ||
| 536 | } | ||
| 537 | } | ||
| 538 | |||
| 539 | diff --git a/src/lib/krad/t_attrset.c b/src/lib/krad/t_attrset.c | ||
| 540 | index 7928335..fd11ee5 100644 | ||
| 541 | --- a/src/lib/krad/t_attrset.c | ||
| 542 | +++ b/src/lib/krad/t_attrset.c | ||
| 543 | @@ -62,7 +62,7 @@ main() | ||
| 544 | noerror(krad_attrset_add(set, krad_attr_name2num("User-Password"), &tmp)); | ||
| 545 | |||
| 546 | /* Encode attrset. */ | ||
| 547 | - noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len)); | ||
| 548 | + noerror(kr_attrset_encode(set, "foo", auth, FALSE, buffer, &encode_len)); | ||
| 549 | krad_attrset_free(set); | ||
| 550 | |||
| 551 | /* Manually encode User-Name. */ | ||
| 552 | diff --git a/src/lib/krad/t_daemon.py b/src/lib/krad/t_daemon.py | ||
| 553 | index 7668cd7..7fa0449 100755 | ||
| 554 | --- a/src/lib/krad/t_daemon.py | ||
| 555 | +++ b/src/lib/krad/t_daemon.py | ||
| 556 | @@ -40,6 +40,7 @@ DICTIONARY = """ | ||
| 557 | ATTRIBUTE\tUser-Name\t1\tstring | ||
| 558 | ATTRIBUTE\tUser-Password\t2\toctets | ||
| 559 | ATTRIBUTE\tNAS-Identifier\t32\tstring | ||
| 560 | +ATTRIBUTE\tMessage-Authenticator\t80\toctets | ||
| 561 | """ | ||
| 562 | |||
| 563 | class TestServer(server.Server): | ||
| 564 | @@ -52,7 +53,7 @@ class TestServer(server.Server): | ||
| 565 | if key == "User-Password": | ||
| 566 | passwd = map(pkt.PwDecrypt, pkt[key]) | ||
| 567 | |||
| 568 | - reply = self.CreateReplyPacket(pkt) | ||
| 569 | + reply = self.CreateReplyPacket(pkt, message_authenticator=True) | ||
| 570 | if passwd == ['accept']: | ||
| 571 | reply.code = packet.AccessAccept | ||
| 572 | else: | ||
| 573 | diff --git a/src/lib/krad/t_packet.c b/src/lib/krad/t_packet.c | ||
| 574 | index 0a92e9c..745fb21 100644 | ||
| 575 | --- a/src/lib/krad/t_packet.c | ||
| 576 | +++ b/src/lib/krad/t_packet.c | ||
| 577 | @@ -159,6 +159,9 @@ main(int argc, const char **argv) | ||
| 578 | krb5_data username, password; | ||
| 579 | krb5_boolean auth = FALSE; | ||
| 580 | krb5_context ctx; | ||
| 581 | + const krad_packet *dupreq; | ||
| 582 | + const krb5_data *encpkt; | ||
| 583 | + krad_packet *decreq; | ||
| 584 | |||
| 585 | username = string2data("testUser"); | ||
| 586 | |||
| 587 | @@ -171,9 +174,17 @@ main(int argc, const char **argv) | ||
| 588 | |||
| 589 | password = string2data("accept"); | ||
| 590 | noerror(make_packet(ctx, &username, &password, &packets[ACCEPT_PACKET])); | ||
| 591 | + encpkt = krad_packet_encode(packets[ACCEPT_PACKET]); | ||
| 592 | + noerror(krad_packet_decode_request(ctx, "foo", encpkt, NULL, NULL, | ||
| 593 | + &dupreq, &decreq)); | ||
| 594 | + krad_packet_free(decreq); | ||
| 595 | |||
| 596 | password = string2data("reject"); | ||
| 597 | noerror(make_packet(ctx, &username, &password, &packets[REJECT_PACKET])); | ||
| 598 | + encpkt = krad_packet_encode(packets[REJECT_PACKET]); | ||
| 599 | + noerror(krad_packet_decode_request(ctx, "foo", encpkt, NULL, NULL, | ||
| 600 | + &dupreq, &decreq)); | ||
| 601 | + krad_packet_free(decreq); | ||
| 602 | |||
| 603 | memset(&hints, 0, sizeof(hints)); | ||
| 604 | hints.ai_family = AF_INET; | ||
| 605 | diff --git a/src/tests/t_otp.py b/src/tests/t_otp.py | ||
| 606 | index cba871a..1ec9165 100755 | ||
| 607 | --- a/src/tests/t_otp.py | ||
| 608 | +++ b/src/tests/t_otp.py | ||
| 609 | @@ -49,6 +49,7 @@ ATTRIBUTE User-Name 1 string | ||
| 610 | ATTRIBUTE User-Password 2 octets | ||
| 611 | ATTRIBUTE Service-Type 6 integer | ||
| 612 | ATTRIBUTE NAS-Identifier 32 string | ||
| 613 | +ATTRIBUTE Message-Authenticator 80 octets | ||
| 614 | ''' | ||
| 615 | |||
| 616 | class RadiusDaemon(Process): | ||
| 617 | @@ -97,6 +98,8 @@ class RadiusDaemon(Process): | ||
| 618 | reply.code = packet.AccessReject | ||
| 619 | replyq['reply'] = False | ||
| 620 | |||
| 621 | + reply.add_message_authenticator() | ||
| 622 | + | ||
| 623 | outq.put(replyq) | ||
| 624 | if addr is None: | ||
| 625 | sock.send(reply.ReplyPacket()) | ||
| 626 | -- | ||
| 627 | 2.50.1 | ||
| 628 | |||
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 d889855649..ed17b57b19 100644 --- a/meta-oe/recipes-connectivity/krb5/krb5_1.17.2.bb +++ b/meta-oe/recipes-connectivity/krb5/krb5_1.17.2.bb | |||
| @@ -41,6 +41,7 @@ SRC_URI = "http://web.mit.edu/kerberos/dist/${BPN}/${SHRT_VER}/${BP}.tar.gz \ | |||
| 41 | file://CVE-2025-3576-01.patch;striplevel=2 \ | 41 | file://CVE-2025-3576-01.patch;striplevel=2 \ |
| 42 | file://CVE-2025-3576-02.patch;striplevel=2 \ | 42 | file://CVE-2025-3576-02.patch;striplevel=2 \ |
| 43 | file://CVE-2025-24528.patch;striplevel=2 \ | 43 | file://CVE-2025-24528.patch;striplevel=2 \ |
| 44 | file://CVE-2024-3596.patch;striplevel=2 \ | ||
| 44 | " | 45 | " |
| 45 | SRC_URI[md5sum] = "aa4337fffa3b61f22dbd0167f708818f" | 46 | SRC_URI[md5sum] = "aa4337fffa3b61f22dbd0167f708818f" |
| 46 | SRC_URI[sha256sum] = "1a4bba94df92f6d39a197a10687653e8bfbc9a2076e129f6eb92766974f86134" | 47 | SRC_URI[sha256sum] = "1a4bba94df92f6d39a197a10687653e8bfbc9a2076e129f6eb92766974f86134" |
