radius.c revision 1f69aa52ea2e0a73ac502565df8c666ee49cab6a
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * RADIUS message processing 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This program is free software; you can redistribute it and/or modify 68d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * it under the terms of the GNU General Public License version 2 as 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * published by the Free Software Foundation. 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * license. 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * See README and COPYING for more details. 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/includes.h" 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/common.h" 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/wpabuf.h" 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/md5.h" 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/crypto.h" 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "radius.h" 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * struct radius_msg - RADIUS message structure for new and parsed messages 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_msg { 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /** 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * buf - Allocated buffer for RADIUS message 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *buf; 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /** 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hdr - Pointer to the RADIUS header in buf 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_hdr *hdr; 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /** 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * attr_pos - Array of indexes to attributes 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The values are number of bytes from buf to the beginning of 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * struct radius_attr_hdr. 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t *attr_pos; 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /** 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * attr_size - Total size of the attribute pointer array 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t attr_size; 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /** 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * attr_used - Total number of attributes in the array 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t attr_used; 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg) 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return msg->hdr; 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * radius_msg_get_buf(struct radius_msg *msg) 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return msg->buf; 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct radius_attr_hdr * 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtradius_get_attr_hdr(struct radius_msg *msg, int idx) 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return (struct radius_attr_hdr *) 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (wpabuf_mhead_u8(msg->buf) + msg->attr_pos[idx]); 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier) 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr->code = code; 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr->identifier = identifier; 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int radius_msg_initialize(struct radius_msg *msg) 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->attr_pos = 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_zalloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attr_pos)); 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg->attr_pos == NULL) 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT; 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->attr_used = 0; 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * radius_msg_new - Create a new RADIUS message 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @code: Code for RADIUS header 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @identifier: Identifier for RADIUS header 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Context for RADIUS message or %NULL on failure 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The caller is responsible for freeing the returned data with 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * radius_msg_free(). 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_msg * radius_msg_new(u8 code, u8 identifier) 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_msg *msg; 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg = os_zalloc(sizeof(*msg)); 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->buf = wpabuf_alloc(RADIUS_DEFAULT_MSG_SIZE); 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg->buf == NULL || radius_msg_initialize(msg)) { 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_free(msg); 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr = wpabuf_put(msg->buf, sizeof(struct radius_hdr)); 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_set_hdr(msg, code, identifier); 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return msg; 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * radius_msg_free - Free a RADIUS message 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @msg: RADIUS message from radius_msg_new() or radius_msg_parse() 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid radius_msg_free(struct radius_msg *msg) 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(msg->buf); 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(msg->attr_pos); 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(msg); 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char *radius_code_string(u8 code) 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (code) { 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request"; 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept"; 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject"; 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request"; 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response"; 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge"; 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_CODE_STATUS_SERVER: return "Status-Server"; 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_CODE_STATUS_CLIENT: return "Status-Client"; 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_CODE_RESERVED: return "Reserved"; 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 }, 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargable-User-Identity", 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_TEXT }, 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 }, 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0])) 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct radius_attr_type *radius_get_attr_type(u8 type) 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < RADIUS_ATTRS; i++) { 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (type == radius_attrs[i].type) 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return &radius_attrs[i]; 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void print_char(char c) 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (c >= 32 && c < 127) 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("%c", c); 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("<%02x>", c); 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void radius_msg_dump_attr(struct radius_attr_hdr *hdr) 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_type *attr; 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i, len; 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned char *pos; 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_type(hdr->type); 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" Attribute %d (%s) length=%d\n", 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->type, attr ? attr->name : "?Unknown?", hdr->length); 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = hdr->length - sizeof(struct radius_attr_hdr); 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (unsigned char *) (hdr + 1); 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (attr->data_type) { 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_TEXT: 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" Value: '"); 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < len; i++) 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt print_char(pos[i]); 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("'\n"); 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_IP: 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 4) { 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct in_addr addr; 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(&addr, pos, 4); 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" Value: %s\n", inet_ntoa(addr)); 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" Invalid IP address length %d\n", len); 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IPV6 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_IPV6: 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 16) { 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char buf[128]; 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const char *atxt; 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct in6_addr *addr = (struct in6_addr *) pos; 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf)); 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" Value: %s\n", atxt ? atxt : "?"); 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" Invalid IPv6 address length %d\n", len); 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IPV6 */ 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_HEXDUMP: 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_UNDIST: 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" Value:"); 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < len; i++) 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" %02x", pos[i]); 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("\n"); 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_INT32: 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 4) 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" Value: %u\n", WPA_GET_BE32(pos)); 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf(" Invalid INT32 length %d\n", len); 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid radius_msg_dump(struct radius_msg *msg) 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n", 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr->code, radius_code_string(msg->hdr->code), 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr->identifier, ntohs(msg->hdr->length)); 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_dump_attr(attr); 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_finish(struct radius_msg *msg, const u8 *secret, 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len) 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (secret) { 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 auth[MD5_MAC_LEN]; 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(auth, 0, MD5_MAC_LEN); 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_msg_add_attr(msg, 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt auth, MD5_MAC_LEN); 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Could not add " 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Message-Authenticator"); 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr->length = htons(wpabuf_len(msg->buf)); 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_len(msg->buf), (u8 *) (attr + 1)); 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr->length = htons(wpabuf_len(msg->buf)); 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_len(msg->buf) > 0xffff) { 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_len(msg->buf)); 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len, const u8 *req_authenticator) 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 auth[MD5_MAC_LEN]; 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[4]; 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len[4]; 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(auth, 0, MD5_MAC_LEN); 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt auth, MD5_MAC_LEN); 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("WARNING: Could not add Message-Authenticator\n"); 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr->length = htons(wpabuf_len(msg->buf)); 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(msg->hdr->authenticator, req_authenticator, 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(msg->hdr->authenticator)); 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_len(msg->buf), (u8 *) (attr + 1)); 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = (u8 *) msg->hdr; 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = 1 + 1 + 2; 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = req_authenticator; 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = MD5_MAC_LEN; 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[3] = secret; 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[3] = secret_len; 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(4, addr, len, msg->hdr->authenticator); 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_len(msg->buf) > 0xffff) { 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_len(msg->buf)); 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret, 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len) 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[2]; 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len[2]; 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr->length = htons(wpabuf_len(msg->buf)); 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN); 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = wpabuf_head(msg->buf); 4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = wpabuf_len(msg->buf); 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = secret; 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = secret_len; 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(2, addr, len, msg->hdr->authenticator); 4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_len(msg->buf) > 0xffff) { 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)", 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_len(msg->buf)); 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int radius_msg_add_attr_to_array(struct radius_msg *msg, 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr) 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg->attr_used >= msg->attr_size) { 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t *nattr_pos; 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int nlen = msg->attr_size * 2; 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nattr_pos = os_realloc(msg->attr_pos, 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nlen * sizeof(*msg->attr_pos)); 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (nattr_pos == NULL) 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->attr_pos = nattr_pos; 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->attr_size = nlen; 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->attr_pos[msg->attr_used++] = 4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned char *) attr - wpabuf_head_u8(msg->buf); 4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, 4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *data, size_t data_len) 4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t buf_needed; 4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data_len > RADIUS_MAX_ATTR_LEN) { 4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("radius_msg_add_attr: too long attribute (%lu bytes)\n", 4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) data_len); 4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf_needed = sizeof(*attr) + data_len; 4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_tailroom(msg->buf) < buf_needed) { 4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* allocate more space for message buffer */ 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_resize(&msg->buf, buf_needed) < 0) 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr = wpabuf_mhead(msg->buf); 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr)); 4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr->type = type; 4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr->length = sizeof(*attr) + data_len; 4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(msg->buf, data, data_len); 4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (radius_msg_add_attr_to_array(msg, attr)) 4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return attr; 4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * radius_msg_parse - Parse a RADIUS message 4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data: RADIUS message to be parsed 4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @len: Length of data buffer in octets 4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Parsed RADIUS message or %NULL on failure 4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This parses a RADIUS message and makes a copy of its data. The caller is 4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * responsible for freeing the returned data with radius_msg_free(). 5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_msg * radius_msg_parse(const u8 *data, size_t len) 5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_msg *msg; 5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_hdr *hdr; 5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t msg_len; 5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned char *pos, *end; 5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data == NULL || len < sizeof(*hdr)) 5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr = (struct radius_hdr *) data; 5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg_len = ntohs(hdr->length); 5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg_len < sizeof(*hdr) || msg_len > len) { 5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "RADIUS: Invalid message length"); 5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg_len < len) { 5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after " 5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "RADIUS message", (unsigned long) len - msg_len); 5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg = os_zalloc(sizeof(*msg)); 5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->buf = wpabuf_alloc_copy(data, msg_len); 5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg->buf == NULL || radius_msg_initialize(msg)) { 5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_free(msg); 5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg->hdr = wpabuf_mhead(msg->buf); 5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* parse attributes */ 5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr); 5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf); 5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (pos < end) { 5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((size_t) (end - pos) < sizeof(*attr)) 5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = (struct radius_attr_hdr *) pos; 5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos + attr->length > end || attr->length < sizeof(*attr)) 5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: check that attr->length is suitable for attr->type */ 5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (radius_msg_add_attr_to_array(msg, attr)) 5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += attr->length; 5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return msg; 5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt fail: 5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_free(msg); 5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len) 5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos = data; 5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t left = data_len; 5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (left > 0) { 5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int len; 5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (left > RADIUS_MAX_ATTR_LEN) 5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = RADIUS_MAX_ATTR_LEN; 5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = left; 5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE, 5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos, len)) 5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += len; 5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left -= len; 5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtu8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len) 5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *eap, *pos; 5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len, i; 5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = 0; 5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_hdr(msg, i); 6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->type == RADIUS_ATTR_EAP_MESSAGE) 6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len += attr->length - sizeof(struct radius_attr_hdr); 6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 0) 6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap = os_malloc(len); 6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (eap == NULL) 6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = eap; 6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_hdr(msg, i); 6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->type == RADIUS_ATTR_EAP_MESSAGE) { 6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int flen = attr->length - sizeof(*attr); 6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, attr + 1, flen); 6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += flen; 6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (eap_len) 6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *eap_len = len; 6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap; 6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, 6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len, const u8 *req_auth) 6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN]; 6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 orig_authenticator[16]; 6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = NULL, *tmp; 6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp = radius_get_attr_hdr(msg, i); 6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) { 6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr != NULL) { 6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("Multiple Message-Authenticator " 6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "attributes in RADIUS message\n"); 6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = tmp; 6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("No Message-Authenticator attribute found\n"); 6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(orig, attr + 1, MD5_MAC_LEN); 6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(attr + 1, 0, MD5_MAC_LEN); 6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (req_auth) { 6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(orig_authenticator, msg->hdr->authenticator, 6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(orig_authenticator)); 6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(msg->hdr->authenticator, req_auth, 6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(msg->hdr->authenticator)); 6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_len(msg->buf), auth); 6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(attr + 1, orig, MD5_MAC_LEN); 6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (req_auth) { 6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(msg->hdr->authenticator, orig_authenticator, 6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(orig_authenticator)); 6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) { 6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("Invalid Message-Authenticator!\n"); 6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_verify(struct radius_msg *msg, const u8 *secret, 6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t secret_len, struct radius_msg *sent_msg, int auth) 6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[4]; 6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len[4]; 6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[MD5_MAC_LEN]; 6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sent_msg == NULL) { 6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("No matching Access-Request message found\n"); 6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (auth && 6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt radius_msg_verify_msg_auth(msg, secret, secret_len, 6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sent_msg->hdr->authenticator)) { 6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = (u8 *) msg->hdr; 6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = 1 + 1 + 2; 6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = sent_msg->hdr->authenticator; 7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = MD5_MAC_LEN; 7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); 7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[3] = secret; 7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[3] = secret_len; 7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(4, addr, len, hash); 7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) { 7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("Response Authenticator invalid!\n"); 7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src, 7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 type) 7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int count = 0; 7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < src->attr_used; i++) { 7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_hdr(src, i); 7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->type == type) { 7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1), 7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr->length - sizeof(*attr))) 7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count++; 7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return count; 7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Create Request Authenticator. The value should be unique over the lifetime 7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * of the shared secret between authenticator and authentication server. 7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Use one-way MD5 hash calculated from current timestamp and some data given 7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * by the caller. */ 7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid radius_msg_make_authenticator(struct radius_msg *msg, 7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *data, size_t len) 7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct os_time tv; 7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt long int l; 7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[3]; 7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t elen[3]; 7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_get_time(&tv); 7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt l = os_random(); 7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = (u8 *) &tv; 7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[0] = sizeof(tv); 7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = data; 7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[1] = len; 7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = (u8 *) &l; 7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[2] = sizeof(l); 7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(3, addr, elen, msg->hdr->authenticator); 7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message. 7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns the Attribute payload and sets alen to indicate the length of the 7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * payload if a vendor attribute with subtype is found, otherwise returns NULL. 7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The returned payload is allocated with os_malloc() and caller must free it 7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * by calling os_free(). 7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor, 7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 subtype, size_t *alen) 7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *data, *pos; 7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i, len; 7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t left; 7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u32 vendor_id; 7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_vendor *vhdr; 7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC) 7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left = attr->length - sizeof(*attr); 7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (left < 4) 7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (u8 *) (attr + 1); 7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(&vendor_id, pos, 4); 7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 4; 7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left -= 4; 7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ntohl(vendor_id) != vendor) 7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (left >= sizeof(*vhdr)) { 7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr = (struct radius_attr_vendor *) pos; 7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (vhdr->vendor_length > left || 8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_length < sizeof(*vhdr)) { 8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left = 0; 8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (vhdr->vendor_type != subtype) { 8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += vhdr->vendor_length; 8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left -= vhdr->vendor_length; 8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = vhdr->vendor_length - sizeof(*vhdr); 8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data = os_malloc(len); 8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data == NULL) 8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(data, pos + sizeof(*vhdr), len); 8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (alen) 8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *alen = len; 8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return data; 8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u8 * decrypt_ms_key(const u8 *key, size_t len, 8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *req_authenticator, 8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len, size_t *reslen) 8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *plain, *ppos, *res; 8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos; 8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t left, plen; 8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[MD5_MAC_LEN]; 8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i, first = 1; 8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[3]; 8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t elen[3]; 8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* key: 16-bit salt followed by encrypted key info */ 8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len < 2 + 16) 8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = key + 2; 8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left = len - 2; 8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (left % 16) { 8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("Invalid ms key len %lu\n", (unsigned long) left); 8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = left; 8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ppos = plain = os_malloc(plen); 8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (plain == NULL) 8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plain[0] = 0; 8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (left > 0) { 8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* b(1) = MD5(Secret + Request-Authenticator + Salt) 8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ 8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = secret; 8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[0] = secret_len; 8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (first) { 8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = req_authenticator; 8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[1] = MD5_MAC_LEN; 8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = key; 8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[2] = 2; /* Salt */ 8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = pos - MD5_MAC_LEN; 8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[1] = MD5_MAC_LEN; 8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(first ? 3 : 2, addr, elen, hash); 8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt first = 0; 8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < MD5_MAC_LEN; i++) 8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *ppos++ = *pos++ ^ hash[i]; 8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left -= MD5_MAC_LEN; 8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (plain[0] == 0 || plain[0] > plen - 1) { 8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("Failed to decrypt MPPE key\n"); 8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(plain); 8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = os_malloc(plain[0]); 8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (res == NULL) { 8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(plain); 8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(res, plain + 1, plain[0]); 8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (reslen) 8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *reslen = plain[0]; 8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(plain); 8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return res; 8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt, 8988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *req_authenticator, 8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len, 9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *ebuf, size_t *elen) 9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i, len, first = 1; 9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[MD5_MAC_LEN], saltbuf[2], *pos; 9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[3]; 9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t _len[3]; 9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(saltbuf, salt); 9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = 1 + key_len; 9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len & 0x0f) { 9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = (len & 0xf0) + 16; 9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(ebuf, 0, len); 9148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ebuf[0] = key_len; 9158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(ebuf + 1, key, key_len); 9168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *elen = len; 9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = ebuf; 9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (len > 0) { 9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* b(1) = MD5(Secret + Request-Authenticator + Salt) 9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ 9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = secret; 9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt _len[0] = secret_len; 9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (first) { 9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = req_authenticator; 9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt _len[1] = MD5_MAC_LEN; 9288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = saltbuf; 9298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt _len[2] = sizeof(saltbuf); 9308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = pos - MD5_MAC_LEN; 9328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt _len[1] = MD5_MAC_LEN; 9338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(first ? 3 : 2, addr, _len, hash); 9358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt first = 0; 9368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < MD5_MAC_LEN; i++) 9388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ ^= hash[i]; 9398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len -= MD5_MAC_LEN; 9418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_ms_mppe_keys * 9468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtradius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg, 9478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len) 9488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *key; 9508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t keylen; 9518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_ms_mppe_keys *keys; 9528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL || sent_msg == NULL) 9548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys = os_zalloc(sizeof(*keys)); 9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (keys == NULL) 9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, 9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY, 9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keylen); 9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (key) { 9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->send = decrypt_ms_key(key, keylen, 9658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sent_msg->hdr->authenticator, 9668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret, secret_len, 9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keys->send_len); 9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(key); 9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, 9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY, 9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keylen); 9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (key) { 9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->recv = decrypt_ms_key(key, keylen, 9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sent_msg->hdr->authenticator, 9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret, secret_len, 9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keys->recv_len); 9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(key); 9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return keys; 9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_ms_mppe_keys * 9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtradius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg, 9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len) 9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *key; 9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t keylen; 9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_ms_mppe_keys *keys; 9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL || sent_msg == NULL) 9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys = os_zalloc(sizeof(*keys)); 9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (keys == NULL) 9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO, 10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RADIUS_CISCO_AV_PAIR, &keylen); 10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (key && keylen == 51 && 10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcmp(key, "leap:session-key=", 17) == 0) { 10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->recv = decrypt_ms_key(key + 17, keylen - 17, 10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sent_msg->hdr->authenticator, 10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret, secret_len, 10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &keys->recv_len); 10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(key); 10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return keys; 10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_add_mppe_keys(struct radius_msg *msg, 10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *req_authenticator, 10188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len, 10198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *send_key, size_t send_key_len, 10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *recv_key, size_t recv_key_len) 10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr; 10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT); 10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *buf; 10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_vendor *vhdr; 10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *pos; 10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t elen; 10288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int hlen; 10298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 salt; 10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2; 10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* MS-MPPE-Send-Key */ 10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf = os_malloc(hlen + send_key_len + 16); 10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (buf == NULL) { 10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = buf; 10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, &vendor_id, sizeof(vendor_id)); 10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += sizeof(vendor_id); 10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr = (struct radius_attr_vendor *) pos; 10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY; 10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (u8 *) (vhdr + 1); 10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt salt = os_random() | 0x8000; 10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(pos, salt); 10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 2; 10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret, 10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret_len, pos, &elen); 10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_length = hlen + elen - sizeof(vendor_id); 10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf, hlen + elen); 10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(buf); 10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* MS-MPPE-Recv-Key */ 10598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf = os_malloc(hlen + send_key_len + 16); 10608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (buf == NULL) { 10618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = buf; 10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, &vendor_id, sizeof(vendor_id)); 10658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += sizeof(vendor_id); 10668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr = (struct radius_attr_vendor *) pos; 10678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY; 10688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (u8 *) (vhdr + 1); 10698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt salt ^= 1; 10708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(pos, salt); 10718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 2; 10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret, 10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt secret_len, pos, &elen); 10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt vhdr->vendor_length = hlen + elen - sizeof(vendor_id); 10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf, hlen + elen); 10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(buf); 10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr == NULL) { 10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 10818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 10858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Add User-Password attribute to a RADIUS message and encrypt it as specified 10888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * in RFC 2865, Chap. 5.2 */ 10898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_attr_hdr * 10908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtradius_msg_add_attr_user_password(struct radius_msg *msg, 10918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *data, size_t data_len, 10928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *secret, size_t secret_len) 10938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 10948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 buf[128]; 10951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t padlen, i, buf_len, pos; 10968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[2]; 10978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len[2]; 10988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[16]; 10998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data_len > 128) 11018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(buf, data, data_len); 11048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf_len = data_len; 11058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt padlen = data_len % 16; 11071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (padlen && data_len < sizeof(buf)) { 11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt padlen = 16 - padlen; 11098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(buf + data_len, 0, padlen); 11108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf_len += padlen; 11118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = secret; 11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = secret_len; 11158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = msg->hdr->authenticator; 11168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = 16; 11178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(2, addr, len, hash); 11188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf[i] ^= hash[i]; 11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = 16; 11228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (pos < buf_len) { 11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = secret; 11258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = secret_len; 11268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = &buf[pos - 16]; 11278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = 16; 11288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(2, addr, len, hash); 11298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 11318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf[pos + i] ^= hash[i]; 11328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 16; 11348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD, 11378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf, buf_len); 11388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 11398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len) 11428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 11438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = NULL, *tmp; 11448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i, dlen; 11458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 11478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp = radius_get_attr_hdr(msg, i); 11488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tmp->type == type) { 11498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = tmp; 11508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 11518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!attr) 11558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 11568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dlen = attr->length - sizeof(*attr); 11588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (buf) 11598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(buf, (attr + 1), dlen > len ? len : dlen); 11608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return dlen; 11618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 11628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf, 11658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t *len, const u8 *start) 11668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 11678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 11688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = NULL, *tmp; 11698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 11718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp = radius_get_attr_hdr(msg, i); 11728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tmp->type == type && 11738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (start == NULL || (u8 *) tmp > start)) { 11748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = tmp; 11758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 11768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!attr) 11808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 11818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *buf = (u8 *) (attr + 1); 11838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *len = attr->length - sizeof(*attr); 11848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 11858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 11868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len) 11898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 11908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 11918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int count; 11928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (count = 0, i = 0; i < msg->attr_used; i++) { 11948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 11958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->type == type && 11968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr->length >= sizeof(struct radius_attr_hdr) + min_len) 11978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count++; 11988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return count; 12018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 12028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct radius_tunnel_attrs { 12058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int tag_used; 12068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int type; /* Tunnel-Type */ 12078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int medium_type; /* Tunnel-Medium-Type */ 12088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int vlanid; 12098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 12108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 12138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information 12148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @msg: RADIUS message 12158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: VLAN ID for the first tunnel configuration of -1 if none is found 12168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 12178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_msg_get_vlanid(struct radius_msg *msg) 12188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 12198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun; 12208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 12218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct radius_attr_hdr *attr = NULL; 12228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *data; 12238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char buf[10]; 12248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t dlen; 12258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(&tunnel, 0, sizeof(tunnel)); 12278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 12298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr = radius_get_attr_hdr(msg, i); 12308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data = (const u8 *) (attr + 1); 12318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dlen = attr->length - sizeof(*attr); 12328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->length < 3) 12338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 12348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data[0] >= RADIUS_TUNNEL_TAGS) 12358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun = &tunnel[0]; 12368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 12378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun = &tunnel[data[0]]; 12388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (attr->type) { 12408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_TUNNEL_TYPE: 12418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->length != 6) 12428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 12438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->tag_used++; 12448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->type = WPA_GET_BE24(data + 1); 12458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 12468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE: 12478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr->length != 6) 12488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 12498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->tag_used++; 12508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->medium_type = WPA_GET_BE24(data + 1); 12518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 12528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID: 12538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data[0] < RADIUS_TUNNEL_TAGS) { 12548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data++; 12558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dlen--; 12568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (dlen >= sizeof(buf)) 12588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 12598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(buf, data, dlen); 12608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf[dlen] = '\0'; 12618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->tag_used++; 12628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->vlanid = atoi(buf); 12638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 12648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) { 12688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun = &tunnel[i]; 12698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tun->tag_used && 12708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->type == RADIUS_TUNNEL_TYPE_VLAN && 12718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 && 12728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tun->vlanid > 0) 12738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return tun->vlanid; 12748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 12778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 12788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/** 12811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password 12821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @msg: Received RADIUS message 12831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @keylen: Length of returned password 12841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @secret: RADIUS shared secret 12851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @secret_len: Length of secret 12861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @sent_msg: Sent RADIUS message 12871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * Returns: pointer to password (free with os_free) or %NULL 12881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */ 12891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtchar * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen, 12901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *secret, size_t secret_len, 12911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct radius_msg *sent_msg) 12921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 12931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 *buf = NULL; 12941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t buflen; 12951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *salt; 12961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 *str; 12971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *addr[3]; 12981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t len[3]; 12991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 hash[16]; 13001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u8 *pos; 13011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t i; 13021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct radius_attr_hdr *attr; 13031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *data; 13041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t dlen; 13051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const u8 *fdata = NULL; /* points to found item */ 13061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t fdlen = -1; 13071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt char *ret = NULL; 13081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 13091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* find attribute with lowest tag and check it */ 13101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt for (i = 0; i < msg->attr_used; i++) { 13111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt attr = radius_get_attr_hdr(msg, i); 13121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (attr == NULL || 13131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) { 13141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt continue; 13151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 13161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (attr->length <= 5) 13171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt continue; 13181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt data = (const u8 *) (attr + 1); 13191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt dlen = attr->length - sizeof(*attr); 13201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (dlen <= 3 || dlen % 16 != 3) 13211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt continue; 13221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (fdata != NULL && fdata[0] <= data[0]) 13231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt continue; 13241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 13251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt fdata = data; 13261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt fdlen = dlen; 13271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 13281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (fdata == NULL) 13291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 13301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 13311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* alloc writable memory for decryption */ 13321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt buf = os_malloc(fdlen); 13331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (buf == NULL) 13341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 13351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_memcpy(buf, fdata, fdlen); 13361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt buflen = fdlen; 13371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 13381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* init pointers */ 13391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt salt = buf + 1; 13401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt str = buf + 3; 13411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 13421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* decrypt blocks */ 13431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos = buf + buflen - 16; /* last block */ 13441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt while (pos >= str + 16) { /* all but the first block */ 13451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[0] = secret; 13461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[0] = secret_len; 13471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[1] = pos - 16; 13481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[1] = 16; 13491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt md5_vector(2, addr, len, hash); 13501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 13511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt for (i = 0; i < 16; i++) 13521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos[i] ^= hash[i]; 13531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 13541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos -= 16; 13551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 13561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 13571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* decrypt first block */ 13581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (str != pos) 13591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 13601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[0] = secret; 13611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[0] = secret_len; 13621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[1] = sent_msg->hdr->authenticator; 13631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[1] = 16; 13641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt addr[2] = salt; 13651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt len[2] = 2; 13661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt md5_vector(3, addr, len, hash); 13671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 13681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt for (i = 0; i < 16; i++) 13691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pos[i] ^= hash[i]; 13701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 13711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* derive plaintext length from first subfield */ 13721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt *keylen = (unsigned char) str[0]; 13731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if ((u8 *) (str + *keylen) >= (u8 *) (buf + buflen)) { 13741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* decryption error - invalid key length */ 13751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 13761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 13771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (*keylen == 0) { 13781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* empty password */ 13791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt goto out; 13801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 13811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 13821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* copy passphrase into new buffer */ 13831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt ret = os_malloc(*keylen); 13841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (ret) 13851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_memcpy(ret, str + 1, *keylen); 13861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 13871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtout: 13881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* return new buffer */ 13891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(buf); 13901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return ret; 13911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 13921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 13931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 13948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid radius_free_class(struct radius_class_data *c) 13958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 13968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 13978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (c == NULL) 13988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 13998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < c->count; i++) 14008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(c->attr[i].data); 14018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(c->attr); 14028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt c->attr = NULL; 14038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt c->count = 0; 14048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 14058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint radius_copy_class(struct radius_class_data *dst, 14088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct radius_class_data *src) 14098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 14108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 14118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (src->attr == NULL) 14138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 14148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dst->attr = os_zalloc(src->count * sizeof(struct radius_attr_data)); 14168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (dst->attr == NULL) 14178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 14188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dst->count = 0; 14208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < src->count; i++) { 14228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dst->attr[i].data = os_malloc(src->attr[i].len); 14238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (dst->attr[i].data == NULL) 14248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 14258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dst->count++; 14268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(dst->attr[i].data, src->attr[i].data, 14278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt src->attr[i].len); 14288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dst->attr[i].len = src->attr[i].len; 14298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 14308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 14328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1433