18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * RADIUS message processing 3d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt * Copyright (c) 2002-2009, 2011-2015, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/includes.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/common.h" 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/wpabuf.h" 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/md5.h" 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/crypto.h" 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "radius.h" 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * struct radius_msg - RADIUS message structure for new and parsed messages 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_msg { 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /** 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * buf - Allocated buffer for RADIUS message 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *buf; 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /** 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hdr - Pointer to the RADIUS header in buf 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_hdr *hdr; 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /** 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * attr_pos - Array of indexes to attributes 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The values are number of bytes from buf to the beginning of 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * struct radius_attr_hdr. 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t *attr_pos; 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /** 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * attr_size - Total size of the attribute pointer array 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t attr_size; 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /** 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * attr_used - Total number of attributes in the array 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t attr_used; 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg) 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return msg->hdr; 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * radius_msg_get_buf(struct radius_msg *msg) 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return msg->buf; 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct radius_attr_hdr * 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtradius_get_attr_hdr(struct radius_msg *msg, int idx) 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return (struct radius_attr_hdr *) 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (wpabuf_mhead_u8(msg->buf) + msg->attr_pos[idx]); 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier) 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr->code = code; 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr->identifier = identifier; 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int radius_msg_initialize(struct radius_msg *msg) 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg->attr_pos = os_calloc(RADIUS_DEFAULT_ATTR_COUNT, 8261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt sizeof(*msg->attr_pos)); 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg->attr_pos == NULL) 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT; 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->attr_used = 0; 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * radius_msg_new - Create a new RADIUS message 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @code: Code for RADIUS header 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @identifier: Identifier for RADIUS header 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Context for RADIUS message or %NULL on failure 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The caller is responsible for freeing the returned data with 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * radius_msg_free(). 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_msg * radius_msg_new(u8 code, u8 identifier) 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_msg *msg; 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg = os_zalloc(sizeof(*msg)); 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->buf = wpabuf_alloc(RADIUS_DEFAULT_MSG_SIZE); 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg->buf == NULL || radius_msg_initialize(msg)) { 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_free(msg); 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr = wpabuf_put(msg->buf, sizeof(struct radius_hdr)); 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_set_hdr(msg, code, identifier); 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return msg; 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * radius_msg_free - Free a RADIUS message 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @msg: RADIUS message from radius_msg_new() or radius_msg_parse() 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid radius_msg_free(struct radius_msg *msg) 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(msg->buf); 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(msg->attr_pos); 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(msg); 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char *radius_code_string(u8 code) 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (code) { 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request"; 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept"; 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject"; 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request"; 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response"; 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge"; 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_CODE_STATUS_SERVER: return "Status-Server"; 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_CODE_STATUS_CLIENT: return "Status-Client"; 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_CODE_RESERVED: return "Reserved"; 15004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_CODE_DISCONNECT_REQUEST: return "Disconnect-Request"; 15104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_CODE_DISCONNECT_ACK: return "Disconnect-ACK"; 15204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_CODE_DISCONNECT_NAK: return "Disconnect-NAK"; 15304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_CODE_COA_REQUEST: return "CoA-Request"; 15404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_CODE_COA_ACK: return "CoA-ACK"; 15504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_CODE_COA_NAK: return "CoA-NAK"; 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: return "?Unknown?"; 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_attr_type { 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 type; 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *name; 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt enum { 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP, 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } data_type; 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1701d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidtstatic const struct radius_attr_type radius_attrs[] = 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT }, 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST }, 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP }, 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 }, 17657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt { RADIUS_ATTR_SERVICE_TYPE, "Service-Type", RADIUS_ATTR_INT32 }, 177d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt { RADIUS_ATTR_FRAMED_IP_ADDRESS, "Framed-IP-Address", RADIUS_ATTR_IP }, 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 }, 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT }, 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST }, 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST }, 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST }, 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 }, 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 }, 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action", 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id", 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_TEXT }, 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id", 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_TEXT }, 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT }, 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST }, 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type", 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 }, 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets", 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets", 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT }, 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 }, 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time", 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets", 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets", 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause", 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id", 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_TEXT }, 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 }, 213293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords", 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords", 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp", 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 21957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt { RADIUS_ATTR_EGRESS_VLANID, "EGRESS-VLANID", RADIUS_ATTR_HEXDUMP }, 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 }, 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP }, 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type", 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_HEXDUMP }, 2241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt { RADIUS_ATTR_TUNNEL_PASSWORD, "Tunnel-Password", 2251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt RADIUS_ATTR_UNDIST }, 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT }, 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST }, 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator", 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_UNDIST }, 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id", 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_HEXDUMP }, 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval", 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 23404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity", 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_TEXT }, 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 }, 2375a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt { RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 }, 2385a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt { RADIUS_ATTR_EAP_KEY_NAME, "EAP-Key-Name", RADIUS_ATTR_HEXDUMP }, 2396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { RADIUS_ATTR_OPERATOR_NAME, "Operator-Name", RADIUS_ATTR_TEXT }, 2406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { RADIUS_ATTR_LOCATION_INFO, "Location-Information", 2416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt RADIUS_ATTR_HEXDUMP }, 2426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { RADIUS_ATTR_LOCATION_DATA, "Location-Data", RADIUS_ATTR_HEXDUMP }, 2436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { RADIUS_ATTR_BASIC_LOCATION_POLICY_RULES, 2446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "Basic-Location-Policy-Rules", RADIUS_ATTR_HEXDUMP }, 2456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { RADIUS_ATTR_EXTENDED_LOCATION_POLICY_RULES, 2466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "Extended-Location-Policy-Rules", RADIUS_ATTR_HEXDUMP }, 2476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { RADIUS_ATTR_LOCATION_CAPABLE, "Location-Capable", RADIUS_ATTR_INT32 }, 2486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { RADIUS_ATTR_REQUESTED_LOCATION_INFO, "Requested-Location-Info", 2496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt RADIUS_ATTR_INT32 }, 25003658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt { RADIUS_ATTR_MOBILITY_DOMAIN_ID, "Mobility-Domain-Id", 25103658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt RADIUS_ATTR_INT32 }, 25203658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt { RADIUS_ATTR_WLAN_HESSID, "WLAN-HESSID", RADIUS_ATTR_TEXT }, 25303658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt { RADIUS_ATTR_WLAN_PAIRWISE_CIPHER, "WLAN-Pairwise-Cipher", 25403658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt RADIUS_ATTR_HEXDUMP }, 25503658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt { RADIUS_ATTR_WLAN_GROUP_CIPHER, "WLAN-Group-Cipher", 25603658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt RADIUS_ATTR_HEXDUMP }, 25703658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt { RADIUS_ATTR_WLAN_AKM_SUITE, "WLAN-AKM-Suite", 25803658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt RADIUS_ATTR_HEXDUMP }, 25903658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt { RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, "WLAN-Group-Mgmt-Pairwise-Cipher", 26003658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt RADIUS_ATTR_HEXDUMP }, 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 26268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#define RADIUS_ATTRS ARRAY_SIZE(radius_attrs) 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2651d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidtstatic const struct radius_attr_type *radius_get_attr_type(u8 type) 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < RADIUS_ATTRS; i++) { 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (type == radius_attrs[i].type) 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return &radius_attrs[i]; 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void radius_msg_dump_attr(struct radius_attr_hdr *hdr) 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2801d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt const struct radius_attr_type *attr; 281bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt int len; 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned char *pos; 283bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt char buf[1000]; 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_type(hdr->type); 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 287bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d", 288bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt hdr->type, attr ? attr->name : "?Unknown?", hdr->length); 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 29061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr)) 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = hdr->length - sizeof(struct radius_attr_hdr); 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (unsigned char *) (hdr + 1); 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (attr->data_type) { 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_TEXT: 298bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt printf_encode(buf, sizeof(buf), pos, len); 299bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, " Value: '%s'", buf); 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_IP: 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 4) { 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct in_addr addr; 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(&addr, pos, 4); 306bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, " Value: %s", 307bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt inet_ntoa(addr)); 308bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt } else { 309bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, " Invalid IP address length %d", 310bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt len); 311bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt } 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IPV6 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_IPV6: 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 16) { 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const char *atxt; 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct in6_addr *addr = (struct in6_addr *) pos; 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf)); 320bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, " Value: %s", 321bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt atxt ? atxt : "?"); 322bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt } else { 323bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, " Invalid IPv6 address length %d", 324bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt len); 325bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt } 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IPV6 */ 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_HEXDUMP: 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_UNDIST: 331bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_snprintf_hex(buf, sizeof(buf), pos, len); 332bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, " Value: %s", buf); 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_INT32: 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 4) 337bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, " Value: %u", 338bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt WPA_GET_BE32(pos)); 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 340bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, " Invalid INT32 length %d", 341bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt len); 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid radius_msg_dump(struct radius_msg *msg) 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 354bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, "RADIUS message: code=%d (%s) identifier=%d length=%d", 355bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt msg->hdr->code, radius_code_string(msg->hdr->code), 356bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt msg->hdr->identifier, be_to_host16(msg->hdr->length)); 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_dump_attr(attr); 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_finish(struct radius_msg *msg, const u8 *secret, 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len) 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (secret) { 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 auth[MD5_MAC_LEN]; 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(auth, 0, MD5_MAC_LEN); 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_msg_add_attr(msg, 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt auth, MD5_MAC_LEN); 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Could not add " 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Message-Authenticator"); 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 38161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_len(msg->buf), (u8 *) (attr + 1)); 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 38561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_len(msg->buf) > 0xffff) { 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_len(msg->buf)); 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len, const u8 *req_authenticator) 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 auth[MD5_MAC_LEN]; 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[4]; 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len[4]; 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(auth, 0, MD5_MAC_LEN); 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt auth, MD5_MAC_LEN); 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 408bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_ERROR, "WARNING: Could not add Message-Authenticator"); 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 41161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(msg->hdr->authenticator, req_authenticator, 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(msg->hdr->authenticator)); 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_len(msg->buf), (u8 *) (attr + 1)); 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = (u8 *) msg->hdr; 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = 1 + 1 + 2; 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = req_authenticator; 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = MD5_MAC_LEN; 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[3] = secret; 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[3] = secret_len; 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(4, addr, len, msg->hdr->authenticator); 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_len(msg->buf) > 0xffff) { 4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_len(msg->buf)); 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 43704949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret, 43804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t secret_len, 43904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const struct radius_hdr *req_hdr) 44004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 44104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *addr[2]; 44204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t len[2]; 44304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 auth[MD5_MAC_LEN]; 44404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_attr_hdr *attr; 44504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 44604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(auth, 0, MD5_MAC_LEN); 44704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 44804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt auth, MD5_MAC_LEN); 44904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (attr == NULL) { 45004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_WARNING, "Could not add Message-Authenticator"); 45104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return -1; 45204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 45304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 45461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 45504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16); 45604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 45704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_len(msg->buf), (u8 *) (attr + 1)); 45804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 45904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 46004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[0] = wpabuf_head_u8(msg->buf); 46104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[0] = wpabuf_len(msg->buf); 46204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[1] = secret; 46304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[1] = secret_len; 46404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0) 46504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return -1; 46604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 46704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (wpabuf_len(msg->buf) > 0xffff) { 46804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 46904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (unsigned long) wpabuf_len(msg->buf)); 47004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return -1; 47104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 47204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 0; 47304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 47404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 47504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret, 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len) 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[2]; 4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len[2]; 4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 48261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN); 4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = wpabuf_head(msg->buf); 4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = wpabuf_len(msg->buf); 4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = secret; 4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = secret_len; 4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(2, addr, len, msg->hdr->authenticator); 4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_len(msg->buf) > 0xffff) { 4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)", 4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_len(msg->buf)); 4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 497bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidtvoid radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret, 498bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt size_t secret_len, const u8 *req_authenticator) 499bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt{ 500bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt const u8 *addr[2]; 501bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt size_t len[2]; 502bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt 503bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 504bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt os_memcpy(msg->hdr->authenticator, req_authenticator, MD5_MAC_LEN); 505bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt addr[0] = wpabuf_head(msg->buf); 506bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt len[0] = wpabuf_len(msg->buf); 507bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt addr[1] = secret; 508bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt len[1] = secret_len; 509bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt md5_vector(2, addr, len, msg->hdr->authenticator); 510bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt 511bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt if (wpabuf_len(msg->buf) > 0xffff) { 512bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)", 513bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt (unsigned long) wpabuf_len(msg->buf)); 514bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt } 515bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt} 516bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt 517bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt 51804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret, 51904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t secret_len) 52004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 52104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *addr[4]; 52204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t len[4]; 52304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 zero[MD5_MAC_LEN]; 52404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 hash[MD5_MAC_LEN]; 52504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 52604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(zero, 0, sizeof(zero)); 52704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[0] = (u8 *) msg->hdr; 52804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN; 52904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[1] = zero; 53004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[1] = MD5_MAC_LEN; 53104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[2] = (u8 *) (msg->hdr + 1); 53204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 53304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[3] = secret; 53404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[3] = secret_len; 53504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt md5_vector(4, addr, len, hash); 536c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt return os_memcmp_const(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0; 53704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 53804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 53904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 54004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret, 5417f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt size_t secret_len, 5427f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt int require_message_authenticator) 54304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 54404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *addr[4]; 54504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t len[4]; 54604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 zero[MD5_MAC_LEN]; 54704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 hash[MD5_MAC_LEN]; 54804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN]; 54904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 orig_authenticator[16]; 55004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 55104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_attr_hdr *attr = NULL, *tmp; 55204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t i; 55304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 55404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(zero, 0, sizeof(zero)); 55504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[0] = (u8 *) msg->hdr; 55604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN; 55704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[1] = zero; 55804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[1] = MD5_MAC_LEN; 55904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[2] = (u8 *) (msg->hdr + 1); 56004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 56104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[3] = secret; 56204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[3] = secret_len; 56304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt md5_vector(4, addr, len, hash); 564c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt if (os_memcmp_const(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0) 56504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 1; 56604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 56704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 56804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tmp = radius_get_attr_hdr(msg, i); 56904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) { 57004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (attr != NULL) { 57104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_WARNING, "Multiple " 57204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Message-Authenticator attributes " 57304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "in RADIUS message"); 57404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 1; 57504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 57604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attr = tmp; 57704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 57804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 57904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 58004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (attr == NULL) { 5817f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt if (require_message_authenticator) { 5827f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt wpa_printf(MSG_WARNING, 5837f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt "Missing Message-Authenticator attribute in RADIUS message"); 5847f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt return 1; 5857f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt } 58604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 0; 58704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 58804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 58904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(orig, attr + 1, MD5_MAC_LEN); 59004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(attr + 1, 0, MD5_MAC_LEN); 59104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(orig_authenticator, msg->hdr->authenticator, 59204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sizeof(orig_authenticator)); 59304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(msg->hdr->authenticator, 0, 59404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sizeof(msg->hdr->authenticator)); 59504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 59604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_len(msg->buf), auth); 59704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(attr + 1, orig, MD5_MAC_LEN); 59804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(msg->hdr->authenticator, orig_authenticator, 59904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sizeof(orig_authenticator)); 60004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 601c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt return os_memcmp_const(orig, auth, MD5_MAC_LEN) != 0; 60204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 60304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 60404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int radius_msg_add_attr_to_array(struct radius_msg *msg, 6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr) 6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg->attr_used >= msg->attr_size) { 6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t *nattr_pos; 6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int nlen = msg->attr_size * 2; 6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 61261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt nattr_pos = os_realloc_array(msg->attr_pos, nlen, 61361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt sizeof(*msg->attr_pos)); 6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (nattr_pos == NULL) 6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->attr_pos = nattr_pos; 6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->attr_size = nlen; 6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->attr_pos[msg->attr_used++] = 6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned char *) attr - wpabuf_head_u8(msg->buf); 6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, 6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *data, size_t data_len) 6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t buf_needed; 6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 634d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (TEST_FAIL()) 635d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt return NULL; 636d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data_len > RADIUS_MAX_ATTR_LEN) { 638bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_ERROR, "radius_msg_add_attr: too long attribute (%lu bytes)", 6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) data_len); 6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf_needed = sizeof(*attr) + data_len; 6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_tailroom(msg->buf) < buf_needed) { 6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* allocate more space for message buffer */ 6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_resize(&msg->buf, buf_needed) < 0) 6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr = wpabuf_mhead(msg->buf); 6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr)); 6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr->type = type; 6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr->length = sizeof(*attr) + data_len; 6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(msg->buf, data, data_len); 6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (radius_msg_add_attr_to_array(msg, attr)) 6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return attr; 6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * radius_msg_parse - Parse a RADIUS message 6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data: RADIUS message to be parsed 6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @len: Length of data buffer in octets 6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Parsed RADIUS message or %NULL on failure 6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This parses a RADIUS message and makes a copy of its data. The caller is 6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * responsible for freeing the returned data with radius_msg_free(). 6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_msg * radius_msg_parse(const u8 *data, size_t len) 6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_msg *msg; 6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_hdr *hdr; 6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t msg_len; 6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned char *pos, *end; 6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data == NULL || len < sizeof(*hdr)) 6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr = (struct radius_hdr *) data; 6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 68661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg_len = be_to_host16(hdr->length); 6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg_len < sizeof(*hdr) || msg_len > len) { 6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "RADIUS: Invalid message length"); 6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg_len < len) { 6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after " 6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "RADIUS message", (unsigned long) len - msg_len); 6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg = os_zalloc(sizeof(*msg)); 6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->buf = wpabuf_alloc_copy(data, msg_len); 7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg->buf == NULL || radius_msg_initialize(msg)) { 7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_free(msg); 7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr = wpabuf_mhead(msg->buf); 7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* parse attributes */ 7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr); 7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf); 7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (pos < end) { 7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((size_t) (end - pos) < sizeof(*attr)) 7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = (struct radius_attr_hdr *) pos; 7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 717d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (attr->length > end - pos || attr->length < sizeof(*attr)) 7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: check that attr->length is suitable for attr->type */ 7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (radius_msg_add_attr_to_array(msg, attr)) 7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += attr->length; 7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return msg; 7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt fail: 7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_free(msg); 7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len) 7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos = data; 7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t left = data_len; 7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (left > 0) { 7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int len; 7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (left > RADIUS_MAX_ATTR_LEN) 7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = RADIUS_MAX_ATTR_LEN; 7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = left; 7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE, 7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos, len)) 7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += len; 7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left -= len; 7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 76061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstruct wpabuf * radius_msg_get_eap(struct radius_msg *msg) 7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 76261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *eap; 7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len, i; 7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = 0; 7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_hdr(msg, i); 77261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (attr->type == RADIUS_ATTR_EAP_MESSAGE && 77361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt attr->length > sizeof(struct radius_attr_hdr)) 7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len += attr->length - sizeof(struct radius_attr_hdr); 7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 0) 7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 78061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt eap = wpabuf_alloc(len); 7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (eap == NULL) 7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_hdr(msg, i); 78661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (attr->type == RADIUS_ATTR_EAP_MESSAGE && 78761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt attr->length > sizeof(struct radius_attr_hdr)) { 7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int flen = attr->length - sizeof(*attr); 78961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(eap, attr + 1, flen); 7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap; 7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, 7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len, const u8 *req_auth) 7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN]; 8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 orig_authenticator[16]; 8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = NULL, *tmp; 8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp = radius_get_attr_hdr(msg, i); 8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) { 8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr != NULL) { 809bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, "Multiple Message-Authenticator attributes in RADIUS message"); 8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = tmp; 8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 817bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, "No Message-Authenticator attribute found"); 8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(orig, attr + 1, MD5_MAC_LEN); 8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(attr + 1, 0, MD5_MAC_LEN); 8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (req_auth) { 8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(orig_authenticator, msg->hdr->authenticator, 8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(orig_authenticator)); 8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(msg->hdr->authenticator, req_auth, 8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(msg->hdr->authenticator)); 8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 829849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 830849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_len(msg->buf), auth) < 0) 831849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return 1; 8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(attr + 1, orig, MD5_MAC_LEN); 8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (req_auth) { 8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(msg->hdr->authenticator, orig_authenticator, 8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(orig_authenticator)); 8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 838c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt if (os_memcmp_const(orig, auth, MD5_MAC_LEN) != 0) { 839bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, "Invalid Message-Authenticator!"); 8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_verify(struct radius_msg *msg, const u8 *secret, 8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len, struct radius_msg *sent_msg, int auth) 8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[4]; 8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len[4]; 8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[MD5_MAC_LEN]; 8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sent_msg == NULL) { 855bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, "No matching Access-Request message found"); 8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (auth && 8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_verify_msg_auth(msg, secret, secret_len, 8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sent_msg->hdr->authenticator)) { 8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = (u8 *) msg->hdr; 8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = 1 + 1 + 2; 8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = sent_msg->hdr->authenticator; 8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = MD5_MAC_LEN; 8708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); 8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[3] = secret; 8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[3] = secret_len; 874849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (md5_vector(4, addr, len, hash) < 0 || 875849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt os_memcmp_const(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) { 876bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, "Response Authenticator invalid!"); 8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src, 8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 type) 8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int count = 0; 8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < src->attr_used; i++) { 8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_hdr(src, i); 89361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (attr->type == type && attr->length >= sizeof(*attr)) { 8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1), 8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr->length - sizeof(*attr))) 8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count++; 8988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return count; 9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Create Request Authenticator. The value should be unique over the lifetime 9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * of the shared secret between authenticator and authentication server. 907b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt */ 908b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidtint radius_msg_make_authenticator(struct radius_msg *msg) 9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 910b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt return os_get_random((u8 *) &msg->hdr->authenticator, 911b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt sizeof(msg->hdr->authenticator)); 9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message. 9168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns the Attribute payload and sets alen to indicate the length of the 9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * payload if a vendor attribute with subtype is found, otherwise returns NULL. 9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The returned payload is allocated with os_malloc() and caller must free it 9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * by calling os_free(). 9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor, 9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 subtype, size_t *alen) 9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *data, *pos; 9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i, len; 9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 9288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 9298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 9328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t left; 9338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u32 vendor_id; 9348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_vendor *vhdr; 9358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 93661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC || 93761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt attr->length < sizeof(*attr)) 9388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 9398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left = attr->length - sizeof(*attr); 9418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (left < 4) 9428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 9438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (u8 *) (attr + 1); 9458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(&vendor_id, pos, 4); 9478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 4; 9488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left -= 4; 9498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ntohl(vendor_id) != vendor) 9518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 9528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (left >= sizeof(*vhdr)) { 9548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr = (struct radius_attr_vendor *) pos; 9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (vhdr->vendor_length > left || 9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_length < sizeof(*vhdr)) { 9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (vhdr->vendor_type != subtype) { 9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += vhdr->vendor_length; 9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left -= vhdr->vendor_length; 9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = vhdr->vendor_length - sizeof(*vhdr); 966d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt data = os_memdup(pos + sizeof(*vhdr), len); 9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data == NULL) 9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (alen) 9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *alen = len; 9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return data; 9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u8 * decrypt_ms_key(const u8 *key, size_t len, 9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *req_authenticator, 9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len, size_t *reslen) 9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *plain, *ppos, *res; 9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos; 9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t left, plen; 9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[MD5_MAC_LEN]; 9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i, first = 1; 9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[3]; 9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t elen[3]; 9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* key: 16-bit salt followed by encrypted key info */ 9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 993807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt if (len < 2 + 16) { 994807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt wpa_printf(MSG_DEBUG, "RADIUS: %s: Len is too small: %d", 995807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt __func__, (int) len); 9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 997807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt } 9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = key + 2; 10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left = len - 2; 10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (left % 16) { 1002807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt wpa_printf(MSG_INFO, "RADIUS: Invalid ms key len %lu", 1003bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt (unsigned long) left); 10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = left; 10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ppos = plain = os_malloc(plen); 10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (plain == NULL) 10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plain[0] = 0; 10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (left > 0) { 10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* b(1) = MD5(Secret + Request-Authenticator + Salt) 10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ 10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = secret; 10188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[0] = secret_len; 10198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (first) { 10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = req_authenticator; 10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[1] = MD5_MAC_LEN; 10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = key; 10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[2] = 2; /* Salt */ 10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = pos - MD5_MAC_LEN; 10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[1] = MD5_MAC_LEN; 10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1028849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (md5_vector(first ? 3 : 2, addr, elen, hash) < 0) { 1029849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt os_free(plain); 1030849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return NULL; 1031849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt first = 0; 10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < MD5_MAC_LEN; i++) 10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *ppos++ = *pos++ ^ hash[i]; 10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left -= MD5_MAC_LEN; 10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (plain[0] == 0 || plain[0] > plen - 1) { 1040807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt wpa_printf(MSG_INFO, "RADIUS: Failed to decrypt MPPE key"); 10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(plain); 10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1045d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt res = os_memdup(plain + 1, plain[0]); 10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (res == NULL) { 10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(plain); 10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (reslen) 10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *reslen = plain[0]; 10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(plain); 10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return res; 10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt, 10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *req_authenticator, 10598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len, 10608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *ebuf, size_t *elen) 10618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i, len, first = 1; 10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[MD5_MAC_LEN], saltbuf[2], *pos; 10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[3]; 10658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t _len[3]; 10668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(saltbuf, salt); 10688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = 1 + key_len; 10708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len & 0x0f) { 10718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = (len & 0xf0) + 16; 10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(ebuf, 0, len); 10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ebuf[0] = key_len; 10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(ebuf + 1, key, key_len); 10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *elen = len; 10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = ebuf; 10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (len > 0) { 10818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* b(1) = MD5(Secret + Request-Authenticator + Salt) 10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ 10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = secret; 10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt _len[0] = secret_len; 10858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (first) { 10868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = req_authenticator; 10878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt _len[1] = MD5_MAC_LEN; 10888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = saltbuf; 10898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt _len[2] = sizeof(saltbuf); 10908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 10918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = pos - MD5_MAC_LEN; 10928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt _len[1] = MD5_MAC_LEN; 10938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(first ? 3 : 2, addr, _len, hash); 10958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt first = 0; 10968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < MD5_MAC_LEN; i++) 10988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ ^= hash[i]; 10998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len -= MD5_MAC_LEN; 11018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 11038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_ms_mppe_keys * 11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtradius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg, 11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len) 11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 11098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *key; 11108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t keylen; 11118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_ms_mppe_keys *keys; 11128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL || sent_msg == NULL) 11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys = os_zalloc(sizeof(*keys)); 11178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (keys == NULL) 11188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, 11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY, 11228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keylen); 11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (key) { 11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->send = decrypt_ms_key(key, keylen, 11258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sent_msg->hdr->authenticator, 11268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret, secret_len, 11278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keys->send_len); 1128807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt if (!keys->send) { 1129807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt wpa_printf(MSG_DEBUG, 1130807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt "RADIUS: Failed to decrypt send key"); 1131807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt } 11328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(key); 11338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, 11368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY, 11378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keylen); 11388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (key) { 11398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->recv = decrypt_ms_key(key, keylen, 11408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sent_msg->hdr->authenticator, 11418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret, secret_len, 11428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keys->recv_len); 1143807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt if (!keys->recv) { 1144807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt wpa_printf(MSG_DEBUG, 1145807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt "RADIUS: Failed to decrypt recv key"); 1146807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt } 11478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(key); 11488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return keys; 11518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 11528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_ms_mppe_keys * 11558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtradius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg, 11568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len) 11578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 11588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *key; 11598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t keylen; 11608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_ms_mppe_keys *keys; 11618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL || sent_msg == NULL) 11638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys = os_zalloc(sizeof(*keys)); 11668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (keys == NULL) 11678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO, 11708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_CISCO_AV_PAIR, &keylen); 11718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (key && keylen == 51 && 11728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcmp(key, "leap:session-key=", 17) == 0) { 11738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->recv = decrypt_ms_key(key + 17, keylen - 17, 11748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sent_msg->hdr->authenticator, 11758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret, secret_len, 11768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keys->recv_len); 11778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(key); 11798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return keys; 11818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 11828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_add_mppe_keys(struct radius_msg *msg, 11858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *req_authenticator, 11868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len, 11878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *send_key, size_t send_key_len, 11888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *recv_key, size_t recv_key_len) 11898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 11908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 11918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT); 11928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *buf; 11938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_vendor *vhdr; 11948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *pos; 11958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t elen; 11968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int hlen; 11978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 salt; 11988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2; 12008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* MS-MPPE-Send-Key */ 12028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf = os_malloc(hlen + send_key_len + 16); 12038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (buf == NULL) { 12048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 12058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = buf; 12078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, &vendor_id, sizeof(vendor_id)); 12088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += sizeof(vendor_id); 12098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr = (struct radius_attr_vendor *) pos; 12108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY; 12118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (u8 *) (vhdr + 1); 1212849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (os_get_random((u8 *) &salt, sizeof(salt)) < 0) { 1213849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt os_free(buf); 1214b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt return 0; 1215849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 1216b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt salt |= 0x8000; 12178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(pos, salt); 12188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 2; 12198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret, 12208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret_len, pos, &elen); 12218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_length = hlen + elen - sizeof(vendor_id); 12228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 12248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf, hlen + elen); 12258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(buf); 12268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 12278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 12288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* MS-MPPE-Recv-Key */ 1231cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt buf = os_malloc(hlen + recv_key_len + 16); 12328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (buf == NULL) { 12338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 12348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = buf; 12368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, &vendor_id, sizeof(vendor_id)); 12378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += sizeof(vendor_id); 12388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr = (struct radius_attr_vendor *) pos; 12398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY; 12408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (u8 *) (vhdr + 1); 12418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt salt ^= 1; 12428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(pos, salt); 12438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 2; 12448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret, 12458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret_len, pos, &elen); 12468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_length = hlen + elen - sizeof(vendor_id); 12478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 12498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf, hlen + elen); 12508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(buf); 12518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 12528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 12538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 12568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 12578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1259f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtint radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data, 1260f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt size_t len) 1261f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{ 1262f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt struct radius_attr_hdr *attr; 1263f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 *buf, *pos; 1264f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt size_t alen; 1265f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1266f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt alen = 4 + 2 + len; 1267f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt buf = os_malloc(alen); 1268f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (buf == NULL) 1269f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return 0; 1270f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = buf; 1271f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt WPA_PUT_BE32(pos, RADIUS_VENDOR_ID_WFA); 1272f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos += 4; 1273f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt *pos++ = subtype; 1274f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt *pos++ = 2 + len; 1275f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_memcpy(pos, data, len); 1276f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 1277f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt buf, alen); 1278f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_free(buf); 1279f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (attr == NULL) 1280f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return 0; 1281f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1282f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return 1; 1283f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt} 1284f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1285f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1286df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtint radius_user_password_hide(struct radius_msg *msg, 1287df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt const u8 *data, size_t data_len, 1288df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt const u8 *secret, size_t secret_len, 1289df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt u8 *buf, size_t buf_len) 12908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1291df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt size_t padlen, i, pos; 12928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[2]; 12938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len[2]; 12948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[16]; 12958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1296df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt if (data_len + 16 > buf_len) 1297df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt return -1; 12988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(buf, data, data_len); 13008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt padlen = data_len % 16; 1302df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt if (padlen && data_len < buf_len) { 13038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt padlen = 16 - padlen; 13048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(buf + data_len, 0, padlen); 1305df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt buf_len = data_len + padlen; 1306df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt } else { 1307df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt buf_len = data_len; 13088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = secret; 13118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = secret_len; 13128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = msg->hdr->authenticator; 13138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = 16; 13148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(2, addr, len, hash); 13158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 13178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf[i] ^= hash[i]; 13188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = 16; 13198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (pos < buf_len) { 13218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = secret; 13228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = secret_len; 13238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = &buf[pos - 16]; 13248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = 16; 13258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(2, addr, len, hash); 13268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 13288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf[pos + i] ^= hash[i]; 13298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 16; 13318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1333df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt return buf_len; 1334df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt} 1335df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 1336df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 1337df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt/* Add User-Password attribute to a RADIUS message and encrypt it as specified 1338df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt * in RFC 2865, Chap. 5.2 */ 1339df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtstruct radius_attr_hdr * 1340df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtradius_msg_add_attr_user_password(struct radius_msg *msg, 1341df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt const u8 *data, size_t data_len, 1342df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt const u8 *secret, size_t secret_len) 1343df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt{ 1344df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt u8 buf[128]; 1345df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt int res; 1346df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 1347df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt res = radius_user_password_hide(msg, data, data_len, 1348df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt secret, secret_len, buf, sizeof(buf)); 1349df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt if (res < 0) 1350df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt return NULL; 1351df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 13528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD, 1353df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt buf, res); 13548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 13558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len) 13588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 13598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = NULL, *tmp; 13608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i, dlen; 13618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 13638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp = radius_get_attr_hdr(msg, i); 13648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tmp->type == type) { 13658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = tmp; 13668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 13678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 137061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!attr || attr->length < sizeof(*attr)) 13718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 13728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dlen = attr->length - sizeof(*attr); 13748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (buf) 13758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(buf, (attr + 1), dlen > len ? len : dlen); 13768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return dlen; 13778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 13788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf, 13818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t *len, const u8 *start) 13828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 13838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 13848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = NULL, *tmp; 13858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 13878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp = radius_get_attr_hdr(msg, i); 13888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tmp->type == type && 13898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (start == NULL || (u8 *) tmp > start)) { 13908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = tmp; 13918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 13928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 139561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!attr || attr->length < sizeof(*attr)) 13968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 13978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *buf = (u8 *) (attr + 1); 13998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *len = attr->length - sizeof(*attr); 14008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 14018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 14028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len) 14058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 14068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 14078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int count; 14088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (count = 0, i = 0; i < msg->attr_used; i++) { 14108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 14118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->type == type && 14128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr->length >= sizeof(struct radius_attr_hdr) + min_len) 14138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count++; 14148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 14158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return count; 14178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 14188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_tunnel_attrs { 14218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int tag_used; 14228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int type; /* Tunnel-Type */ 14238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int medium_type; /* Tunnel-Medium-Type */ 14248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int vlanid; 14258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 14268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 142857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtstatic int cmp_int(const void *a, const void *b) 142957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt{ 143057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt int x, y; 143157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 143257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt x = *((int *) a); 143357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt y = *((int *) b); 143457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return (x - y); 143557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt} 143657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 143757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 14388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 14398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information 144057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * The k tagged vlans found are sorted by vlan_id and stored in the first k 144157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * items of tagged. 144257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * 14438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @msg: RADIUS message 144457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * @untagged: Pointer to store untagged vid 144557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * @numtagged: Size of tagged 144657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * @tagged: Pointer to store tagged list 144757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * 144857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * Returns: 0 if neither tagged nor untagged configuration is found, 1 otherwise 14498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 145057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtint radius_msg_get_vlanid(struct radius_msg *msg, int *untagged, int numtagged, 145157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt int *tagged) 14528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 14538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun; 14548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 14558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = NULL; 14568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *data; 14578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char buf[10]; 14588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t dlen; 145957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt int j, taggedidx = 0, vlan_id; 14608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(&tunnel, 0, sizeof(tunnel)); 146257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt for (j = 0; j < numtagged; j++) 146357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt tagged[j] = 0; 146457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *untagged = 0; 14658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 14678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_hdr(msg, i); 146861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (attr->length < sizeof(*attr)) 146961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 14708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data = (const u8 *) (attr + 1); 14718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dlen = attr->length - sizeof(*attr); 14728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->length < 3) 14738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 14748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data[0] >= RADIUS_TUNNEL_TAGS) 14758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun = &tunnel[0]; 14768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 14778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun = &tunnel[data[0]]; 14788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (attr->type) { 14808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_TUNNEL_TYPE: 14818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->length != 6) 14828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 14838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->tag_used++; 14848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->type = WPA_GET_BE24(data + 1); 14858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 14868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE: 14878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->length != 6) 14888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 14898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->tag_used++; 14908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->medium_type = WPA_GET_BE24(data + 1); 14918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 14928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID: 14938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data[0] < RADIUS_TUNNEL_TAGS) { 14948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data++; 14958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dlen--; 14968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 14978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (dlen >= sizeof(buf)) 14988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 14998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(buf, data, dlen); 15008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf[dlen] = '\0'; 150157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt vlan_id = atoi(buf); 150257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (vlan_id <= 0) 150357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; 15048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->tag_used++; 150557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt tun->vlanid = vlan_id; 150657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; 150757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt case RADIUS_ATTR_EGRESS_VLANID: /* RFC 4675 */ 150857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (attr->length != 6) 150957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; 151057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt vlan_id = WPA_GET_BE24(data + 1); 151157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (vlan_id <= 0) 151257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; 151357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (data[0] == 0x32) 151457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *untagged = vlan_id; 151557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt else if (data[0] == 0x31 && tagged && 151657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt taggedidx < numtagged) 151757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt tagged[taggedidx++] = vlan_id; 15188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 15198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 15208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 15218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 152257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt /* Use tunnel with the lowest tag for untagged VLAN id */ 15238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) { 15248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun = &tunnel[i]; 15258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tun->tag_used && 15268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->type == RADIUS_TUNNEL_TYPE_VLAN && 15278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 && 152857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt tun->vlanid > 0) { 152957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *untagged = tun->vlanid; 153057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; 153157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 15328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 15338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 153457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (taggedidx) 153557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt qsort(tagged, taggedidx, sizeof(int), cmp_int); 153657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 153757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (*untagged > 0 || taggedidx) 153857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return 1; 15398347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidt return 0; 15408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 15418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 15428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 15431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/** 15441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password 15451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @msg: Received RADIUS message 15461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @keylen: Length of returned password 15471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @secret: RADIUS shared secret 15481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @secret_len: Length of secret 15491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @sent_msg: Sent RADIUS message 1550d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt * @n: Number of password attribute to return (starting with 0) 1551d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt * Returns: Pointer to n-th password (free with os_free) or %NULL 15521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */ 15531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtchar * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen, 15541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *secret, size_t secret_len, 1555d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt struct radius_msg *sent_msg, size_t n) 15561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 15571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 *buf = NULL; 15581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t buflen; 15591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *salt; 15601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 *str; 15611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *addr[3]; 15621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t len[3]; 15631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 hash[16]; 15641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 *pos; 1565d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt size_t i, j = 0; 15661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct radius_attr_hdr *attr; 15671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *data; 15681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t dlen; 15691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *fdata = NULL; /* points to found item */ 15701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t fdlen = -1; 15711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt char *ret = NULL; 15721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1573d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt /* find n-th valid Tunnel-Password attribute */ 15741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 15751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt attr = radius_get_attr_hdr(msg, i); 15761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (attr == NULL || 15771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) { 15781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt continue; 15791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 15801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (attr->length <= 5) 15811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt continue; 15821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt data = (const u8 *) (attr + 1); 15831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt dlen = attr->length - sizeof(*attr); 15841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (dlen <= 3 || dlen % 16 != 3) 15851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt continue; 1586d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt j++; 1587d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt if (j <= n) 15881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt continue; 15891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt fdata = data; 15911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt fdlen = dlen; 1592d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt break; 15931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 15941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (fdata == NULL) 15951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 15961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* alloc writable memory for decryption */ 1598d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt buf = os_memdup(fdata, fdlen); 15991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (buf == NULL) 16001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 16011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt buflen = fdlen; 16021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 16031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* init pointers */ 16041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt salt = buf + 1; 16051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt str = buf + 3; 16061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 16071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* decrypt blocks */ 16081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos = buf + buflen - 16; /* last block */ 16091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt while (pos >= str + 16) { /* all but the first block */ 16101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[0] = secret; 16111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[0] = secret_len; 16121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[1] = pos - 16; 16131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[1] = 16; 16141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt md5_vector(2, addr, len, hash); 16151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 16161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt for (i = 0; i < 16; i++) 16171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos[i] ^= hash[i]; 16181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 16191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos -= 16; 16201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 16211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 16221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* decrypt first block */ 16231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (str != pos) 16241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 16251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[0] = secret; 16261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[0] = secret_len; 16271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[1] = sent_msg->hdr->authenticator; 16281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[1] = 16; 16291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[2] = salt; 16301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[2] = 2; 16311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt md5_vector(3, addr, len, hash); 16321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 16331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt for (i = 0; i < 16; i++) 16341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos[i] ^= hash[i]; 16351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 16361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* derive plaintext length from first subfield */ 16371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt *keylen = (unsigned char) str[0]; 16381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if ((u8 *) (str + *keylen) >= (u8 *) (buf + buflen)) { 16391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* decryption error - invalid key length */ 16401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 16411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 16421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (*keylen == 0) { 16431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* empty password */ 16441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 16451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 16461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 16471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* copy passphrase into new buffer */ 16481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt ret = os_malloc(*keylen); 16491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (ret) 16501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_memcpy(ret, str + 1, *keylen); 16511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 16521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtout: 16531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* return new buffer */ 16541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(buf); 16551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return ret; 16561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 16571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 16581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 16598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid radius_free_class(struct radius_class_data *c) 16608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 16618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 16628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (c == NULL) 16638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 16648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < c->count; i++) 16658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(c->attr[i].data); 16668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(c->attr); 16678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt c->attr = NULL; 16688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt c->count = 0; 16698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 16708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_copy_class(struct radius_class_data *dst, 16738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct radius_class_data *src) 16748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 16758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 16768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (src->attr == NULL) 16788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 16798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 168061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt dst->attr = os_calloc(src->count, sizeof(struct radius_attr_data)); 16818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (dst->attr == NULL) 16828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 16838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dst->count = 0; 16858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < src->count; i++) { 1687d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt dst->attr[i].data = os_memdup(src->attr[i].data, 1688d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt src->attr[i].len); 16898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (dst->attr[i].data == NULL) 16908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 16918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dst->count++; 16928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dst->attr[i].len = src->attr[i].len; 16938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 16948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 16968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 169704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 169804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 169904949598a23f501be6eec21697465fd46a28840aDmitry Shmidtu8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs) 170004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 170104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t i, j; 170204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_attr_hdr *attr; 170304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 170404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 170504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attr = radius_get_attr_hdr(msg, i); 170604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 170704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (j = 0; attrs[j]; j++) { 170804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (attr->type == attrs[j]) 170904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 171004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 171104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 171204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (attrs[j] == 0) 171304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return attr->type; /* unlisted attr */ 171404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 171504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 171604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 0; 171704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 1718b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt 1719b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt 1720b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidtint radius_gen_session_id(u8 *id, size_t len) 1721b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt{ 1722b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt /* 1723b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt * Acct-Session-Id and Acct-Multi-Session-Id should be globally and 1724b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt * temporarily unique. A high quality random number is required 1725b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt * therefore. This could be be improved by switching to a GUID. 1726b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt */ 1727b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt return os_get_random(id, len); 1728b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt} 1729