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 <j@w1.fi>
This commit is contained in:
parent
6c9e76e58a
commit
24763e3cd0
2 changed files with 193 additions and 28 deletions
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* RADIUS message processing
|
||||
* Copyright (c) 2002-2009, 2011-2015, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2002-2009, 2011-2022, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* 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) | <ext-type> 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);
|
||||
|
||||
wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d",
|
||||
hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
|
||||
|
||||
if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr))
|
||||
if (hdr->length < sizeof(struct radius_attr_hdr))
|
||||
return;
|
||||
|
||||
len = hdr->length - sizeof(struct radius_attr_hdr);
|
||||
pos = (unsigned char *) (hdr + 1);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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_is_long_ext_type(type)) {
|
||||
size_t plen = 255 - sizeof(struct radius_attr_hdr_ext) - 1;
|
||||
size_t alen;
|
||||
|
||||
if (radius_msg_add_attr_to_array(msg, attr))
|
||||
return NULL;
|
||||
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,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* RADIUS message processing
|
||||
* Copyright (c) 2002-2009, 2012, 2014-2015, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2002-2009, 2012, 2014-2022, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* 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,
|
||||
|
|
Loading…
Reference in a new issue