18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * RADIUS message processing 3bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt * Copyright (c) 2002-2009, 2011-2014, 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 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic 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 }, 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 }, 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT }, 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST }, 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST }, 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST }, 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 }, 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 }, 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action", 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id", 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_TEXT }, 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id", 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_TEXT }, 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT }, 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST }, 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type", 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 }, 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets", 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets", 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT }, 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 }, 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time", 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets", 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets", 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause", 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id", 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_TEXT }, 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 }, 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords", 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords", 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp", 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 }, 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP }, 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type", 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_HEXDUMP }, 2211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt { RADIUS_ATTR_TUNNEL_PASSWORD, "Tunnel-Password", 2221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt RADIUS_ATTR_UNDIST }, 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT }, 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST }, 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator", 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_UNDIST }, 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id", 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_HEXDUMP }, 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval", 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_INT32 }, 23104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity", 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_TEXT }, 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 }, 2345a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt { RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 }, 2355a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt { RADIUS_ATTR_EAP_KEY_NAME, "EAP-Key-Name", RADIUS_ATTR_HEXDUMP }, 23603658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt { RADIUS_ATTR_MOBILITY_DOMAIN_ID, "Mobility-Domain-Id", 23703658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt RADIUS_ATTR_INT32 }, 23803658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt { RADIUS_ATTR_WLAN_HESSID, "WLAN-HESSID", RADIUS_ATTR_TEXT }, 23903658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt { RADIUS_ATTR_WLAN_PAIRWISE_CIPHER, "WLAN-Pairwise-Cipher", 24003658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt RADIUS_ATTR_HEXDUMP }, 24103658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt { RADIUS_ATTR_WLAN_GROUP_CIPHER, "WLAN-Group-Cipher", 24203658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt RADIUS_ATTR_HEXDUMP }, 24303658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt { RADIUS_ATTR_WLAN_AKM_SUITE, "WLAN-AKM-Suite", 24403658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt RADIUS_ATTR_HEXDUMP }, 24503658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt { RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, "WLAN-Group-Mgmt-Pairwise-Cipher", 24603658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt RADIUS_ATTR_HEXDUMP }, 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 24868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#define RADIUS_ATTRS ARRAY_SIZE(radius_attrs) 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct radius_attr_type *radius_get_attr_type(u8 type) 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < RADIUS_ATTRS; i++) { 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (type == radius_attrs[i].type) 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return &radius_attrs[i]; 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void radius_msg_dump_attr(struct radius_attr_hdr *hdr) 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_type *attr; 267bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt int len; 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned char *pos; 269bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt char buf[1000]; 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_type(hdr->type); 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 273bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d", 274bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt hdr->type, attr ? attr->name : "?Unknown?", hdr->length); 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 27661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr)) 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = hdr->length - sizeof(struct radius_attr_hdr); 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (unsigned char *) (hdr + 1); 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (attr->data_type) { 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_TEXT: 284bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt printf_encode(buf, sizeof(buf), pos, len); 285bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, " Value: '%s'", buf); 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_IP: 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 4) { 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct in_addr addr; 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(&addr, pos, 4); 292bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, " Value: %s", 293bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt inet_ntoa(addr)); 294bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt } else { 295bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, " Invalid IP address length %d", 296bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt len); 297bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt } 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IPV6 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_IPV6: 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 16) { 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const char *atxt; 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct in6_addr *addr = (struct in6_addr *) pos; 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf)); 306bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, " Value: %s", 307bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt atxt ? atxt : "?"); 308bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt } else { 309bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, " Invalid IPv6 address length %d", 310bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt len); 311bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt } 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IPV6 */ 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_HEXDUMP: 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_UNDIST: 317bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_snprintf_hex(buf, sizeof(buf), pos, len); 318bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, " Value: %s", buf); 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_INT32: 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 4) 323bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, " Value: %u", 324bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt WPA_GET_BE32(pos)); 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 326bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, " Invalid INT32 length %d", 327bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt len); 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid radius_msg_dump(struct radius_msg *msg) 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 340bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, "RADIUS message: code=%d (%s) identifier=%d length=%d", 341bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt msg->hdr->code, radius_code_string(msg->hdr->code), 342bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt msg->hdr->identifier, be_to_host16(msg->hdr->length)); 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_dump_attr(attr); 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_finish(struct radius_msg *msg, const u8 *secret, 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len) 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (secret) { 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 auth[MD5_MAC_LEN]; 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(auth, 0, MD5_MAC_LEN); 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_msg_add_attr(msg, 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt auth, MD5_MAC_LEN); 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Could not add " 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Message-Authenticator"); 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 36761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_len(msg->buf), (u8 *) (attr + 1)); 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 37161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_len(msg->buf) > 0xffff) { 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_len(msg->buf)); 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len, const u8 *req_authenticator) 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 auth[MD5_MAC_LEN]; 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[4]; 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len[4]; 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(auth, 0, MD5_MAC_LEN); 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt auth, MD5_MAC_LEN); 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 394bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_ERROR, "WARNING: Could not add Message-Authenticator"); 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 39761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(msg->hdr->authenticator, req_authenticator, 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(msg->hdr->authenticator)); 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_len(msg->buf), (u8 *) (attr + 1)); 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = (u8 *) msg->hdr; 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = 1 + 1 + 2; 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = req_authenticator; 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = MD5_MAC_LEN; 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[3] = secret; 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[3] = secret_len; 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(4, addr, len, msg->hdr->authenticator); 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_len(msg->buf) > 0xffff) { 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_len(msg->buf)); 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 42304949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret, 42404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t secret_len, 42504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const struct radius_hdr *req_hdr) 42604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 42704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *addr[2]; 42804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t len[2]; 42904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 auth[MD5_MAC_LEN]; 43004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_attr_hdr *attr; 43104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 43204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(auth, 0, MD5_MAC_LEN); 43304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 43404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt auth, MD5_MAC_LEN); 43504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (attr == NULL) { 43604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_WARNING, "Could not add Message-Authenticator"); 43704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return -1; 43804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 43904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 44061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 44104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16); 44204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 44304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_len(msg->buf), (u8 *) (attr + 1)); 44404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 44504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 44604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[0] = wpabuf_head_u8(msg->buf); 44704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[0] = wpabuf_len(msg->buf); 44804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[1] = secret; 44904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[1] = secret_len; 45004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0) 45104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return -1; 45204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 45304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (wpabuf_len(msg->buf) > 0xffff) { 45404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 45504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (unsigned long) wpabuf_len(msg->buf)); 45604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return -1; 45704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 45804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 0; 45904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 46004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 46104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret, 4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len) 4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[2]; 4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len[2]; 4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 46861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN); 4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = wpabuf_head(msg->buf); 4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = wpabuf_len(msg->buf); 4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = secret; 4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = secret_len; 4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(2, addr, len, msg->hdr->authenticator); 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_len(msg->buf) > 0xffff) { 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)", 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_len(msg->buf)); 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 483bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidtvoid radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret, 484bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt size_t secret_len, const u8 *req_authenticator) 485bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt{ 486bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt const u8 *addr[2]; 487bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt size_t len[2]; 488bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt 489bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 490bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt os_memcpy(msg->hdr->authenticator, req_authenticator, MD5_MAC_LEN); 491bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt addr[0] = wpabuf_head(msg->buf); 492bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt len[0] = wpabuf_len(msg->buf); 493bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt addr[1] = secret; 494bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt len[1] = secret_len; 495bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt md5_vector(2, addr, len, msg->hdr->authenticator); 496bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt 497bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt if (wpabuf_len(msg->buf) > 0xffff) { 498bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)", 499bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt (unsigned long) wpabuf_len(msg->buf)); 500bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt } 501bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt} 502bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt 503bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt 50404949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret, 50504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t secret_len) 50604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 50704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *addr[4]; 50804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t len[4]; 50904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 zero[MD5_MAC_LEN]; 51004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 hash[MD5_MAC_LEN]; 51104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 51204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(zero, 0, sizeof(zero)); 51304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[0] = (u8 *) msg->hdr; 51404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN; 51504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[1] = zero; 51604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[1] = MD5_MAC_LEN; 51704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[2] = (u8 *) (msg->hdr + 1); 51804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 51904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[3] = secret; 52004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[3] = secret_len; 52104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt md5_vector(4, addr, len, hash); 522c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt return os_memcmp_const(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0; 52304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 52404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 52504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 52604949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret, 52704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t secret_len) 52804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 52904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *addr[4]; 53004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t len[4]; 53104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 zero[MD5_MAC_LEN]; 53204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 hash[MD5_MAC_LEN]; 53304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN]; 53404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 orig_authenticator[16]; 53504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 53604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_attr_hdr *attr = NULL, *tmp; 53704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t i; 53804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 53904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(zero, 0, sizeof(zero)); 54004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[0] = (u8 *) msg->hdr; 54104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN; 54204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[1] = zero; 54304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[1] = MD5_MAC_LEN; 54404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[2] = (u8 *) (msg->hdr + 1); 54504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 54604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[3] = secret; 54704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[3] = secret_len; 54804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt md5_vector(4, addr, len, hash); 549c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt if (os_memcmp_const(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0) 55004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 1; 55104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 55204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 55304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tmp = radius_get_attr_hdr(msg, i); 55404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) { 55504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (attr != NULL) { 55604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_WARNING, "Multiple " 55704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Message-Authenticator attributes " 55804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "in RADIUS message"); 55904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 1; 56004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 56104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attr = tmp; 56204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 56304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 56404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 56504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (attr == NULL) { 56604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* Message-Authenticator is MAY; not required */ 56704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 0; 56804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 56904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 57004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(orig, attr + 1, MD5_MAC_LEN); 57104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(attr + 1, 0, MD5_MAC_LEN); 57204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(orig_authenticator, msg->hdr->authenticator, 57304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sizeof(orig_authenticator)); 57404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(msg->hdr->authenticator, 0, 57504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sizeof(msg->hdr->authenticator)); 57604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 57704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_len(msg->buf), auth); 57804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(attr + 1, orig, MD5_MAC_LEN); 57904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(msg->hdr->authenticator, orig_authenticator, 58004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sizeof(orig_authenticator)); 58104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 582c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt return os_memcmp_const(orig, auth, MD5_MAC_LEN) != 0; 58304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 58404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 58504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int radius_msg_add_attr_to_array(struct radius_msg *msg, 5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr) 5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg->attr_used >= msg->attr_size) { 5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t *nattr_pos; 5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int nlen = msg->attr_size * 2; 5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 59361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt nattr_pos = os_realloc_array(msg->attr_pos, nlen, 59461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt sizeof(*msg->attr_pos)); 5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (nattr_pos == NULL) 5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->attr_pos = nattr_pos; 5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->attr_size = nlen; 6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->attr_pos[msg->attr_used++] = 6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned char *) attr - wpabuf_head_u8(msg->buf); 6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, 6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *data, size_t data_len) 6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t buf_needed; 6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data_len > RADIUS_MAX_ATTR_LEN) { 616bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_ERROR, "radius_msg_add_attr: too long attribute (%lu bytes)", 6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) data_len); 6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf_needed = sizeof(*attr) + data_len; 6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_tailroom(msg->buf) < buf_needed) { 6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* allocate more space for message buffer */ 6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_resize(&msg->buf, buf_needed) < 0) 6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr = wpabuf_mhead(msg->buf); 6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr)); 6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr->type = type; 6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr->length = sizeof(*attr) + data_len; 6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(msg->buf, data, data_len); 6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (radius_msg_add_attr_to_array(msg, attr)) 6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return attr; 6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * radius_msg_parse - Parse a RADIUS message 6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data: RADIUS message to be parsed 6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @len: Length of data buffer in octets 6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Parsed RADIUS message or %NULL on failure 6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This parses a RADIUS message and makes a copy of its data. The caller is 6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * responsible for freeing the returned data with radius_msg_free(). 6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_msg * radius_msg_parse(const u8 *data, size_t len) 6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_msg *msg; 6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_hdr *hdr; 6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t msg_len; 6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned char *pos, *end; 6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data == NULL || len < sizeof(*hdr)) 6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr = (struct radius_hdr *) data; 6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 66461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg_len = be_to_host16(hdr->length); 6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg_len < sizeof(*hdr) || msg_len > len) { 6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "RADIUS: Invalid message length"); 6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg_len < len) { 6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after " 6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "RADIUS message", (unsigned long) len - msg_len); 6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg = os_zalloc(sizeof(*msg)); 6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->buf = wpabuf_alloc_copy(data, msg_len); 6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg->buf == NULL || radius_msg_initialize(msg)) { 6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_free(msg); 6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr = wpabuf_mhead(msg->buf); 6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* parse attributes */ 6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr); 6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf); 6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (pos < end) { 6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((size_t) (end - pos) < sizeof(*attr)) 6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = (struct radius_attr_hdr *) pos; 6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos + attr->length > end || attr->length < sizeof(*attr)) 6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: check that attr->length is suitable for attr->type */ 6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (radius_msg_add_attr_to_array(msg, attr)) 7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += attr->length; 7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return msg; 7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt fail: 7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_free(msg); 7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len) 7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos = data; 7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t left = data_len; 7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (left > 0) { 7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int len; 7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (left > RADIUS_MAX_ATTR_LEN) 7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = RADIUS_MAX_ATTR_LEN; 7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = left; 7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE, 7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos, len)) 7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += len; 7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left -= len; 7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 73861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstruct wpabuf * radius_msg_get_eap(struct radius_msg *msg) 7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 74061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *eap; 7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len, i; 7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = 0; 7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_hdr(msg, i); 75061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (attr->type == RADIUS_ATTR_EAP_MESSAGE && 75161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt attr->length > sizeof(struct radius_attr_hdr)) 7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len += attr->length - sizeof(struct radius_attr_hdr); 7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 0) 7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 75861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt eap = wpabuf_alloc(len); 7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (eap == NULL) 7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_hdr(msg, i); 76461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (attr->type == RADIUS_ATTR_EAP_MESSAGE && 76561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt attr->length > sizeof(struct radius_attr_hdr)) { 7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int flen = attr->length - sizeof(*attr); 76761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(eap, attr + 1, flen); 7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap; 7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, 7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len, const u8 *req_auth) 7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN]; 7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 orig_authenticator[16]; 7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = NULL, *tmp; 7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp = radius_get_attr_hdr(msg, i); 7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) { 7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr != NULL) { 787bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, "Multiple Message-Authenticator attributes in RADIUS message"); 7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = tmp; 7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 795bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, "No Message-Authenticator attribute found"); 7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(orig, attr + 1, MD5_MAC_LEN); 8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(attr + 1, 0, MD5_MAC_LEN); 8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (req_auth) { 8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(orig_authenticator, msg->hdr->authenticator, 8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(orig_authenticator)); 8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(msg->hdr->authenticator, req_auth, 8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(msg->hdr->authenticator)); 8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_len(msg->buf), auth); 8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(attr + 1, orig, MD5_MAC_LEN); 8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (req_auth) { 8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(msg->hdr->authenticator, orig_authenticator, 8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(orig_authenticator)); 8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 815c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt if (os_memcmp_const(orig, auth, MD5_MAC_LEN) != 0) { 816bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, "Invalid Message-Authenticator!"); 8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_verify(struct radius_msg *msg, const u8 *secret, 8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len, struct radius_msg *sent_msg, int auth) 8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[4]; 8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len[4]; 8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[MD5_MAC_LEN]; 8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sent_msg == NULL) { 832bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, "No matching Access-Request message found"); 8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (auth && 8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_verify_msg_auth(msg, secret, secret_len, 8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sent_msg->hdr->authenticator)) { 8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = (u8 *) msg->hdr; 8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = 1 + 1 + 2; 8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = sent_msg->hdr->authenticator; 8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = MD5_MAC_LEN; 8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); 8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[3] = secret; 8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[3] = secret_len; 8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(4, addr, len, hash); 852c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt if (os_memcmp_const(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) { 853bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, "Response Authenticator invalid!"); 8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src, 8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 type) 8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int count = 0; 8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < src->attr_used; i++) { 8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_hdr(src, i); 87061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (attr->type == type && attr->length >= sizeof(*attr)) { 8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1), 8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr->length - sizeof(*attr))) 8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count++; 8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return count; 8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Create Request Authenticator. The value should be unique over the lifetime 8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * of the shared secret between authenticator and authentication server. 8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Use one-way MD5 hash calculated from current timestamp and some data given 8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * by the caller. */ 8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid radius_msg_make_authenticator(struct radius_msg *msg, 8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *data, size_t len) 8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct os_time tv; 8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt long int l; 8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[3]; 8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t elen[3]; 8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_get_time(&tv); 8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt l = os_random(); 8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = (u8 *) &tv; 8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[0] = sizeof(tv); 8988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = data; 8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[1] = len; 9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = (u8 *) &l; 9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[2] = sizeof(l); 9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(3, addr, elen, msg->hdr->authenticator); 9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message. 9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns the Attribute payload and sets alen to indicate the length of the 9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * payload if a vendor attribute with subtype is found, otherwise returns NULL. 9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The returned payload is allocated with os_malloc() and caller must free it 9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * by calling os_free(). 9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor, 9138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 subtype, size_t *alen) 9148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *data, *pos; 9168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i, len; 9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t left; 9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u32 vendor_id; 9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_vendor *vhdr; 9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 92761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC || 92861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt attr->length < sizeof(*attr)) 9298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 9308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left = attr->length - sizeof(*attr); 9328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (left < 4) 9338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 9348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (u8 *) (attr + 1); 9368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(&vendor_id, pos, 4); 9388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 4; 9398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left -= 4; 9408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ntohl(vendor_id) != vendor) 9428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 9438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (left >= sizeof(*vhdr)) { 9458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr = (struct radius_attr_vendor *) pos; 9468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (vhdr->vendor_length > left || 9478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_length < sizeof(*vhdr)) { 9488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left = 0; 9498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 9508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (vhdr->vendor_type != subtype) { 9528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += vhdr->vendor_length; 9538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left -= vhdr->vendor_length; 9548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = vhdr->vendor_length - sizeof(*vhdr); 9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data = os_malloc(len); 9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data == NULL) 9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(data, pos + sizeof(*vhdr), len); 9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (alen) 9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *alen = len; 9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return data; 9658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u8 * decrypt_ms_key(const u8 *key, size_t len, 9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *req_authenticator, 9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len, size_t *reslen) 9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *plain, *ppos, *res; 9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos; 9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t left, plen; 9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[MD5_MAC_LEN]; 9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i, first = 1; 9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[3]; 9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t elen[3]; 9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* key: 16-bit salt followed by encrypted key info */ 9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len < 2 + 16) 9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = key + 2; 9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left = len - 2; 9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (left % 16) { 992bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, "Invalid ms key len %lu", 993bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt (unsigned long) left); 9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = left; 9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ppos = plain = os_malloc(plen); 9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (plain == NULL) 10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plain[0] = 0; 10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (left > 0) { 10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* b(1) = MD5(Secret + Request-Authenticator + Salt) 10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ 10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = secret; 10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[0] = secret_len; 10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (first) { 10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = req_authenticator; 10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[1] = MD5_MAC_LEN; 10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = key; 10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[2] = 2; /* Salt */ 10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = pos - MD5_MAC_LEN; 10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[1] = MD5_MAC_LEN; 10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(first ? 3 : 2, addr, elen, hash); 10198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt first = 0; 10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < MD5_MAC_LEN; i++) 10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *ppos++ = *pos++ ^ hash[i]; 10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left -= MD5_MAC_LEN; 10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (plain[0] == 0 || plain[0] > plen - 1) { 1027bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt wpa_printf(MSG_INFO, "Failed to decrypt MPPE key"); 10288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(plain); 10298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = os_malloc(plain[0]); 10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (res == NULL) { 10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(plain); 10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(res, plain + 1, plain[0]); 10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (reslen) 10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *reslen = plain[0]; 10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(plain); 10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return res; 10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt, 10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *req_authenticator, 10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len, 10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *ebuf, size_t *elen) 10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i, len, first = 1; 10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[MD5_MAC_LEN], saltbuf[2], *pos; 10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[3]; 10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t _len[3]; 10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(saltbuf, salt); 10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = 1 + key_len; 10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len & 0x0f) { 10598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = (len & 0xf0) + 16; 10608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(ebuf, 0, len); 10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ebuf[0] = key_len; 10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(ebuf + 1, key, key_len); 10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *elen = len; 10668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = ebuf; 10688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (len > 0) { 10698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* b(1) = MD5(Secret + Request-Authenticator + Salt) 10708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ 10718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = secret; 10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt _len[0] = secret_len; 10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (first) { 10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = req_authenticator; 10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt _len[1] = MD5_MAC_LEN; 10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = saltbuf; 10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt _len[2] = sizeof(saltbuf); 10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = pos - MD5_MAC_LEN; 10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt _len[1] = MD5_MAC_LEN; 10818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(first ? 3 : 2, addr, _len, hash); 10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt first = 0; 10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < MD5_MAC_LEN; i++) 10868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ ^= hash[i]; 10878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len -= MD5_MAC_LEN; 10898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 10918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_ms_mppe_keys * 10948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtradius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg, 10958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len) 10968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 10978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *key; 10988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t keylen; 10998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_ms_mppe_keys *keys; 11008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL || sent_msg == NULL) 11028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys = os_zalloc(sizeof(*keys)); 11058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (keys == NULL) 11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, 11098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY, 11108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keylen); 11118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (key) { 11128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->send = decrypt_ms_key(key, keylen, 11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sent_msg->hdr->authenticator, 11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret, secret_len, 11158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keys->send_len); 11168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(key); 11178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, 11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY, 11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keylen); 11228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (key) { 11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->recv = decrypt_ms_key(key, keylen, 11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sent_msg->hdr->authenticator, 11258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret, secret_len, 11268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keys->recv_len); 11278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(key); 11288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return keys; 11318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 11328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_ms_mppe_keys * 11358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtradius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg, 11368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len) 11378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 11388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *key; 11398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t keylen; 11408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_ms_mppe_keys *keys; 11418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL || sent_msg == NULL) 11438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys = os_zalloc(sizeof(*keys)); 11468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (keys == NULL) 11478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO, 11508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_CISCO_AV_PAIR, &keylen); 11518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (key && keylen == 51 && 11528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcmp(key, "leap:session-key=", 17) == 0) { 11538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->recv = decrypt_ms_key(key + 17, keylen - 17, 11548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sent_msg->hdr->authenticator, 11558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret, secret_len, 11568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keys->recv_len); 11578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(key); 11598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return keys; 11618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 11628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_add_mppe_keys(struct radius_msg *msg, 11658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *req_authenticator, 11668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len, 11678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *send_key, size_t send_key_len, 11688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *recv_key, size_t recv_key_len) 11698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 11708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 11718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT); 11728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *buf; 11738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_vendor *vhdr; 11748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *pos; 11758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t elen; 11768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int hlen; 11778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 salt; 11788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2; 11808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* MS-MPPE-Send-Key */ 11828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf = os_malloc(hlen + send_key_len + 16); 11838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (buf == NULL) { 11848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 11858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = buf; 11878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, &vendor_id, sizeof(vendor_id)); 11888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += sizeof(vendor_id); 11898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr = (struct radius_attr_vendor *) pos; 11908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY; 11918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (u8 *) (vhdr + 1); 11928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt salt = os_random() | 0x8000; 11938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(pos, salt); 11948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 2; 11958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret, 11968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret_len, pos, &elen); 11978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_length = hlen + elen - sizeof(vendor_id); 11988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 12008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf, hlen + elen); 12018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(buf); 12028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 12038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 12048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* MS-MPPE-Recv-Key */ 12078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf = os_malloc(hlen + send_key_len + 16); 12088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (buf == NULL) { 12098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 12108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = buf; 12128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, &vendor_id, sizeof(vendor_id)); 12138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += sizeof(vendor_id); 12148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr = (struct radius_attr_vendor *) pos; 12158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY; 12168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (u8 *) (vhdr + 1); 12178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt salt ^= 1; 12188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(pos, salt); 12198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 2; 12208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret, 12218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret_len, pos, &elen); 12228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_length = hlen + elen - sizeof(vendor_id); 12238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 12258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf, hlen + elen); 12268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(buf); 12278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 12288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 12298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 12328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 12338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1235f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtint radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data, 1236f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt size_t len) 1237f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{ 1238f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt struct radius_attr_hdr *attr; 1239f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 *buf, *pos; 1240f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt size_t alen; 1241f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1242f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt alen = 4 + 2 + len; 1243f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt buf = os_malloc(alen); 1244f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (buf == NULL) 1245f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return 0; 1246f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = buf; 1247f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt WPA_PUT_BE32(pos, RADIUS_VENDOR_ID_WFA); 1248f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos += 4; 1249f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt *pos++ = subtype; 1250f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt *pos++ = 2 + len; 1251f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_memcpy(pos, data, len); 1252f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 1253f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt buf, alen); 1254f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_free(buf); 1255f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (attr == NULL) 1256f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return 0; 1257f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1258f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return 1; 1259f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt} 1260f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1261f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1262df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtint radius_user_password_hide(struct radius_msg *msg, 1263df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt const u8 *data, size_t data_len, 1264df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt const u8 *secret, size_t secret_len, 1265df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt u8 *buf, size_t buf_len) 12668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1267df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt size_t padlen, i, pos; 12688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[2]; 12698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len[2]; 12708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[16]; 12718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1272df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt if (data_len + 16 > buf_len) 1273df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt return -1; 12748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(buf, data, data_len); 12768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt padlen = data_len % 16; 1278df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt if (padlen && data_len < buf_len) { 12798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt padlen = 16 - padlen; 12808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(buf + data_len, 0, padlen); 1281df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt buf_len = data_len + padlen; 1282df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt } else { 1283df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt buf_len = data_len; 12848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = secret; 12878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = secret_len; 12888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = msg->hdr->authenticator; 12898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = 16; 12908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(2, addr, len, hash); 12918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 12938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf[i] ^= hash[i]; 12948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = 16; 12958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (pos < buf_len) { 12978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = secret; 12988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = secret_len; 12998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = &buf[pos - 16]; 13008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = 16; 13018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(2, addr, len, hash); 13028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 13048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf[pos + i] ^= hash[i]; 13058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 16; 13078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1309df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt return buf_len; 1310df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt} 1311df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 1312df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 1313df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt/* Add User-Password attribute to a RADIUS message and encrypt it as specified 1314df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt * in RFC 2865, Chap. 5.2 */ 1315df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtstruct radius_attr_hdr * 1316df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtradius_msg_add_attr_user_password(struct radius_msg *msg, 1317df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt const u8 *data, size_t data_len, 1318df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt const u8 *secret, size_t secret_len) 1319df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt{ 1320df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt u8 buf[128]; 1321df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt int res; 1322df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 1323df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt res = radius_user_password_hide(msg, data, data_len, 1324df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt secret, secret_len, buf, sizeof(buf)); 1325df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt if (res < 0) 1326df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt return NULL; 1327df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 13288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD, 1329df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt buf, res); 13308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 13318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len) 13348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 13358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = NULL, *tmp; 13368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i, dlen; 13378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 13398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp = radius_get_attr_hdr(msg, i); 13408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tmp->type == type) { 13418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = tmp; 13428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 13438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 134661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!attr || attr->length < sizeof(*attr)) 13478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 13488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dlen = attr->length - sizeof(*attr); 13508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (buf) 13518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(buf, (attr + 1), dlen > len ? len : dlen); 13528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return dlen; 13538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 13548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf, 13578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t *len, const u8 *start) 13588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 13598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 13608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = NULL, *tmp; 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 (start == NULL || (u8 *) tmp > start)) { 13668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = tmp; 13678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 13688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 137161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!attr || attr->length < sizeof(*attr)) 13728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 13738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *buf = (u8 *) (attr + 1); 13758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *len = attr->length - sizeof(*attr); 13768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 13778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 13788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len) 13818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 13828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 13838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int count; 13848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (count = 0, i = 0; i < msg->attr_used; i++) { 13868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 13878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->type == type && 13888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr->length >= sizeof(struct radius_attr_hdr) + min_len) 13898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count++; 13908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return count; 13938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 13948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_tunnel_attrs { 13978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int tag_used; 13988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int type; /* Tunnel-Type */ 13998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int medium_type; /* Tunnel-Medium-Type */ 14008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int vlanid; 14018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 14028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 14058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information 14068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @msg: RADIUS message 14078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: VLAN ID for the first tunnel configuration of -1 if none is found 14088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 14098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_get_vlanid(struct radius_msg *msg) 14108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 14118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun; 14128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 14138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = NULL; 14148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *data; 14158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char buf[10]; 14168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t dlen; 14178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(&tunnel, 0, sizeof(tunnel)); 14198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 14218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_hdr(msg, i); 142261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (attr->length < sizeof(*attr)) 142361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 14248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data = (const u8 *) (attr + 1); 14258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dlen = attr->length - sizeof(*attr); 14268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->length < 3) 14278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 14288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data[0] >= RADIUS_TUNNEL_TAGS) 14298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun = &tunnel[0]; 14308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 14318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun = &tunnel[data[0]]; 14328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (attr->type) { 14348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_TUNNEL_TYPE: 14358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->length != 6) 14368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 14378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->tag_used++; 14388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->type = WPA_GET_BE24(data + 1); 14398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 14408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE: 14418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->length != 6) 14428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 14438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->tag_used++; 14448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->medium_type = WPA_GET_BE24(data + 1); 14458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 14468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID: 14478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data[0] < RADIUS_TUNNEL_TAGS) { 14488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data++; 14498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dlen--; 14508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 14518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (dlen >= sizeof(buf)) 14528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 14538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(buf, data, dlen); 14548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf[dlen] = '\0'; 14558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->tag_used++; 14568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->vlanid = atoi(buf); 14578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 14588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 14598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 14608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) { 14628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun = &tunnel[i]; 14638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tun->tag_used && 14648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->type == RADIUS_TUNNEL_TYPE_VLAN && 14658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 && 14668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->vlanid > 0) 14678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return tun->vlanid; 14688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 14698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 14718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 14728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/** 14751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password 14761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @msg: Received RADIUS message 14771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @keylen: Length of returned password 14781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @secret: RADIUS shared secret 14791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @secret_len: Length of secret 14801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @sent_msg: Sent RADIUS message 1481d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt * @n: Number of password attribute to return (starting with 0) 1482d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt * Returns: Pointer to n-th password (free with os_free) or %NULL 14831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */ 14841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtchar * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen, 14851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *secret, size_t secret_len, 1486d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt struct radius_msg *sent_msg, size_t n) 14871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 14881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 *buf = NULL; 14891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t buflen; 14901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *salt; 14911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 *str; 14921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *addr[3]; 14931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t len[3]; 14941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 hash[16]; 14951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 *pos; 1496d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt size_t i, j = 0; 14971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct radius_attr_hdr *attr; 14981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *data; 14991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t dlen; 15001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *fdata = NULL; /* points to found item */ 15011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t fdlen = -1; 15021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt char *ret = NULL; 15031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1504d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt /* find n-th valid Tunnel-Password attribute */ 15051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 15061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt attr = radius_get_attr_hdr(msg, i); 15071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (attr == NULL || 15081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) { 15091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt continue; 15101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 15111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (attr->length <= 5) 15121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt continue; 15131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt data = (const u8 *) (attr + 1); 15141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt dlen = attr->length - sizeof(*attr); 15151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (dlen <= 3 || dlen % 16 != 3) 15161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt continue; 1517d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt j++; 1518d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt if (j <= n) 15191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt continue; 15201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt fdata = data; 15221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt fdlen = dlen; 1523d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt break; 15241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 15251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (fdata == NULL) 15261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 15271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* alloc writable memory for decryption */ 15291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt buf = os_malloc(fdlen); 15301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (buf == NULL) 15311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 15321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_memcpy(buf, fdata, fdlen); 15331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt buflen = fdlen; 15341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* init pointers */ 15361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt salt = buf + 1; 15371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt str = buf + 3; 15381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* decrypt blocks */ 15401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos = buf + buflen - 16; /* last block */ 15411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt while (pos >= str + 16) { /* all but the first block */ 15421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[0] = secret; 15431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[0] = secret_len; 15441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[1] = pos - 16; 15451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[1] = 16; 15461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt md5_vector(2, addr, len, hash); 15471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt for (i = 0; i < 16; i++) 15491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos[i] ^= hash[i]; 15501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos -= 16; 15521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 15531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* decrypt first block */ 15551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (str != pos) 15561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 15571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[0] = secret; 15581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[0] = secret_len; 15591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[1] = sent_msg->hdr->authenticator; 15601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[1] = 16; 15611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[2] = salt; 15621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[2] = 2; 15631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt md5_vector(3, addr, len, hash); 15641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt for (i = 0; i < 16; i++) 15661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos[i] ^= hash[i]; 15671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* derive plaintext length from first subfield */ 15691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt *keylen = (unsigned char) str[0]; 15701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if ((u8 *) (str + *keylen) >= (u8 *) (buf + buflen)) { 15711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* decryption error - invalid key length */ 15721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 15731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 15741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (*keylen == 0) { 15751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* empty password */ 15761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 15771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 15781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* copy passphrase into new buffer */ 15801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt ret = os_malloc(*keylen); 15811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (ret) 15821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_memcpy(ret, str + 1, *keylen); 15831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtout: 15851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* return new buffer */ 15861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(buf); 15871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return ret; 15881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 15891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid radius_free_class(struct radius_class_data *c) 15928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 15938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 15948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (c == NULL) 15958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 15968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < c->count; i++) 15978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(c->attr[i].data); 15988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(c->attr); 15998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt c->attr = NULL; 16008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt c->count = 0; 16018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 16028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_copy_class(struct radius_class_data *dst, 16058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct radius_class_data *src) 16068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 16078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 16088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (src->attr == NULL) 16108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 16118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 161261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt dst->attr = os_calloc(src->count, sizeof(struct radius_attr_data)); 16138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (dst->attr == NULL) 16148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 16158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dst->count = 0; 16178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < src->count; i++) { 16198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dst->attr[i].data = os_malloc(src->attr[i].len); 16208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (dst->attr[i].data == NULL) 16218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 16228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dst->count++; 16238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(dst->attr[i].data, src->attr[i].data, 16248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt src->attr[i].len); 16258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dst->attr[i].len = src->attr[i].len; 16268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 16278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 16298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 163004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 163104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 163204949598a23f501be6eec21697465fd46a28840aDmitry Shmidtu8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs) 163304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 163404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t i, j; 163504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_attr_hdr *attr; 163604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 163704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 163804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attr = radius_get_attr_hdr(msg, i); 163904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 164004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (j = 0; attrs[j]; j++) { 164104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (attr->type == attrs[j]) 164204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 164304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 164404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 164504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (attrs[j] == 0) 164604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return attr->type; /* unlisted attr */ 164704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 164804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 164904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 0; 165004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 1651