From adac846bd0e258a0aa50750bbd2b411fa0085c46 Mon Sep 17 00:00:00 2001
From: Jouni Malinen <j@w1.fi>
Date: Sat, 16 Mar 2024 11:11:44 +0200
Subject: [PATCH 2/9] RADIUS: Allow Message-Authenticator attribute as the
 first attribute

If a Message-Authenticator attribute was already added to a RADIUS
message, use that attribute instead of adding a new one when finishing
message building. This allows the Message-Authenticator attribute to be
placed as the first attribute in the message.

Signed-off-by: Jouni Malinen <j@w1.fi>

CVE: CVE-2024-3596
Upstream-Status: Backport [https://w1.fi/cgit/hostap/commit/?id=adac846bd0e258a0aa50750bbd2b411fa0085c46]
Signed-off-by: Peter Marko <peter.marko@siemens.com>
---
 src/radius/radius.c | 85 ++++++++++++++++++++++++++++-----------------
 src/radius/radius.h |  1 +
 2 files changed, 54 insertions(+), 32 deletions(-)

diff --git a/src/radius/radius.c b/src/radius/radius.c
index be16e27b9..2d2e00b5c 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -364,25 +364,54 @@ void radius_msg_dump(struct radius_msg *msg)
 }
 
 
+u8 * radius_msg_add_msg_auth(struct radius_msg *msg)
+{
+	u8 auth[MD5_MAC_LEN];
+	struct radius_attr_hdr *attr;
+
+	os_memset(auth, 0, MD5_MAC_LEN);
+	attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
+				   auth, MD5_MAC_LEN);
+	if (!attr) {
+		wpa_printf(MSG_ERROR,
+			   "WARNING: Could not add Message-Authenticator");
+		return NULL;
+	}
+
+	return (u8 *) (attr + 1);
+}
+
+
+static u8 * radius_msg_auth_pos(struct radius_msg *msg)
+{
+	u8 *pos;
+	size_t alen;
+
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
+				    &pos, &alen, NULL) == 0 &&
+	    alen == MD5_MAC_LEN) {
+		/* Use already added Message-Authenticator attribute */
+		return pos;
+	}
+
+	/* Add a Message-Authenticator attribute */
+	return radius_msg_add_msg_auth(msg);
+}
+
+
 int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
 		      size_t secret_len)
 {
 	if (secret) {
-		u8 auth[MD5_MAC_LEN];
-		struct radius_attr_hdr *attr;
+		u8 *pos;
 
-		os_memset(auth, 0, MD5_MAC_LEN);
-		attr = radius_msg_add_attr(msg,
-					   RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
-					   auth, MD5_MAC_LEN);
-		if (attr == NULL) {
-			wpa_printf(MSG_WARNING, "RADIUS: Could not add "
-				   "Message-Authenticator");
+		pos = radius_msg_auth_pos(msg);
+		if (!pos)
 			return -1;
-		}
 		msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
-		hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
-			 wpabuf_len(msg->buf), (u8 *) (attr + 1));
+		if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+			     wpabuf_len(msg->buf), pos) < 0)
+			return -1;
 	} else
 		msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
 
@@ -398,23 +427,19 @@ int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
 int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
 			  size_t secret_len, const u8 *req_authenticator)
 {
-	u8 auth[MD5_MAC_LEN];
-	struct radius_attr_hdr *attr;
 	const u8 *addr[4];
 	size_t len[4];
+	u8 *pos;
 
-	os_memset(auth, 0, MD5_MAC_LEN);
-	attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
-				   auth, MD5_MAC_LEN);
-	if (attr == NULL) {
-		wpa_printf(MSG_ERROR, "WARNING: Could not add Message-Authenticator");
+	pos = radius_msg_auth_pos(msg);
+	if (!pos)
 		return -1;
-	}
 	msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
 	os_memcpy(msg->hdr->authenticator, req_authenticator,
 		  sizeof(msg->hdr->authenticator));
-	hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
-		 wpabuf_len(msg->buf), (u8 *) (attr + 1));
+	if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+		     wpabuf_len(msg->buf), pos) < 0)
+		return -1;
 
 	/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
 	addr[0] = (u8 *) msg->hdr;
@@ -442,21 +467,17 @@ int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret,
 {
 	const u8 *addr[2];
 	size_t len[2];
-	u8 auth[MD5_MAC_LEN];
-	struct radius_attr_hdr *attr;
+	u8 *pos;
 
-	os_memset(auth, 0, MD5_MAC_LEN);
-	attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
-				   auth, MD5_MAC_LEN);
-	if (attr == NULL) {
-		wpa_printf(MSG_WARNING, "Could not add Message-Authenticator");
+	pos = radius_msg_auth_pos(msg);
+	if (!pos)
 		return -1;
-	}
 
 	msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
 	os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16);
-	hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
-		 wpabuf_len(msg->buf), (u8 *) (attr + 1));
+	if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+		     wpabuf_len(msg->buf), pos) < 0)
+		return -1;
 
 	/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
 	addr[0] = wpabuf_head_u8(msg->buf);
diff --git a/src/radius/radius.h b/src/radius/radius.h
index fb8148180..6b9dfbca2 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -240,6 +240,7 @@ struct wpabuf * radius_msg_get_buf(struct radius_msg *msg);
 struct radius_msg * radius_msg_new(u8 code, u8 identifier);
 void radius_msg_free(struct radius_msg *msg);
 void radius_msg_dump(struct radius_msg *msg);
+u8 * radius_msg_add_msg_auth(struct radius_msg *msg);
 int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
 		      size_t secret_len);
 int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
-- 
2.30.2

