From: Jouni Malinen Date: Fri, 15 Apr 2022 14:31:48 +0000 (+0300) Subject: RADIUS: Attributes with Extended Types (RFC 6929) X-Git-Tag: hostap_2_11~2064 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=24763e3cd0a564eb71f3c501bbb4fbb0d7070762;p=thirdparty%2Fhostap.git RADIUS: Attributes with Extended Types (RFC 6929) Supported extended types for RADIUS attributes for the cases defined in RFC 6929. Signed-off-by: Jouni Malinen --- diff --git a/src/radius/radius.c b/src/radius/radius.c index be16e27b9..a64228067 100644 --- a/src/radius/radius.c +++ b/src/radius/radius.c @@ -1,6 +1,6 @@ /* * RADIUS message processing - * Copyright (c) 2002-2009, 2011-2015, Jouni Malinen + * Copyright (c) 2002-2009, 2011-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -159,7 +159,8 @@ static const char *radius_code_string(u8 code) struct radius_attr_type { - u8 type; + u16 type; /* 0..255 for basic types; + * (241 << 8) | for extended types */ char *name; enum { RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP, @@ -260,11 +261,31 @@ static const struct radius_attr_type radius_attrs[] = RADIUS_ATTR_HEXDUMP }, { RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, "WLAN-Group-Mgmt-Pairwise-Cipher", RADIUS_ATTR_HEXDUMP }, + { RADIUS_ATTR_EXT_TYPE_1, "Extended-Type-1", RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_TYPE_2, "Extended-Type-2", RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_TYPE_3, "Extended-Type-3", RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_TYPE_4, "Extended-Type-4", RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_LONG_EXT_TYPE_1, "Long-Extended-Type-1", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_LONG_EXT_TYPE_2, "Long-Extended-Type-2", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_1, "Extended-Vendor-Specific-1", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_2, "Extended-Vendor-Specific-2", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_3, "Extended-Vendor-Specific-3", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_4, "Extended-Vendor-Specific-4", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5, "Extended-Vendor-Specific-5", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_6, "Extended-Vendor-Specific-6", + RADIUS_ATTR_UNDIST }, }; #define RADIUS_ATTRS ARRAY_SIZE(radius_attrs) -static const struct radius_attr_type *radius_get_attr_type(u8 type) +static const struct radius_attr_type * radius_get_attr_type(u16 type) { size_t i; @@ -277,23 +298,60 @@ static const struct radius_attr_type *radius_get_attr_type(u8 type) } +static bool radius_is_long_ext_type(u8 type) +{ + return type == RADIUS_ATTR_LONG_EXT_TYPE_1 || + type == RADIUS_ATTR_LONG_EXT_TYPE_2; +} + + +static bool radius_is_ext_type(u8 type) +{ + return type >= RADIUS_ATTR_EXT_TYPE_1 && + type <= RADIUS_ATTR_LONG_EXT_TYPE_2; +} + + static void radius_msg_dump_attr(struct radius_attr_hdr *hdr) { + struct radius_attr_hdr_ext *ext = NULL; const struct radius_attr_type *attr; int len; unsigned char *pos; char buf[1000]; - attr = radius_get_attr_type(hdr->type); + if (hdr->length < sizeof(struct radius_attr_hdr)) + return; - wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d", - hdr->type, attr ? attr->name : "?Unknown?", hdr->length); + if (radius_is_ext_type(hdr->type)) { + if (hdr->length < 4) { + wpa_printf(MSG_INFO, + " Invalid attribute %d (too short for extended type)", + hdr->type); + return; + } - if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr)) - return; + ext = (struct radius_attr_hdr_ext *) hdr; + } + + if (ext) { + attr = radius_get_attr_type((ext->type << 8) | ext->ext_type); + wpa_printf(MSG_INFO, " Attribute %d.%d (%s) length=%d", + ext->type, ext->ext_type, + attr ? attr->name : "?Unknown?", ext->length); + pos = (unsigned char *) (ext + 1); + len = ext->length - sizeof(struct radius_attr_hdr_ext); + } else { + attr = radius_get_attr_type(hdr->type); + wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d", + hdr->type, attr ? attr->name : "?Unknown?", + hdr->length); + pos = (unsigned char *) (hdr + 1); + len = hdr->length - sizeof(struct radius_attr_hdr); + } - len = hdr->length - sizeof(struct radius_attr_hdr); - pos = (unsigned char *) (hdr + 1); + if (!attr) + return; switch (attr->data_type) { case RADIUS_ATTR_TEXT: @@ -627,22 +685,54 @@ static int radius_msg_add_attr_to_array(struct radius_msg *msg, } -struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, - const u8 *data, size_t data_len) +struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u16 type, + const u8 *data, size_t data_len) { - size_t buf_needed; - struct radius_attr_hdr *attr; + size_t buf_needed, max_len; + struct radius_attr_hdr *attr = NULL; + struct radius_attr_hdr_ext *ext; + u8 ext_type = 0; if (TEST_FAIL()) return NULL; - if (data_len > RADIUS_MAX_ATTR_LEN) { - wpa_printf(MSG_ERROR, "radius_msg_add_attr: too long attribute (%lu bytes)", - (unsigned long) data_len); - return NULL; + if (type > 255) { + if (!radius_is_ext_type(type >> 8)) { + wpa_printf(MSG_ERROR, + "%s: Undefined extended type %d.%d", + __func__, type >> 8, type & 0xff); + return NULL; + } + ext_type = type & 0xff; + type >>= 8; + } else if (radius_is_ext_type(type)) { + wpa_printf(MSG_ERROR, "%s: Unexpected extended type use for %d", + __func__, type); } - buf_needed = sizeof(*attr) + data_len; + if (radius_is_long_ext_type(type)) { + size_t hdr_len = sizeof(struct radius_attr_hdr_ext) + 1; + size_t plen = 255 - hdr_len; + size_t num; + + max_len = 4096; + num = (data_len + plen - 1) / plen; + if (num == 0) + num = 1; + buf_needed = num * hdr_len + data_len; + } else if (radius_is_ext_type(type)) { + max_len = RADIUS_MAX_EXT_ATTR_LEN; + buf_needed = sizeof(struct radius_attr_hdr_ext) + data_len; + } else { + max_len = RADIUS_MAX_ATTR_LEN; + buf_needed = sizeof(*attr) + data_len; + } + if (data_len > max_len) { + wpa_printf(MSG_ERROR, + "%s: too long attribute (%zu > %zu bytes)", + __func__, data_len, max_len); + return NULL; + } if (wpabuf_tailroom(msg->buf) < buf_needed) { /* allocate more space for message buffer */ @@ -651,13 +741,44 @@ struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, msg->hdr = wpabuf_mhead(msg->buf); } - attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr)); - attr->type = type; - attr->length = sizeof(*attr) + data_len; - wpabuf_put_data(msg->buf, data, data_len); - - if (radius_msg_add_attr_to_array(msg, attr)) - return NULL; + if (radius_is_long_ext_type(type)) { + size_t plen = 255 - sizeof(struct radius_attr_hdr_ext) - 1; + size_t alen; + + do { + alen = data_len > plen ? plen : data_len; + ext = wpabuf_put(msg->buf, + sizeof(struct radius_attr_hdr_ext)); + if (!attr) + attr = (struct radius_attr_hdr *) ext; + ext->type = type; + ext->length = sizeof(*ext) + 1 + alen; + ext->ext_type = ext_type; + wpabuf_put_u8(msg->buf, data_len > alen ? 0x80 : 0); + wpabuf_put_data(msg->buf, data, data_len); + data += alen; + data_len -= alen; + if (radius_msg_add_attr_to_array( + msg, (struct radius_attr_hdr *) ext)) + return NULL; + } while (data_len > 0); + } else if (radius_is_ext_type(type)) { + ext = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr_ext)); + attr = (struct radius_attr_hdr *) ext; + ext->type = type; + ext->length = sizeof(*ext) + data_len; + ext->ext_type = ext_type; + wpabuf_put_data(msg->buf, data, data_len); + if (radius_msg_add_attr_to_array(msg, attr)) + return NULL; + } else { + attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr)); + attr->type = type; + attr->length = sizeof(*attr) + data_len; + wpabuf_put_data(msg->buf, data, data_len); + if (radius_msg_add_attr_to_array(msg, attr)) + return NULL; + } return attr; } @@ -1285,6 +1406,28 @@ int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data, } +int radius_msg_add_ext_vs(struct radius_msg *msg, u16 type, u32 vendor_id, + u8 vendor_type, const u8 *data, size_t len) +{ + struct radius_attr_hdr *attr; + u8 *buf, *pos; + size_t alen; + + alen = 4 + 1 + len; + buf = os_malloc(alen); + if (!buf) + return 0; + pos = buf; + WPA_PUT_BE32(pos, vendor_id); + pos += 4; + *pos++ = vendor_type; + os_memcpy(pos, data, len); + attr = radius_msg_add_attr(msg, type, buf, alen); + os_free(buf); + return attr != NULL; +} + + int radius_user_password_hide(struct radius_msg *msg, const u8 *data, size_t data_len, const u8 *secret, size_t secret_len, diff --git a/src/radius/radius.h b/src/radius/radius.h index fb8148180..490c8d1f6 100644 --- a/src/radius/radius.h +++ b/src/radius/radius.h @@ -1,6 +1,6 @@ /* * RADIUS message processing - * Copyright (c) 2002-2009, 2012, 2014-2015, Jouni Malinen + * Copyright (c) 2002-2009, 2012, 2014-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -46,7 +46,15 @@ struct radius_attr_hdr { /* followed by length-2 octets of attribute value */ } STRUCT_PACKED; +struct radius_attr_hdr_ext { + u8 type; + u8 length; /* including this header */ + u8 ext_type; + /* followed by length-3 octets of attribute value */ +} STRUCT_PACKED; + #define RADIUS_MAX_ATTR_LEN (255 - sizeof(struct radius_attr_hdr)) +#define RADIUS_MAX_EXT_ATTR_LEN (255 - sizeof(struct radius_attr_hdr_ext)) enum { RADIUS_ATTR_USER_NAME = 1, RADIUS_ATTR_USER_PASSWORD = 2, @@ -113,6 +121,18 @@ enum { RADIUS_ATTR_USER_NAME = 1, RADIUS_ATTR_WLAN_GROUP_CIPHER = 187, RADIUS_ATTR_WLAN_AKM_SUITE = 188, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER = 189, + RADIUS_ATTR_EXT_TYPE_1 = 241, + RADIUS_ATTR_EXT_TYPE_2 = 242, + RADIUS_ATTR_EXT_TYPE_3 = 243, + RADIUS_ATTR_EXT_TYPE_4 = 244, + RADIUS_ATTR_LONG_EXT_TYPE_1 = 245, + RADIUS_ATTR_LONG_EXT_TYPE_2 = 246, + RADIUS_ATTR_EXT_VENDOR_SPECIFIC_1 = (241 << 8) | 26, + RADIUS_ATTR_EXT_VENDOR_SPECIFIC_2 = (242 << 8) | 26, + RADIUS_ATTR_EXT_VENDOR_SPECIFIC_3 = (243 << 8) | 26, + RADIUS_ATTR_EXT_VENDOR_SPECIFIC_4 = (244 << 8) | 26, + RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5 = (245 << 8) | 26, + RADIUS_ATTR_EXT_VENDOR_SPECIFIC_6 = (246 << 8) | 26, }; @@ -257,7 +277,7 @@ int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret, int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret, size_t secret_len, int require_message_authenticator); -struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u8 type, +struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u16 type, const u8 *data, size_t data_len); struct radius_msg * radius_msg_parse(const u8 *data, size_t len); int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, @@ -284,6 +304,8 @@ int radius_msg_add_mppe_keys(struct radius_msg *msg, const u8 *recv_key, size_t recv_key_len); int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data, size_t len); +int radius_msg_add_ext_vs(struct radius_msg *msg, u16 type, u32 vendor_id, + u8 vendor_type, const u8 *data, size_t len); int radius_user_password_hide(struct radius_msg *msg, const u8 *data, size_t data_len, const u8 *secret, size_t secret_len,