radius.c revision d5e4923d04122f81300fa68fb07d64ede28fd44d
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * RADIUS message processing 304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * Copyright (c) 2002-2009, 2011-2012, 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 }, 23404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt { RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 } 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0])) 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct radius_attr_type *radius_get_attr_type(u8 type) 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < RADIUS_ATTRS; i++) { 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (type == radius_attrs[i].type) 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return &radius_attrs[i]; 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void print_char(char c) 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (c >= 32 && c < 127) 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("%c", c); 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("<%02x>", c); 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void radius_msg_dump_attr(struct radius_attr_hdr *hdr) 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_type *attr; 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i, len; 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned char *pos; 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_type(hdr->type); 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" Attribute %d (%s) length=%d\n", 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->type, attr ? attr->name : "?Unknown?", hdr->length); 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 27261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr)) 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = hdr->length - sizeof(struct radius_attr_hdr); 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (unsigned char *) (hdr + 1); 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (attr->data_type) { 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_TEXT: 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" Value: '"); 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < len; i++) 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt print_char(pos[i]); 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("'\n"); 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_IP: 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 4) { 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct in_addr addr; 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(&addr, pos, 4); 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" Value: %s\n", inet_ntoa(addr)); 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" Invalid IP address length %d\n", len); 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IPV6 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_IPV6: 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 16) { 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char buf[128]; 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const char *atxt; 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct in6_addr *addr = (struct in6_addr *) pos; 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf)); 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" Value: %s\n", atxt ? atxt : "?"); 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" Invalid IPv6 address length %d\n", len); 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IPV6 */ 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_HEXDUMP: 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_UNDIST: 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" Value:"); 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < len; i++) 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" %02x", pos[i]); 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("\n"); 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_INT32: 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 4) 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" Value: %u\n", WPA_GET_BE32(pos)); 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" Invalid INT32 length %d\n", len); 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid radius_msg_dump(struct radius_msg *msg) 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n", 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr->code, radius_code_string(msg->hdr->code), 33561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg->hdr->identifier, be_to_host16(msg->hdr->length)); 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_dump_attr(attr); 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_finish(struct radius_msg *msg, const u8 *secret, 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len) 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (secret) { 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 auth[MD5_MAC_LEN]; 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(auth, 0, MD5_MAC_LEN); 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_msg_add_attr(msg, 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt auth, MD5_MAC_LEN); 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Could not add " 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Message-Authenticator"); 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 36061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_len(msg->buf), (u8 *) (attr + 1)); 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 36461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_len(msg->buf) > 0xffff) { 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_len(msg->buf)); 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len, const u8 *req_authenticator) 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 auth[MD5_MAC_LEN]; 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[4]; 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len[4]; 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(auth, 0, MD5_MAC_LEN); 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt auth, MD5_MAC_LEN); 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("WARNING: Could not add Message-Authenticator\n"); 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 39061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(msg->hdr->authenticator, req_authenticator, 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(msg->hdr->authenticator)); 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_len(msg->buf), (u8 *) (attr + 1)); 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = (u8 *) msg->hdr; 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = 1 + 1 + 2; 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = req_authenticator; 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = MD5_MAC_LEN; 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[3] = secret; 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[3] = secret_len; 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(4, addr, len, msg->hdr->authenticator); 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_len(msg->buf) > 0xffff) { 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_len(msg->buf)); 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 41604949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret, 41704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t secret_len, 41804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const struct radius_hdr *req_hdr) 41904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 42004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *addr[2]; 42104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t len[2]; 42204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 auth[MD5_MAC_LEN]; 42304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_attr_hdr *attr; 42404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 42504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(auth, 0, MD5_MAC_LEN); 42604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 42704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt auth, MD5_MAC_LEN); 42804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (attr == NULL) { 42904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_WARNING, "Could not add Message-Authenticator"); 43004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return -1; 43104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 43204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 43361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 43404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16); 43504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 43604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_len(msg->buf), (u8 *) (attr + 1)); 43704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 43804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 43904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[0] = wpabuf_head_u8(msg->buf); 44004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[0] = wpabuf_len(msg->buf); 44104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[1] = secret; 44204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[1] = secret_len; 44304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0) 44404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return -1; 44504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 44604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (wpabuf_len(msg->buf) > 0xffff) { 44704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 44804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (unsigned long) wpabuf_len(msg->buf)); 44904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return -1; 45004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 45104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 0; 45204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 45304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 45404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret, 4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len) 4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[2]; 4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len[2]; 4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 46161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN); 4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = wpabuf_head(msg->buf); 4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = wpabuf_len(msg->buf); 4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = secret; 4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = secret_len; 4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(2, addr, len, msg->hdr->authenticator); 4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_len(msg->buf) > 0xffff) { 4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)", 4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_len(msg->buf)); 4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 47604949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret, 47704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t secret_len) 47804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 47904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *addr[4]; 48004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t len[4]; 48104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 zero[MD5_MAC_LEN]; 48204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 hash[MD5_MAC_LEN]; 48304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 48404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(zero, 0, sizeof(zero)); 48504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[0] = (u8 *) msg->hdr; 48604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN; 48704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[1] = zero; 48804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[1] = MD5_MAC_LEN; 48904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[2] = (u8 *) (msg->hdr + 1); 49004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 49104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[3] = secret; 49204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[3] = secret_len; 49304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt md5_vector(4, addr, len, hash); 49404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0; 49504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 49604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 49704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 49804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret, 49904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t secret_len) 50004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 50104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const u8 *addr[4]; 50204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t len[4]; 50304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 zero[MD5_MAC_LEN]; 50404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 hash[MD5_MAC_LEN]; 50504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN]; 50604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 orig_authenticator[16]; 50704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 50804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_attr_hdr *attr = NULL, *tmp; 50904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t i; 51004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 51104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(zero, 0, sizeof(zero)); 51204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[0] = (u8 *) msg->hdr; 51304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN; 51404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[1] = zero; 51504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[1] = MD5_MAC_LEN; 51604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[2] = (u8 *) (msg->hdr + 1); 51704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 51804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr[3] = secret; 51904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len[3] = secret_len; 52004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt md5_vector(4, addr, len, hash); 52104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0) 52204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 1; 52304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 52404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 52504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tmp = radius_get_attr_hdr(msg, i); 52604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) { 52704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (attr != NULL) { 52804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_WARNING, "Multiple " 52904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Message-Authenticator attributes " 53004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "in RADIUS message"); 53104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 1; 53204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 53304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attr = tmp; 53404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 53504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 53604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 53704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (attr == NULL) { 53804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* Message-Authenticator is MAY; not required */ 53904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 0; 54004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 54104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 54204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(orig, attr + 1, MD5_MAC_LEN); 54304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(attr + 1, 0, MD5_MAC_LEN); 54404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(orig_authenticator, msg->hdr->authenticator, 54504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sizeof(orig_authenticator)); 54604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(msg->hdr->authenticator, 0, 54704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sizeof(msg->hdr->authenticator)); 54804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 54904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_len(msg->buf), auth); 55004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(attr + 1, orig, MD5_MAC_LEN); 55104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(msg->hdr->authenticator, orig_authenticator, 55204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sizeof(orig_authenticator)); 55304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 55404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return os_memcmp(orig, auth, MD5_MAC_LEN) != 0; 55504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 55604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 55704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int radius_msg_add_attr_to_array(struct radius_msg *msg, 5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr) 5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg->attr_used >= msg->attr_size) { 5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t *nattr_pos; 5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int nlen = msg->attr_size * 2; 5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 56561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt nattr_pos = os_realloc_array(msg->attr_pos, nlen, 56661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt sizeof(*msg->attr_pos)); 5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (nattr_pos == NULL) 5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->attr_pos = nattr_pos; 5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->attr_size = nlen; 5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->attr_pos[msg->attr_used++] = 5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned char *) attr - wpabuf_head_u8(msg->buf); 5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, 5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *data, size_t data_len) 5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t buf_needed; 5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data_len > RADIUS_MAX_ATTR_LEN) { 5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("radius_msg_add_attr: too long attribute (%lu bytes)\n", 5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) data_len); 5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf_needed = sizeof(*attr) + data_len; 5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_tailroom(msg->buf) < buf_needed) { 5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* allocate more space for message buffer */ 5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_resize(&msg->buf, buf_needed) < 0) 5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr = wpabuf_mhead(msg->buf); 6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr)); 6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr->type = type; 6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr->length = sizeof(*attr) + data_len; 6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(msg->buf, data, data_len); 6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (radius_msg_add_attr_to_array(msg, attr)) 6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return attr; 6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * radius_msg_parse - Parse a RADIUS message 6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data: RADIUS message to be parsed 6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @len: Length of data buffer in octets 6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Parsed RADIUS message or %NULL on failure 6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This parses a RADIUS message and makes a copy of its data. The caller is 6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * responsible for freeing the returned data with radius_msg_free(). 6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_msg * radius_msg_parse(const u8 *data, size_t len) 6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_msg *msg; 6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_hdr *hdr; 6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t msg_len; 6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned char *pos, *end; 6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data == NULL || len < sizeof(*hdr)) 6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr = (struct radius_hdr *) data; 6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 63661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt msg_len = be_to_host16(hdr->length); 6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg_len < sizeof(*hdr) || msg_len > len) { 6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "RADIUS: Invalid message length"); 6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg_len < len) { 6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after " 6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "RADIUS message", (unsigned long) len - msg_len); 6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg = os_zalloc(sizeof(*msg)); 6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->buf = wpabuf_alloc_copy(data, msg_len); 6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg->buf == NULL || radius_msg_initialize(msg)) { 6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_free(msg); 6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr = wpabuf_mhead(msg->buf); 6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* parse attributes */ 6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr); 6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf); 6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (pos < end) { 6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((size_t) (end - pos) < sizeof(*attr)) 6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = (struct radius_attr_hdr *) pos; 6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos + attr->length > end || attr->length < sizeof(*attr)) 6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: check that attr->length is suitable for attr->type */ 6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (radius_msg_add_attr_to_array(msg, attr)) 6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += attr->length; 6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return msg; 6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt fail: 6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_free(msg); 6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len) 6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos = data; 6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t left = data_len; 6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (left > 0) { 6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int len; 6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (left > RADIUS_MAX_ATTR_LEN) 6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = RADIUS_MAX_ATTR_LEN; 6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = left; 6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE, 6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos, len)) 7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += len; 7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left -= len; 7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 71061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstruct wpabuf * radius_msg_get_eap(struct radius_msg *msg) 7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 71261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *eap; 7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len, i; 7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = 0; 7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_hdr(msg, i); 72261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (attr->type == RADIUS_ATTR_EAP_MESSAGE && 72361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt attr->length > sizeof(struct radius_attr_hdr)) 7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len += attr->length - sizeof(struct radius_attr_hdr); 7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 0) 7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 73061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt eap = wpabuf_alloc(len); 7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (eap == NULL) 7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_hdr(msg, i); 73661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (attr->type == RADIUS_ATTR_EAP_MESSAGE && 73761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt attr->length > sizeof(struct radius_attr_hdr)) { 7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int flen = attr->length - sizeof(*attr); 73961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(eap, attr + 1, flen); 7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap; 7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, 7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len, const u8 *req_auth) 7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN]; 7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 orig_authenticator[16]; 7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = NULL, *tmp; 7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp = radius_get_attr_hdr(msg, i); 7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) { 7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr != NULL) { 7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("Multiple Message-Authenticator " 7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "attributes in RADIUS message\n"); 7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = tmp; 7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("No Message-Authenticator attribute found\n"); 7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(orig, attr + 1, MD5_MAC_LEN); 7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(attr + 1, 0, MD5_MAC_LEN); 7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (req_auth) { 7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(orig_authenticator, msg->hdr->authenticator, 7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(orig_authenticator)); 7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(msg->hdr->authenticator, req_auth, 7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(msg->hdr->authenticator)); 7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_len(msg->buf), auth); 7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(attr + 1, orig, MD5_MAC_LEN); 7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (req_auth) { 7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(msg->hdr->authenticator, orig_authenticator, 7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(orig_authenticator)); 7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) { 7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("Invalid Message-Authenticator!\n"); 7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_verify(struct radius_msg *msg, const u8 *secret, 7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len, struct radius_msg *sent_msg, int auth) 7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[4]; 8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len[4]; 8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[MD5_MAC_LEN]; 8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sent_msg == NULL) { 8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("No matching Access-Request message found\n"); 8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (auth && 8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_verify_msg_auth(msg, secret, secret_len, 8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sent_msg->hdr->authenticator)) { 8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = (u8 *) msg->hdr; 8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = 1 + 1 + 2; 8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = sent_msg->hdr->authenticator; 8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = MD5_MAC_LEN; 8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); 8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[3] = secret; 8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[3] = secret_len; 8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(4, addr, len, hash); 8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) { 8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("Response Authenticator invalid!\n"); 8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src, 8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 type) 8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int count = 0; 8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < src->attr_used; i++) { 8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_hdr(src, i); 84361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (attr->type == type && attr->length >= sizeof(*attr)) { 8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1), 8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr->length - sizeof(*attr))) 8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count++; 8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return count; 8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Create Request Authenticator. The value should be unique over the lifetime 8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * of the shared secret between authenticator and authentication server. 8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Use one-way MD5 hash calculated from current timestamp and some data given 8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * by the caller. */ 8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid radius_msg_make_authenticator(struct radius_msg *msg, 8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *data, size_t len) 8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct os_time tv; 8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt long int l; 8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[3]; 8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t elen[3]; 8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_get_time(&tv); 8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt l = os_random(); 8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = (u8 *) &tv; 8708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[0] = sizeof(tv); 8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = data; 8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[1] = len; 8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = (u8 *) &l; 8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[2] = sizeof(l); 8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(3, addr, elen, msg->hdr->authenticator); 8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message. 8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns the Attribute payload and sets alen to indicate the length of the 8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * payload if a vendor attribute with subtype is found, otherwise returns NULL. 8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The returned payload is allocated with os_malloc() and caller must free it 8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * by calling os_free(). 8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor, 8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 subtype, size_t *alen) 8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *data, *pos; 8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i, len; 8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t left; 8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u32 vendor_id; 8988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_vendor *vhdr; 8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 90061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC || 90161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt attr->length < sizeof(*attr)) 9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left = attr->length - sizeof(*attr); 9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (left < 4) 9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (u8 *) (attr + 1); 9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(&vendor_id, pos, 4); 9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 4; 9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left -= 4; 9138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ntohl(vendor_id) != vendor) 9158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 9168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (left >= sizeof(*vhdr)) { 9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr = (struct radius_attr_vendor *) pos; 9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (vhdr->vendor_length > left || 9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_length < sizeof(*vhdr)) { 9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left = 0; 9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (vhdr->vendor_type != subtype) { 9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += vhdr->vendor_length; 9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left -= vhdr->vendor_length; 9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 9288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = vhdr->vendor_length - sizeof(*vhdr); 9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data = os_malloc(len); 9328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data == NULL) 9338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 9348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(data, pos + sizeof(*vhdr), len); 9358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (alen) 9368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *alen = len; 9378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return data; 9388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 9428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u8 * decrypt_ms_key(const u8 *key, size_t len, 9468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *req_authenticator, 9478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len, size_t *reslen) 9488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *plain, *ppos, *res; 9508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos; 9518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t left, plen; 9528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[MD5_MAC_LEN]; 9538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i, first = 1; 9548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[3]; 9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t elen[3]; 9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* key: 16-bit salt followed by encrypted key info */ 9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len < 2 + 16) 9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = key + 2; 9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left = len - 2; 9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (left % 16) { 9658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("Invalid ms key len %lu\n", (unsigned long) left); 9668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = left; 9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ppos = plain = os_malloc(plen); 9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (plain == NULL) 9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plain[0] = 0; 9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (left > 0) { 9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* b(1) = MD5(Secret + Request-Authenticator + Salt) 9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ 9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = secret; 9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[0] = secret_len; 9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (first) { 9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = req_authenticator; 9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[1] = MD5_MAC_LEN; 9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = key; 9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[2] = 2; /* Salt */ 9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = pos - MD5_MAC_LEN; 9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[1] = MD5_MAC_LEN; 9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(first ? 3 : 2, addr, elen, hash); 9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt first = 0; 9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < MD5_MAC_LEN; i++) 9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *ppos++ = *pos++ ^ hash[i]; 9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left -= MD5_MAC_LEN; 9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (plain[0] == 0 || plain[0] > plen - 1) { 9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("Failed to decrypt MPPE key\n"); 10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(plain); 10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = os_malloc(plain[0]); 10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (res == NULL) { 10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(plain); 10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(res, plain + 1, plain[0]); 10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (reslen) 10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *reslen = plain[0]; 10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(plain); 10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return res; 10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt, 10188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *req_authenticator, 10198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len, 10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *ebuf, size_t *elen) 10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i, len, first = 1; 10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[MD5_MAC_LEN], saltbuf[2], *pos; 10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[3]; 10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t _len[3]; 10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(saltbuf, salt); 10288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = 1 + key_len; 10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len & 0x0f) { 10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = (len & 0xf0) + 16; 10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(ebuf, 0, len); 10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ebuf[0] = key_len; 10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(ebuf + 1, key, key_len); 10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *elen = len; 10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = ebuf; 10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (len > 0) { 10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* b(1) = MD5(Secret + Request-Authenticator + Salt) 10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ 10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = secret; 10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt _len[0] = secret_len; 10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (first) { 10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = req_authenticator; 10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt _len[1] = MD5_MAC_LEN; 10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = saltbuf; 10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt _len[2] = sizeof(saltbuf); 10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = pos - MD5_MAC_LEN; 10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt _len[1] = MD5_MAC_LEN; 10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(first ? 3 : 2, addr, _len, hash); 10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt first = 0; 10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < MD5_MAC_LEN; i++) 10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ ^= hash[i]; 10598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len -= MD5_MAC_LEN; 10618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_ms_mppe_keys * 10668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtradius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg, 10678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len) 10688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 10698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *key; 10708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t keylen; 10718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_ms_mppe_keys *keys; 10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL || sent_msg == NULL) 10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys = os_zalloc(sizeof(*keys)); 10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (keys == NULL) 10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, 10818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY, 10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keylen); 10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (key) { 10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->send = decrypt_ms_key(key, keylen, 10858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sent_msg->hdr->authenticator, 10868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret, secret_len, 10878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keys->send_len); 10888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(key); 10898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, 10928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY, 10938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keylen); 10948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (key) { 10958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->recv = decrypt_ms_key(key, keylen, 10968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sent_msg->hdr->authenticator, 10978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret, secret_len, 10988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keys->recv_len); 10998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(key); 11008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return keys; 11038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 11048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_ms_mppe_keys * 11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtradius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg, 11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len) 11098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 11108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *key; 11118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t keylen; 11128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_ms_mppe_keys *keys; 11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL || sent_msg == NULL) 11158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys = os_zalloc(sizeof(*keys)); 11188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (keys == NULL) 11198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO, 11228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_CISCO_AV_PAIR, &keylen); 11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (key && keylen == 51 && 11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcmp(key, "leap:session-key=", 17) == 0) { 11258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->recv = decrypt_ms_key(key + 17, keylen - 17, 11268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sent_msg->hdr->authenticator, 11278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret, secret_len, 11288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keys->recv_len); 11298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(key); 11318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return keys; 11338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 11348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_add_mppe_keys(struct radius_msg *msg, 11378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *req_authenticator, 11388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len, 11398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *send_key, size_t send_key_len, 11408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *recv_key, size_t recv_key_len) 11418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 11428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 11438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT); 11448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *buf; 11458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_vendor *vhdr; 11468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *pos; 11478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t elen; 11488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int hlen; 11498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 salt; 11508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2; 11528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* MS-MPPE-Send-Key */ 11548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf = os_malloc(hlen + send_key_len + 16); 11558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (buf == NULL) { 11568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 11578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = buf; 11598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, &vendor_id, sizeof(vendor_id)); 11608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += sizeof(vendor_id); 11618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr = (struct radius_attr_vendor *) pos; 11628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY; 11638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (u8 *) (vhdr + 1); 11648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt salt = os_random() | 0x8000; 11658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(pos, salt); 11668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 2; 11678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret, 11688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret_len, pos, &elen); 11698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_length = hlen + elen - sizeof(vendor_id); 11708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 11728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf, hlen + elen); 11738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(buf); 11748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 11758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 11768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* MS-MPPE-Recv-Key */ 11798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf = os_malloc(hlen + send_key_len + 16); 11808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (buf == NULL) { 11818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 11828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = buf; 11848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, &vendor_id, sizeof(vendor_id)); 11858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += sizeof(vendor_id); 11868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr = (struct radius_attr_vendor *) pos; 11878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY; 11888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (u8 *) (vhdr + 1); 11898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt salt ^= 1; 11908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(pos, salt); 11918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 2; 11928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret, 11938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret_len, pos, &elen); 11948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_length = hlen + elen - sizeof(vendor_id); 11958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 11978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf, hlen + elen); 11988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(buf); 11998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 12008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 12018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 12048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 12058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Add User-Password attribute to a RADIUS message and encrypt it as specified 12088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * in RFC 2865, Chap. 5.2 */ 12098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_attr_hdr * 12108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtradius_msg_add_attr_user_password(struct radius_msg *msg, 12118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *data, size_t data_len, 12128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len) 12138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 12148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 buf[128]; 12151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t padlen, i, buf_len, pos; 12168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[2]; 12178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len[2]; 12188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[16]; 12198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data_len > 128) 12218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 12228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(buf, data, data_len); 12248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf_len = data_len; 12258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt padlen = data_len % 16; 12271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (padlen && data_len < sizeof(buf)) { 12288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt padlen = 16 - padlen; 12298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(buf + data_len, 0, padlen); 12308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf_len += padlen; 12318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = secret; 12348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = secret_len; 12358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = msg->hdr->authenticator; 12368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = 16; 12378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(2, addr, len, hash); 12388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 12408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf[i] ^= hash[i]; 12418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = 16; 12428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (pos < buf_len) { 12448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = secret; 12458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = secret_len; 12468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = &buf[pos - 16]; 12478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = 16; 12488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(2, addr, len, hash); 12498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 12518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf[pos + i] ^= hash[i]; 12528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 16; 12548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD, 12578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf, buf_len); 12588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 12598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len) 12628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 12638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = NULL, *tmp; 12648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i, dlen; 12658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 12678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp = radius_get_attr_hdr(msg, i); 12688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tmp->type == type) { 12698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = tmp; 12708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 12718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 127461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!attr || attr->length < sizeof(*attr)) 12758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 12768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dlen = attr->length - sizeof(*attr); 12788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (buf) 12798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(buf, (attr + 1), dlen > len ? len : dlen); 12808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return dlen; 12818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 12828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf, 12858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t *len, const u8 *start) 12868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 12878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 12888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = NULL, *tmp; 12898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 12918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp = radius_get_attr_hdr(msg, i); 12928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tmp->type == type && 12938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (start == NULL || (u8 *) tmp > start)) { 12948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = tmp; 12958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 12968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 129961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!attr || attr->length < sizeof(*attr)) 13008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 13018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *buf = (u8 *) (attr + 1); 13038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *len = attr->length - sizeof(*attr); 13048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 13058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 13068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len) 13098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 13108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 13118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int count; 13128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (count = 0, i = 0; i < msg->attr_used; i++) { 13148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 13158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->type == type && 13168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr->length >= sizeof(struct radius_attr_hdr) + min_len) 13178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count++; 13188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return count; 13218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 13228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_tunnel_attrs { 13258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int tag_used; 13268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int type; /* Tunnel-Type */ 13278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int medium_type; /* Tunnel-Medium-Type */ 13288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int vlanid; 13298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 13308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 13338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information 13348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @msg: RADIUS message 13358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: VLAN ID for the first tunnel configuration of -1 if none is found 13368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 13378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_get_vlanid(struct radius_msg *msg) 13388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 13398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun; 13408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 13418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = NULL; 13428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *data; 13438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char buf[10]; 13448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t dlen; 13458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(&tunnel, 0, sizeof(tunnel)); 13478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 13498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_hdr(msg, i); 135061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (attr->length < sizeof(*attr)) 135161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 13528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data = (const u8 *) (attr + 1); 13538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dlen = attr->length - sizeof(*attr); 13548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->length < 3) 13558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 13568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data[0] >= RADIUS_TUNNEL_TAGS) 13578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun = &tunnel[0]; 13588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 13598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun = &tunnel[data[0]]; 13608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (attr->type) { 13628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_TUNNEL_TYPE: 13638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->length != 6) 13648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 13658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->tag_used++; 13668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->type = WPA_GET_BE24(data + 1); 13678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 13688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE: 13698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->length != 6) 13708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 13718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->tag_used++; 13728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->medium_type = WPA_GET_BE24(data + 1); 13738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 13748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID: 13758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data[0] < RADIUS_TUNNEL_TAGS) { 13768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data++; 13778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dlen--; 13788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (dlen >= sizeof(buf)) 13808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 13818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(buf, data, dlen); 13828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf[dlen] = '\0'; 13838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->tag_used++; 13848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->vlanid = atoi(buf); 13858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 13868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) { 13908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun = &tunnel[i]; 13918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tun->tag_used && 13928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->type == RADIUS_TUNNEL_TYPE_VLAN && 13938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 && 13948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->vlanid > 0) 13958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return tun->vlanid; 13968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 13998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 14008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/** 14031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password 14041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @msg: Received RADIUS message 14051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @keylen: Length of returned password 14061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @secret: RADIUS shared secret 14071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @secret_len: Length of secret 14081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @sent_msg: Sent RADIUS message 1409d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt * @n: Number of password attribute to return (starting with 0) 1410d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt * Returns: Pointer to n-th password (free with os_free) or %NULL 14111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */ 14121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtchar * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen, 14131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *secret, size_t secret_len, 1414d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt struct radius_msg *sent_msg, size_t n) 14151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 14161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 *buf = NULL; 14171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t buflen; 14181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *salt; 14191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 *str; 14201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *addr[3]; 14211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t len[3]; 14221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 hash[16]; 14231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 *pos; 1424d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt size_t i, j = 0; 14251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct radius_attr_hdr *attr; 14261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *data; 14271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t dlen; 14281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *fdata = NULL; /* points to found item */ 14291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t fdlen = -1; 14301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt char *ret = NULL; 14311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1432d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt /* find n-th valid Tunnel-Password attribute */ 14331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 14341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt attr = radius_get_attr_hdr(msg, i); 14351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (attr == NULL || 14361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) { 14371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt continue; 14381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 14391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (attr->length <= 5) 14401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt continue; 14411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt data = (const u8 *) (attr + 1); 14421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt dlen = attr->length - sizeof(*attr); 14431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (dlen <= 3 || dlen % 16 != 3) 14441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt continue; 1445d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt j++; 1446d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt if (j <= n) 14471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt continue; 14481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 14491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt fdata = data; 14501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt fdlen = dlen; 1451d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt break; 14521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 14531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (fdata == NULL) 14541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 14551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 14561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* alloc writable memory for decryption */ 14571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt buf = os_malloc(fdlen); 14581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (buf == NULL) 14591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 14601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_memcpy(buf, fdata, fdlen); 14611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt buflen = fdlen; 14621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 14631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* init pointers */ 14641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt salt = buf + 1; 14651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt str = buf + 3; 14661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 14671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* decrypt blocks */ 14681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos = buf + buflen - 16; /* last block */ 14691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt while (pos >= str + 16) { /* all but the first block */ 14701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[0] = secret; 14711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[0] = secret_len; 14721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[1] = pos - 16; 14731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[1] = 16; 14741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt md5_vector(2, addr, len, hash); 14751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 14761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt for (i = 0; i < 16; i++) 14771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos[i] ^= hash[i]; 14781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 14791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos -= 16; 14801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 14811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 14821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* decrypt first block */ 14831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (str != pos) 14841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 14851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[0] = secret; 14861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[0] = secret_len; 14871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[1] = sent_msg->hdr->authenticator; 14881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[1] = 16; 14891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[2] = salt; 14901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[2] = 2; 14911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt md5_vector(3, addr, len, hash); 14921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 14931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt for (i = 0; i < 16; i++) 14941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos[i] ^= hash[i]; 14951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 14961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* derive plaintext length from first subfield */ 14971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt *keylen = (unsigned char) str[0]; 14981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if ((u8 *) (str + *keylen) >= (u8 *) (buf + buflen)) { 14991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* decryption error - invalid key length */ 15001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 15011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 15021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (*keylen == 0) { 15031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* empty password */ 15041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 15051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 15061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* copy passphrase into new buffer */ 15081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt ret = os_malloc(*keylen); 15091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (ret) 15101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_memcpy(ret, str + 1, *keylen); 15111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtout: 15131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* return new buffer */ 15141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(buf); 15151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return ret; 15161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 15171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 15198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid radius_free_class(struct radius_class_data *c) 15208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 15218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 15228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (c == NULL) 15238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 15248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < c->count; i++) 15258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(c->attr[i].data); 15268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(c->attr); 15278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt c->attr = NULL; 15288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt c->count = 0; 15298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 15308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 15318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 15328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_copy_class(struct radius_class_data *dst, 15338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct radius_class_data *src) 15348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 15358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 15368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 15378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (src->attr == NULL) 15388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 15398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 154061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt dst->attr = os_calloc(src->count, sizeof(struct radius_attr_data)); 15418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (dst->attr == NULL) 15428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 15438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 15448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dst->count = 0; 15458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 15468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < src->count; i++) { 15478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dst->attr[i].data = os_malloc(src->attr[i].len); 15488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (dst->attr[i].data == NULL) 15498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 15508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dst->count++; 15518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(dst->attr[i].data, src->attr[i].data, 15528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt src->attr[i].len); 15538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dst->attr[i].len = src->attr[i].len; 15548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 15558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 15568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 15578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 155804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 155904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 156004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtu8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs) 156104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 156204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t i, j; 156304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_attr_hdr *attr; 156404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 156504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 156604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attr = radius_get_attr_hdr(msg, i); 156704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 156804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (j = 0; attrs[j]; j++) { 156904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (attr->type == attrs[j]) 157004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 157104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 157204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 157304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (attrs[j] == 0) 157404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return attr->type; /* unlisted attr */ 157504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 157604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 157704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 0; 157804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 1579