1 /* 2 * RADIUS message processing 3 * Copyright (c) 2002-2009, 2011-2022, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "utils/includes.h" 10 11 #include "utils/common.h" 12 #include "utils/wpabuf.h" 13 #include "crypto/md5.h" 14 #include "crypto/crypto.h" 15 #include "radius.h" 16 17 18 /** 19 * struct radius_msg - RADIUS message structure for new and parsed messages 20 */ 21 struct radius_msg { 22 /** 23 * buf - Allocated buffer for RADIUS message 24 */ 25 struct wpabuf *buf; 26 27 /** 28 * hdr - Pointer to the RADIUS header in buf 29 */ 30 struct radius_hdr *hdr; 31 32 /** 33 * attr_pos - Array of indexes to attributes 34 * 35 * The values are number of bytes from buf to the beginning of 36 * struct radius_attr_hdr. 37 */ 38 size_t *attr_pos; 39 40 /** 41 * attr_size - Total size of the attribute pointer array 42 */ 43 size_t attr_size; 44 45 /** 46 * attr_used - Total number of attributes in the array 47 */ 48 size_t attr_used; 49 }; 50 51 radius_msg_get_hdr(struct radius_msg * msg)52 struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg) 53 { 54 return msg->hdr; 55 } 56 57 radius_msg_get_buf(struct radius_msg * msg)58 struct wpabuf * radius_msg_get_buf(struct radius_msg *msg) 59 { 60 return msg->buf; 61 } 62 63 64 static struct radius_attr_hdr * radius_get_attr_hdr(struct radius_msg * msg,int idx)65 radius_get_attr_hdr(struct radius_msg *msg, int idx) 66 { 67 return (struct radius_attr_hdr *) 68 (wpabuf_mhead_u8(msg->buf) + msg->attr_pos[idx]); 69 } 70 71 radius_msg_set_hdr(struct radius_msg * msg,u8 code,u8 identifier)72 static void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier) 73 { 74 msg->hdr->code = code; 75 msg->hdr->identifier = identifier; 76 } 77 78 radius_msg_initialize(struct radius_msg * msg)79 static int radius_msg_initialize(struct radius_msg *msg) 80 { 81 msg->attr_pos = os_calloc(RADIUS_DEFAULT_ATTR_COUNT, 82 sizeof(*msg->attr_pos)); 83 if (msg->attr_pos == NULL) 84 return -1; 85 86 msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT; 87 msg->attr_used = 0; 88 89 return 0; 90 } 91 92 93 /** 94 * radius_msg_new - Create a new RADIUS message 95 * @code: Code for RADIUS header 96 * @identifier: Identifier for RADIUS header 97 * Returns: Context for RADIUS message or %NULL on failure 98 * 99 * The caller is responsible for freeing the returned data with 100 * radius_msg_free(). 101 */ radius_msg_new(u8 code,u8 identifier)102 struct radius_msg * radius_msg_new(u8 code, u8 identifier) 103 { 104 struct radius_msg *msg; 105 106 msg = os_zalloc(sizeof(*msg)); 107 if (msg == NULL) 108 return NULL; 109 110 msg->buf = wpabuf_alloc(RADIUS_DEFAULT_MSG_SIZE); 111 if (msg->buf == NULL || radius_msg_initialize(msg)) { 112 radius_msg_free(msg); 113 return NULL; 114 } 115 msg->hdr = wpabuf_put(msg->buf, sizeof(struct radius_hdr)); 116 117 radius_msg_set_hdr(msg, code, identifier); 118 119 return msg; 120 } 121 122 123 /** 124 * radius_msg_free - Free a RADIUS message 125 * @msg: RADIUS message from radius_msg_new() or radius_msg_parse() 126 */ radius_msg_free(struct radius_msg * msg)127 void radius_msg_free(struct radius_msg *msg) 128 { 129 if (msg == NULL) 130 return; 131 132 wpabuf_free(msg->buf); 133 os_free(msg->attr_pos); 134 os_free(msg); 135 } 136 137 radius_code_string(u8 code)138 static const char *radius_code_string(u8 code) 139 { 140 switch (code) { 141 case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request"; 142 case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept"; 143 case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject"; 144 case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request"; 145 case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response"; 146 case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge"; 147 case RADIUS_CODE_STATUS_SERVER: return "Status-Server"; 148 case RADIUS_CODE_STATUS_CLIENT: return "Status-Client"; 149 case RADIUS_CODE_RESERVED: return "Reserved"; 150 case RADIUS_CODE_DISCONNECT_REQUEST: return "Disconnect-Request"; 151 case RADIUS_CODE_DISCONNECT_ACK: return "Disconnect-ACK"; 152 case RADIUS_CODE_DISCONNECT_NAK: return "Disconnect-NAK"; 153 case RADIUS_CODE_COA_REQUEST: return "CoA-Request"; 154 case RADIUS_CODE_COA_ACK: return "CoA-ACK"; 155 case RADIUS_CODE_COA_NAK: return "CoA-NAK"; 156 default: return "?Unknown?"; 157 } 158 } 159 160 161 struct radius_attr_type { 162 u16 type; /* 0..255 for basic types; 163 * (241 << 8) | <ext-type> for extended types */ 164 char *name; 165 enum { 166 RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP, 167 RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6 168 } data_type; 169 }; 170 171 static const struct radius_attr_type radius_attrs[] = 172 { 173 { RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT }, 174 { RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST }, 175 { RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP }, 176 { RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 }, 177 { RADIUS_ATTR_SERVICE_TYPE, "Service-Type", RADIUS_ATTR_INT32 }, 178 { RADIUS_ATTR_FRAMED_IP_ADDRESS, "Framed-IP-Address", RADIUS_ATTR_IP }, 179 { RADIUS_ATTR_FILTER_ID, "Filter-Id", RADIUS_ATTR_TEXT }, 180 { RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 }, 181 { RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT }, 182 { RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST }, 183 { RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST }, 184 { RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST }, 185 { RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 }, 186 { RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 }, 187 { RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action", 188 RADIUS_ATTR_INT32 }, 189 { RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id", 190 RADIUS_ATTR_TEXT }, 191 { RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id", 192 RADIUS_ATTR_TEXT }, 193 { RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT }, 194 { RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST }, 195 { RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type", 196 RADIUS_ATTR_INT32 }, 197 { RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 }, 198 { RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets", 199 RADIUS_ATTR_INT32 }, 200 { RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets", 201 RADIUS_ATTR_INT32 }, 202 { RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT }, 203 { RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 }, 204 { RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time", 205 RADIUS_ATTR_INT32 }, 206 { RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets", 207 RADIUS_ATTR_INT32 }, 208 { RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets", 209 RADIUS_ATTR_INT32 }, 210 { RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause", 211 RADIUS_ATTR_INT32 }, 212 { RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id", 213 RADIUS_ATTR_TEXT }, 214 { RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 }, 215 { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords", 216 RADIUS_ATTR_INT32 }, 217 { RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords", 218 RADIUS_ATTR_INT32 }, 219 { RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp", 220 RADIUS_ATTR_INT32 }, 221 { RADIUS_ATTR_EGRESS_VLANID, "EGRESS-VLANID", RADIUS_ATTR_HEXDUMP }, 222 { RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 }, 223 { RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP }, 224 { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type", 225 RADIUS_ATTR_HEXDUMP }, 226 { RADIUS_ATTR_TUNNEL_PASSWORD, "Tunnel-Password", 227 RADIUS_ATTR_UNDIST }, 228 { RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT }, 229 { RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST }, 230 { RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator", 231 RADIUS_ATTR_UNDIST }, 232 { RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id", 233 RADIUS_ATTR_HEXDUMP }, 234 { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval", 235 RADIUS_ATTR_INT32 }, 236 { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity", 237 RADIUS_ATTR_TEXT }, 238 { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 }, 239 { RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 }, 240 { RADIUS_ATTR_EAP_KEY_NAME, "EAP-Key-Name", RADIUS_ATTR_HEXDUMP }, 241 { RADIUS_ATTR_OPERATOR_NAME, "Operator-Name", RADIUS_ATTR_TEXT }, 242 { RADIUS_ATTR_LOCATION_INFO, "Location-Information", 243 RADIUS_ATTR_HEXDUMP }, 244 { RADIUS_ATTR_LOCATION_DATA, "Location-Data", RADIUS_ATTR_HEXDUMP }, 245 { RADIUS_ATTR_BASIC_LOCATION_POLICY_RULES, 246 "Basic-Location-Policy-Rules", RADIUS_ATTR_HEXDUMP }, 247 { RADIUS_ATTR_EXTENDED_LOCATION_POLICY_RULES, 248 "Extended-Location-Policy-Rules", RADIUS_ATTR_HEXDUMP }, 249 { RADIUS_ATTR_LOCATION_CAPABLE, "Location-Capable", RADIUS_ATTR_INT32 }, 250 { RADIUS_ATTR_REQUESTED_LOCATION_INFO, "Requested-Location-Info", 251 RADIUS_ATTR_INT32 }, 252 { RADIUS_ATTR_MOBILITY_DOMAIN_ID, "Mobility-Domain-Id", 253 RADIUS_ATTR_INT32 }, 254 { RADIUS_ATTR_WLAN_HESSID, "WLAN-HESSID", RADIUS_ATTR_TEXT }, 255 { RADIUS_ATTR_WLAN_REASON_CODE, "WLAN-Reason-Code", 256 RADIUS_ATTR_INT32 }, 257 { RADIUS_ATTR_WLAN_PAIRWISE_CIPHER, "WLAN-Pairwise-Cipher", 258 RADIUS_ATTR_HEXDUMP }, 259 { RADIUS_ATTR_WLAN_GROUP_CIPHER, "WLAN-Group-Cipher", 260 RADIUS_ATTR_HEXDUMP }, 261 { RADIUS_ATTR_WLAN_AKM_SUITE, "WLAN-AKM-Suite", 262 RADIUS_ATTR_HEXDUMP }, 263 { RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, "WLAN-Group-Mgmt-Pairwise-Cipher", 264 RADIUS_ATTR_HEXDUMP }, 265 { RADIUS_ATTR_EXT_TYPE_1, "Extended-Type-1", RADIUS_ATTR_UNDIST }, 266 { RADIUS_ATTR_EXT_TYPE_2, "Extended-Type-2", RADIUS_ATTR_UNDIST }, 267 { RADIUS_ATTR_EXT_TYPE_3, "Extended-Type-3", RADIUS_ATTR_UNDIST }, 268 { RADIUS_ATTR_EXT_TYPE_4, "Extended-Type-4", RADIUS_ATTR_UNDIST }, 269 { RADIUS_ATTR_LONG_EXT_TYPE_1, "Long-Extended-Type-1", 270 RADIUS_ATTR_UNDIST }, 271 { RADIUS_ATTR_LONG_EXT_TYPE_2, "Long-Extended-Type-2", 272 RADIUS_ATTR_UNDIST }, 273 { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_1, "Extended-Vendor-Specific-1", 274 RADIUS_ATTR_UNDIST }, 275 { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_2, "Extended-Vendor-Specific-2", 276 RADIUS_ATTR_UNDIST }, 277 { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_3, "Extended-Vendor-Specific-3", 278 RADIUS_ATTR_UNDIST }, 279 { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_4, "Extended-Vendor-Specific-4", 280 RADIUS_ATTR_UNDIST }, 281 { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5, "Extended-Vendor-Specific-5", 282 RADIUS_ATTR_UNDIST }, 283 { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_6, "Extended-Vendor-Specific-6", 284 RADIUS_ATTR_UNDIST }, 285 }; 286 #define RADIUS_ATTRS ARRAY_SIZE(radius_attrs) 287 288 radius_get_attr_type(u16 type)289 static const struct radius_attr_type * radius_get_attr_type(u16 type) 290 { 291 size_t i; 292 293 for (i = 0; i < RADIUS_ATTRS; i++) { 294 if (type == radius_attrs[i].type) 295 return &radius_attrs[i]; 296 } 297 298 return NULL; 299 } 300 301 radius_is_long_ext_type(u8 type)302 static bool radius_is_long_ext_type(u8 type) 303 { 304 return type == RADIUS_ATTR_LONG_EXT_TYPE_1 || 305 type == RADIUS_ATTR_LONG_EXT_TYPE_2; 306 } 307 308 radius_is_ext_type(u8 type)309 static bool radius_is_ext_type(u8 type) 310 { 311 return type >= RADIUS_ATTR_EXT_TYPE_1 && 312 type <= RADIUS_ATTR_LONG_EXT_TYPE_2; 313 } 314 315 radius_msg_dump_attr(struct radius_attr_hdr * hdr)316 static void radius_msg_dump_attr(struct radius_attr_hdr *hdr) 317 { 318 struct radius_attr_hdr_ext *ext = NULL; 319 const struct radius_attr_type *attr; 320 int len; 321 unsigned char *pos; 322 char buf[1000]; 323 324 if (hdr->length < sizeof(struct radius_attr_hdr)) 325 return; 326 327 if (radius_is_ext_type(hdr->type)) { 328 if (hdr->length < 4) { 329 wpa_printf(MSG_INFO, 330 " Invalid attribute %d (too short for extended type)", 331 hdr->type); 332 return; 333 } 334 335 ext = (struct radius_attr_hdr_ext *) hdr; 336 } 337 338 if (ext) { 339 attr = radius_get_attr_type((ext->type << 8) | ext->ext_type); 340 wpa_printf(MSG_INFO, " Attribute %d.%d (%s) length=%d", 341 ext->type, ext->ext_type, 342 attr ? attr->name : "?Unknown?", ext->length); 343 pos = (unsigned char *) (ext + 1); 344 len = ext->length - sizeof(struct radius_attr_hdr_ext); 345 } else { 346 attr = radius_get_attr_type(hdr->type); 347 wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d", 348 hdr->type, attr ? attr->name : "?Unknown?", 349 hdr->length); 350 pos = (unsigned char *) (hdr + 1); 351 len = hdr->length - sizeof(struct radius_attr_hdr); 352 } 353 354 if (!attr) 355 return; 356 357 switch (attr->data_type) { 358 case RADIUS_ATTR_TEXT: 359 printf_encode(buf, sizeof(buf), pos, len); 360 wpa_printf(MSG_INFO, " Value: '%s'", buf); 361 break; 362 363 case RADIUS_ATTR_IP: 364 if (len == 4) { 365 struct in_addr addr; 366 os_memcpy(&addr, pos, 4); 367 wpa_printf(MSG_INFO, " Value: %s", 368 inet_ntoa(addr)); 369 } else { 370 wpa_printf(MSG_INFO, " Invalid IP address length %d", 371 len); 372 } 373 break; 374 375 #ifdef CONFIG_IPV6 376 case RADIUS_ATTR_IPV6: 377 if (len == 16) { 378 const char *atxt; 379 struct in6_addr *addr = (struct in6_addr *) pos; 380 atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf)); 381 wpa_printf(MSG_INFO, " Value: %s", 382 atxt ? atxt : "?"); 383 } else { 384 wpa_printf(MSG_INFO, " Invalid IPv6 address length %d", 385 len); 386 } 387 break; 388 #endif /* CONFIG_IPV6 */ 389 390 case RADIUS_ATTR_HEXDUMP: 391 case RADIUS_ATTR_UNDIST: 392 wpa_snprintf_hex(buf, sizeof(buf), pos, len); 393 wpa_printf(MSG_INFO, " Value: %s", buf); 394 break; 395 396 case RADIUS_ATTR_INT32: 397 if (len == 4) 398 wpa_printf(MSG_INFO, " Value: %u", 399 WPA_GET_BE32(pos)); 400 else 401 wpa_printf(MSG_INFO, " Invalid INT32 length %d", 402 len); 403 break; 404 405 default: 406 break; 407 } 408 } 409 410 radius_msg_dump(struct radius_msg * msg)411 void radius_msg_dump(struct radius_msg *msg) 412 { 413 size_t i; 414 415 wpa_printf(MSG_INFO, "RADIUS message: code=%d (%s) identifier=%d length=%d", 416 msg->hdr->code, radius_code_string(msg->hdr->code), 417 msg->hdr->identifier, be_to_host16(msg->hdr->length)); 418 419 for (i = 0; i < msg->attr_used; i++) { 420 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 421 radius_msg_dump_attr(attr); 422 } 423 } 424 425 radius_msg_add_msg_auth(struct radius_msg * msg)426 u8 * radius_msg_add_msg_auth(struct radius_msg *msg) 427 { 428 u8 auth[MD5_MAC_LEN]; 429 struct radius_attr_hdr *attr; 430 431 os_memset(auth, 0, MD5_MAC_LEN); 432 attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 433 auth, MD5_MAC_LEN); 434 if (!attr) { 435 wpa_printf(MSG_ERROR, 436 "WARNING: Could not add Message-Authenticator"); 437 return NULL; 438 } 439 440 return (u8 *) (attr + 1); 441 } 442 443 radius_msg_auth_pos(struct radius_msg * msg)444 static u8 * radius_msg_auth_pos(struct radius_msg *msg) 445 { 446 u8 *pos; 447 size_t alen; 448 449 if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 450 &pos, &alen, NULL) == 0 && 451 alen == MD5_MAC_LEN) { 452 /* Use already added Message-Authenticator attribute */ 453 return pos; 454 } 455 456 /* Add a Message-Authenticator attribute */ 457 return radius_msg_add_msg_auth(msg); 458 } 459 460 radius_msg_finish(struct radius_msg * msg,const u8 * secret,size_t secret_len)461 int radius_msg_finish(struct radius_msg *msg, const u8 *secret, 462 size_t secret_len) 463 { 464 if (secret) { 465 u8 *pos; 466 467 pos = radius_msg_auth_pos(msg); 468 if (!pos) 469 return -1; 470 msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 471 if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 472 wpabuf_len(msg->buf), pos) < 0) { 473 wpa_printf(MSG_INFO, "RADIUS: MD5 not available"); 474 return -1; 475 } 476 } else 477 msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 478 479 if (wpabuf_len(msg->buf) > 0xffff) { 480 wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 481 (unsigned long) wpabuf_len(msg->buf)); 482 return -1; 483 } 484 return 0; 485 } 486 487 radius_msg_finish_srv(struct radius_msg * msg,const u8 * secret,size_t secret_len,const u8 * req_authenticator)488 int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, 489 size_t secret_len, const u8 *req_authenticator) 490 { 491 const u8 *addr[4]; 492 size_t len[4]; 493 u8 *pos; 494 495 pos = radius_msg_auth_pos(msg); 496 if (!pos) 497 return -1; 498 msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 499 os_memcpy(msg->hdr->authenticator, req_authenticator, 500 sizeof(msg->hdr->authenticator)); 501 if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 502 wpabuf_len(msg->buf), pos) < 0) { 503 wpa_printf(MSG_INFO, "RADIUS: MD5 not available"); 504 return -1; 505 } 506 507 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 508 addr[0] = (u8 *) msg->hdr; 509 len[0] = 1 + 1 + 2; 510 addr[1] = req_authenticator; 511 len[1] = MD5_MAC_LEN; 512 addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); 513 len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 514 addr[3] = secret; 515 len[3] = secret_len; 516 if (md5_vector(4, addr, len, msg->hdr->authenticator) < 0) { 517 wpa_printf(MSG_INFO, "RADIUS: MD5 not available"); 518 return -1; 519 } 520 521 if (wpabuf_len(msg->buf) > 0xffff) { 522 wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 523 (unsigned long) wpabuf_len(msg->buf)); 524 return -1; 525 } 526 return 0; 527 } 528 529 radius_msg_finish_das_resp(struct radius_msg * msg,const u8 * secret,size_t secret_len,const struct radius_hdr * req_hdr)530 int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret, 531 size_t secret_len, 532 const struct radius_hdr *req_hdr) 533 { 534 const u8 *addr[2]; 535 size_t len[2]; 536 u8 *pos; 537 538 pos = radius_msg_auth_pos(msg); 539 if (!pos) 540 return -1; 541 542 msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 543 os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16); 544 if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 545 wpabuf_len(msg->buf), pos) < 0) { 546 wpa_printf(MSG_INFO, "RADIUS: MD5 not available"); 547 return -1; 548 } 549 550 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 551 addr[0] = wpabuf_head_u8(msg->buf); 552 len[0] = wpabuf_len(msg->buf); 553 addr[1] = secret; 554 len[1] = secret_len; 555 if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0) { 556 wpa_printf(MSG_INFO, "RADIUS: MD5 not available"); 557 return -1; 558 } 559 560 if (wpabuf_len(msg->buf) > 0xffff) { 561 wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 562 (unsigned long) wpabuf_len(msg->buf)); 563 return -1; 564 } 565 return 0; 566 } 567 568 radius_msg_finish_acct(struct radius_msg * msg,const u8 * secret,size_t secret_len)569 int radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret, 570 size_t secret_len) 571 { 572 const u8 *addr[2]; 573 size_t len[2]; 574 575 msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 576 os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN); 577 addr[0] = wpabuf_head(msg->buf); 578 len[0] = wpabuf_len(msg->buf); 579 addr[1] = secret; 580 len[1] = secret_len; 581 if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0) { 582 wpa_printf(MSG_INFO, "RADIUS: MD5 not available"); 583 return -1; 584 } 585 586 if (wpabuf_len(msg->buf) > 0xffff) { 587 wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)", 588 (unsigned long) wpabuf_len(msg->buf)); 589 return -1; 590 } 591 return 0; 592 } 593 594 radius_msg_finish_acct_resp(struct radius_msg * msg,const u8 * secret,size_t secret_len,const u8 * req_authenticator)595 int radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret, 596 size_t secret_len, const u8 *req_authenticator) 597 { 598 const u8 *addr[2]; 599 size_t len[2]; 600 601 msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 602 os_memcpy(msg->hdr->authenticator, req_authenticator, MD5_MAC_LEN); 603 addr[0] = wpabuf_head(msg->buf); 604 len[0] = wpabuf_len(msg->buf); 605 addr[1] = secret; 606 len[1] = secret_len; 607 if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0) { 608 wpa_printf(MSG_INFO, "RADIUS: MD5 not available"); 609 return -1; 610 } 611 612 if (wpabuf_len(msg->buf) > 0xffff) { 613 wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)", 614 (unsigned long) wpabuf_len(msg->buf)); 615 return -1; 616 } 617 return 0; 618 } 619 620 radius_msg_verify_acct_req(struct radius_msg * msg,const u8 * secret,size_t secret_len)621 int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret, 622 size_t secret_len) 623 { 624 const u8 *addr[4]; 625 size_t len[4]; 626 u8 zero[MD5_MAC_LEN]; 627 u8 hash[MD5_MAC_LEN]; 628 629 os_memset(zero, 0, sizeof(zero)); 630 addr[0] = (u8 *) msg->hdr; 631 len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN; 632 addr[1] = zero; 633 len[1] = MD5_MAC_LEN; 634 addr[2] = (u8 *) (msg->hdr + 1); 635 len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 636 addr[3] = secret; 637 len[3] = secret_len; 638 if (md5_vector(4, addr, len, hash) < 0) { 639 wpa_printf(MSG_INFO, "RADIUS: MD5 not available"); 640 return 1; 641 } 642 return os_memcmp_const(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0; 643 } 644 645 radius_msg_verify_das_req(struct radius_msg * msg,const u8 * secret,size_t secret_len,int require_message_authenticator)646 int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret, 647 size_t secret_len, 648 int require_message_authenticator) 649 { 650 const u8 *addr[4]; 651 size_t len[4]; 652 u8 zero[MD5_MAC_LEN]; 653 u8 hash[MD5_MAC_LEN]; 654 u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN]; 655 u8 orig_authenticator[16]; 656 657 struct radius_attr_hdr *attr = NULL, *tmp; 658 size_t i; 659 660 os_memset(zero, 0, sizeof(zero)); 661 addr[0] = (u8 *) msg->hdr; 662 len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN; 663 addr[1] = zero; 664 len[1] = MD5_MAC_LEN; 665 addr[2] = (u8 *) (msg->hdr + 1); 666 len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 667 addr[3] = secret; 668 len[3] = secret_len; 669 if (md5_vector(4, addr, len, hash) < 0) { 670 wpa_printf(MSG_INFO, "RADIUS: MD5 not available"); 671 return 1; 672 } 673 if (os_memcmp_const(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0) 674 return 1; 675 676 for (i = 0; i < msg->attr_used; i++) { 677 tmp = radius_get_attr_hdr(msg, i); 678 if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) { 679 if (attr != NULL) { 680 wpa_printf(MSG_WARNING, "Multiple " 681 "Message-Authenticator attributes " 682 "in RADIUS message"); 683 return 1; 684 } 685 attr = tmp; 686 } 687 } 688 689 if (attr == NULL) { 690 if (require_message_authenticator) { 691 wpa_printf(MSG_WARNING, 692 "Missing Message-Authenticator attribute in RADIUS message"); 693 return 1; 694 } 695 return 0; 696 } 697 698 os_memcpy(orig, attr + 1, MD5_MAC_LEN); 699 os_memset(attr + 1, 0, MD5_MAC_LEN); 700 os_memcpy(orig_authenticator, msg->hdr->authenticator, 701 sizeof(orig_authenticator)); 702 os_memset(msg->hdr->authenticator, 0, 703 sizeof(msg->hdr->authenticator)); 704 if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 705 wpabuf_len(msg->buf), auth) < 0) { 706 wpa_printf(MSG_INFO, "RADIUS: MD5 not available"); 707 return 1; 708 } 709 os_memcpy(attr + 1, orig, MD5_MAC_LEN); 710 os_memcpy(msg->hdr->authenticator, orig_authenticator, 711 sizeof(orig_authenticator)); 712 713 return os_memcmp_const(orig, auth, MD5_MAC_LEN) != 0; 714 } 715 716 radius_msg_add_attr_to_array(struct radius_msg * msg,struct radius_attr_hdr * attr)717 static int radius_msg_add_attr_to_array(struct radius_msg *msg, 718 struct radius_attr_hdr *attr) 719 { 720 if (msg->attr_used >= msg->attr_size) { 721 size_t *nattr_pos; 722 size_t nlen = msg->attr_size * 2; 723 724 nattr_pos = os_realloc_array(msg->attr_pos, nlen, 725 sizeof(*msg->attr_pos)); 726 if (nattr_pos == NULL) 727 return -1; 728 729 msg->attr_pos = nattr_pos; 730 msg->attr_size = nlen; 731 } 732 733 msg->attr_pos[msg->attr_used++] = 734 (unsigned char *) attr - wpabuf_head_u8(msg->buf); 735 736 return 0; 737 } 738 739 radius_msg_add_attr(struct radius_msg * msg,u16 type,const u8 * data,size_t data_len)740 struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u16 type, 741 const u8 *data, size_t data_len) 742 { 743 size_t buf_needed, max_len; 744 struct radius_attr_hdr *attr = NULL; 745 struct radius_attr_hdr_ext *ext; 746 u8 ext_type = 0; 747 748 if (TEST_FAIL()) 749 return NULL; 750 751 if (type > 255) { 752 if (!radius_is_ext_type(type >> 8)) { 753 wpa_printf(MSG_ERROR, 754 "%s: Undefined extended type %d.%d", 755 __func__, type >> 8, type & 0xff); 756 return NULL; 757 } 758 ext_type = type & 0xff; 759 type >>= 8; 760 } else if (radius_is_ext_type(type)) { 761 wpa_printf(MSG_ERROR, "%s: Unexpected extended type use for %d", 762 __func__, type); 763 } 764 765 if (radius_is_long_ext_type(type)) { 766 size_t hdr_len = sizeof(struct radius_attr_hdr_ext) + 1; 767 size_t plen = 255 - hdr_len; 768 size_t num; 769 770 max_len = 4096; 771 num = (data_len + plen - 1) / plen; 772 if (num == 0) 773 num = 1; 774 buf_needed = num * hdr_len + data_len; 775 } else if (radius_is_ext_type(type)) { 776 max_len = RADIUS_MAX_EXT_ATTR_LEN; 777 buf_needed = sizeof(struct radius_attr_hdr_ext) + data_len; 778 } else { 779 max_len = RADIUS_MAX_ATTR_LEN; 780 buf_needed = sizeof(*attr) + data_len; 781 } 782 if (data_len > max_len) { 783 wpa_printf(MSG_ERROR, 784 "%s: too long attribute (%zu > %zu bytes)", 785 __func__, data_len, max_len); 786 return NULL; 787 } 788 789 if (wpabuf_tailroom(msg->buf) < buf_needed) { 790 /* allocate more space for message buffer */ 791 if (wpabuf_resize(&msg->buf, buf_needed) < 0) 792 return NULL; 793 msg->hdr = wpabuf_mhead(msg->buf); 794 } 795 796 if (radius_is_long_ext_type(type)) { 797 size_t plen = 255 - sizeof(struct radius_attr_hdr_ext) - 1; 798 size_t alen; 799 800 do { 801 alen = data_len > plen ? plen : data_len; 802 ext = wpabuf_put(msg->buf, 803 sizeof(struct radius_attr_hdr_ext)); 804 if (!attr) 805 attr = (struct radius_attr_hdr *) ext; 806 ext->type = type; 807 ext->length = sizeof(*ext) + 1 + alen; 808 ext->ext_type = ext_type; 809 wpabuf_put_u8(msg->buf, data_len > alen ? 0x80 : 0); 810 wpabuf_put_data(msg->buf, data, data_len); 811 data += alen; 812 data_len -= alen; 813 if (radius_msg_add_attr_to_array( 814 msg, (struct radius_attr_hdr *) ext)) 815 return NULL; 816 } while (data_len > 0); 817 } else if (radius_is_ext_type(type)) { 818 ext = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr_ext)); 819 attr = (struct radius_attr_hdr *) ext; 820 ext->type = type; 821 ext->length = sizeof(*ext) + data_len; 822 ext->ext_type = ext_type; 823 wpabuf_put_data(msg->buf, data, data_len); 824 if (radius_msg_add_attr_to_array(msg, attr)) 825 return NULL; 826 } else { 827 attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr)); 828 attr->type = type; 829 attr->length = sizeof(*attr) + data_len; 830 wpabuf_put_data(msg->buf, data, data_len); 831 if (radius_msg_add_attr_to_array(msg, attr)) 832 return NULL; 833 } 834 835 return attr; 836 } 837 838 839 /** 840 * radius_msg_parse - Parse a RADIUS message 841 * @data: RADIUS message to be parsed 842 * @len: Length of data buffer in octets 843 * Returns: Parsed RADIUS message or %NULL on failure 844 * 845 * This parses a RADIUS message and makes a copy of its data. The caller is 846 * responsible for freeing the returned data with radius_msg_free(). 847 */ radius_msg_parse(const u8 * data,size_t len)848 struct radius_msg * radius_msg_parse(const u8 *data, size_t len) 849 { 850 struct radius_msg *msg; 851 struct radius_hdr *hdr; 852 struct radius_attr_hdr *attr; 853 size_t msg_len; 854 unsigned char *pos, *end; 855 856 if (data == NULL || len < sizeof(*hdr)) 857 return NULL; 858 859 hdr = (struct radius_hdr *) data; 860 861 msg_len = be_to_host16(hdr->length); 862 if (msg_len < sizeof(*hdr) || msg_len > len) { 863 wpa_printf(MSG_INFO, "RADIUS: Invalid message length"); 864 return NULL; 865 } 866 867 if (msg_len < len) { 868 wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after " 869 "RADIUS message", (unsigned long) len - msg_len); 870 } 871 872 msg = os_zalloc(sizeof(*msg)); 873 if (msg == NULL) 874 return NULL; 875 876 msg->buf = wpabuf_alloc_copy(data, msg_len); 877 if (msg->buf == NULL || radius_msg_initialize(msg)) { 878 radius_msg_free(msg); 879 return NULL; 880 } 881 msg->hdr = wpabuf_mhead(msg->buf); 882 883 /* parse attributes */ 884 pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr); 885 end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf); 886 while (pos < end) { 887 if ((size_t) (end - pos) < sizeof(*attr)) 888 goto fail; 889 890 attr = (struct radius_attr_hdr *) pos; 891 892 if (attr->length > end - pos || attr->length < sizeof(*attr)) 893 goto fail; 894 895 /* TODO: check that attr->length is suitable for attr->type */ 896 897 if (radius_msg_add_attr_to_array(msg, attr)) 898 goto fail; 899 900 pos += attr->length; 901 } 902 903 return msg; 904 905 fail: 906 radius_msg_free(msg); 907 return NULL; 908 } 909 910 radius_msg_add_eap(struct radius_msg * msg,const u8 * data,size_t data_len)911 int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len) 912 { 913 const u8 *pos = data; 914 size_t left = data_len; 915 916 while (left > 0) { 917 int len; 918 if (left > RADIUS_MAX_ATTR_LEN) 919 len = RADIUS_MAX_ATTR_LEN; 920 else 921 len = left; 922 923 if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE, 924 pos, len)) 925 return 0; 926 927 pos += len; 928 left -= len; 929 } 930 931 return 1; 932 } 933 934 radius_msg_get_eap(struct radius_msg * msg)935 struct wpabuf * radius_msg_get_eap(struct radius_msg *msg) 936 { 937 struct wpabuf *eap; 938 size_t len, i; 939 struct radius_attr_hdr *attr; 940 941 if (msg == NULL) 942 return NULL; 943 944 len = 0; 945 for (i = 0; i < msg->attr_used; i++) { 946 attr = radius_get_attr_hdr(msg, i); 947 if (attr->type == RADIUS_ATTR_EAP_MESSAGE && 948 attr->length > sizeof(struct radius_attr_hdr)) 949 len += attr->length - sizeof(struct radius_attr_hdr); 950 } 951 952 if (len == 0) 953 return NULL; 954 955 eap = wpabuf_alloc(len); 956 if (eap == NULL) 957 return NULL; 958 959 for (i = 0; i < msg->attr_used; i++) { 960 attr = radius_get_attr_hdr(msg, i); 961 if (attr->type == RADIUS_ATTR_EAP_MESSAGE && 962 attr->length > sizeof(struct radius_attr_hdr)) { 963 int flen = attr->length - sizeof(*attr); 964 wpabuf_put_data(eap, attr + 1, flen); 965 } 966 } 967 968 return eap; 969 } 970 971 radius_msg_verify_msg_auth(struct radius_msg * msg,const u8 * secret,size_t secret_len,const u8 * req_auth)972 int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, 973 size_t secret_len, const u8 *req_auth) 974 { 975 u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN]; 976 u8 orig_authenticator[16]; 977 struct radius_attr_hdr *attr = NULL, *tmp; 978 size_t i; 979 980 for (i = 0; i < msg->attr_used; i++) { 981 tmp = radius_get_attr_hdr(msg, i); 982 if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) { 983 if (attr != NULL) { 984 wpa_printf(MSG_INFO, "Multiple Message-Authenticator attributes in RADIUS message"); 985 return 1; 986 } 987 attr = tmp; 988 } 989 } 990 991 if (attr == NULL) { 992 wpa_printf(MSG_INFO, "No Message-Authenticator attribute found"); 993 return 1; 994 } 995 996 os_memcpy(orig, attr + 1, MD5_MAC_LEN); 997 os_memset(attr + 1, 0, MD5_MAC_LEN); 998 if (req_auth) { 999 os_memcpy(orig_authenticator, msg->hdr->authenticator, 1000 sizeof(orig_authenticator)); 1001 os_memcpy(msg->hdr->authenticator, req_auth, 1002 sizeof(msg->hdr->authenticator)); 1003 } 1004 if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 1005 wpabuf_len(msg->buf), auth) < 0) { 1006 wpa_printf(MSG_INFO, "RADIUS: MD5 not available"); 1007 return 1; 1008 } 1009 os_memcpy(attr + 1, orig, MD5_MAC_LEN); 1010 if (req_auth) { 1011 os_memcpy(msg->hdr->authenticator, orig_authenticator, 1012 sizeof(orig_authenticator)); 1013 } 1014 1015 if (os_memcmp_const(orig, auth, MD5_MAC_LEN) != 0) { 1016 wpa_printf(MSG_INFO, "Invalid Message-Authenticator!"); 1017 return 1; 1018 } 1019 1020 return 0; 1021 } 1022 1023 radius_msg_verify(struct radius_msg * msg,const u8 * secret,size_t secret_len,struct radius_msg * sent_msg,int auth)1024 int radius_msg_verify(struct radius_msg *msg, const u8 *secret, 1025 size_t secret_len, struct radius_msg *sent_msg, int auth) 1026 { 1027 const u8 *addr[4]; 1028 size_t len[4]; 1029 u8 hash[MD5_MAC_LEN]; 1030 1031 if (sent_msg == NULL) { 1032 wpa_printf(MSG_INFO, "No matching Access-Request message found"); 1033 return 1; 1034 } 1035 1036 if (!auth) { 1037 u8 *pos; 1038 size_t alen; 1039 1040 if (radius_msg_get_attr_ptr(msg, 1041 RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 1042 &pos, &alen, NULL) == 0) { 1043 /* Check the Message-Authenticator attribute since it 1044 * was included even if we are configured to not 1045 * require it. */ 1046 auth = 1; 1047 } 1048 } 1049 1050 if (auth && 1051 radius_msg_verify_msg_auth(msg, secret, secret_len, 1052 sent_msg->hdr->authenticator)) { 1053 return 1; 1054 } 1055 1056 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 1057 addr[0] = (u8 *) msg->hdr; 1058 len[0] = 1 + 1 + 2; 1059 addr[1] = sent_msg->hdr->authenticator; 1060 len[1] = MD5_MAC_LEN; 1061 addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); 1062 len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 1063 addr[3] = secret; 1064 len[3] = secret_len; 1065 if (md5_vector(4, addr, len, hash) < 0 || 1066 os_memcmp_const(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) { 1067 wpa_printf(MSG_INFO, "Response Authenticator invalid!"); 1068 return 1; 1069 } 1070 1071 return 0; 1072 } 1073 1074 radius_msg_copy_attr(struct radius_msg * dst,struct radius_msg * src,u8 type)1075 int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src, 1076 u8 type) 1077 { 1078 struct radius_attr_hdr *attr; 1079 size_t i; 1080 int count = 0; 1081 1082 for (i = 0; i < src->attr_used; i++) { 1083 attr = radius_get_attr_hdr(src, i); 1084 if (attr->type == type && attr->length >= sizeof(*attr)) { 1085 if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1), 1086 attr->length - sizeof(*attr))) 1087 return -1; 1088 count++; 1089 } 1090 } 1091 1092 return count; 1093 } 1094 1095 1096 /* Create Request Authenticator. The value should be unique over the lifetime 1097 * of the shared secret between authenticator and authentication server. 1098 */ radius_msg_make_authenticator(struct radius_msg * msg)1099 int radius_msg_make_authenticator(struct radius_msg *msg) 1100 { 1101 return os_get_random((u8 *) &msg->hdr->authenticator, 1102 sizeof(msg->hdr->authenticator)); 1103 } 1104 1105 1106 /* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message. 1107 * Returns the Attribute payload and sets alen to indicate the length of the 1108 * payload if a vendor attribute with subtype is found, otherwise returns NULL. 1109 * The returned payload is allocated with os_malloc() and caller must free it 1110 * by calling os_free(). 1111 */ radius_msg_get_vendor_attr(struct radius_msg * msg,u32 vendor,u8 subtype,size_t * alen)1112 static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor, 1113 u8 subtype, size_t *alen) 1114 { 1115 u8 *data, *pos; 1116 size_t i, len; 1117 1118 if (msg == NULL) 1119 return NULL; 1120 1121 for (i = 0; i < msg->attr_used; i++) { 1122 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 1123 size_t left; 1124 u32 vendor_id; 1125 struct radius_attr_vendor *vhdr; 1126 1127 if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC || 1128 attr->length < sizeof(*attr)) 1129 continue; 1130 1131 left = attr->length - sizeof(*attr); 1132 if (left < 4) 1133 continue; 1134 1135 pos = (u8 *) (attr + 1); 1136 1137 os_memcpy(&vendor_id, pos, 4); 1138 pos += 4; 1139 left -= 4; 1140 1141 if (ntohl(vendor_id) != vendor) 1142 continue; 1143 1144 while (left >= sizeof(*vhdr)) { 1145 vhdr = (struct radius_attr_vendor *) pos; 1146 if (vhdr->vendor_length > left || 1147 vhdr->vendor_length < sizeof(*vhdr)) { 1148 break; 1149 } 1150 if (vhdr->vendor_type != subtype) { 1151 pos += vhdr->vendor_length; 1152 left -= vhdr->vendor_length; 1153 continue; 1154 } 1155 1156 len = vhdr->vendor_length - sizeof(*vhdr); 1157 data = os_memdup(pos + sizeof(*vhdr), len); 1158 if (data == NULL) 1159 return NULL; 1160 if (alen) 1161 *alen = len; 1162 return data; 1163 } 1164 } 1165 1166 return NULL; 1167 } 1168 1169 decrypt_ms_key(const u8 * key,size_t len,const u8 * req_authenticator,const u8 * secret,size_t secret_len,size_t * reslen)1170 static u8 * decrypt_ms_key(const u8 *key, size_t len, 1171 const u8 *req_authenticator, 1172 const u8 *secret, size_t secret_len, size_t *reslen) 1173 { 1174 u8 *plain, *ppos, *res; 1175 const u8 *pos; 1176 size_t left, plen; 1177 u8 hash[MD5_MAC_LEN]; 1178 int i, first = 1; 1179 const u8 *addr[3]; 1180 size_t elen[3]; 1181 1182 /* key: 16-bit salt followed by encrypted key info */ 1183 1184 if (len < 2 + 16) { 1185 wpa_printf(MSG_DEBUG, "RADIUS: %s: Len is too small: %d", 1186 __func__, (int) len); 1187 return NULL; 1188 } 1189 1190 pos = key + 2; 1191 left = len - 2; 1192 if (left % 16) { 1193 wpa_printf(MSG_INFO, "RADIUS: Invalid ms key len %lu", 1194 (unsigned long) left); 1195 return NULL; 1196 } 1197 1198 plen = left; 1199 ppos = plain = os_malloc(plen); 1200 if (plain == NULL) 1201 return NULL; 1202 plain[0] = 0; 1203 1204 while (left > 0) { 1205 /* b(1) = MD5(Secret + Request-Authenticator + Salt) 1206 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ 1207 1208 addr[0] = secret; 1209 elen[0] = secret_len; 1210 if (first) { 1211 addr[1] = req_authenticator; 1212 elen[1] = MD5_MAC_LEN; 1213 addr[2] = key; 1214 elen[2] = 2; /* Salt */ 1215 } else { 1216 addr[1] = pos - MD5_MAC_LEN; 1217 elen[1] = MD5_MAC_LEN; 1218 } 1219 if (md5_vector(first ? 3 : 2, addr, elen, hash) < 0) { 1220 wpa_printf(MSG_INFO, "RADIUS: MD5 not available"); 1221 os_free(plain); 1222 return NULL; 1223 } 1224 first = 0; 1225 1226 for (i = 0; i < MD5_MAC_LEN; i++) 1227 *ppos++ = *pos++ ^ hash[i]; 1228 left -= MD5_MAC_LEN; 1229 } 1230 1231 if (plain[0] == 0 || plain[0] > plen - 1) { 1232 wpa_printf(MSG_INFO, "RADIUS: Failed to decrypt MPPE key"); 1233 os_free(plain); 1234 return NULL; 1235 } 1236 1237 res = os_memdup(plain + 1, plain[0]); 1238 if (res == NULL) { 1239 os_free(plain); 1240 return NULL; 1241 } 1242 if (reslen) 1243 *reslen = plain[0]; 1244 os_free(plain); 1245 return res; 1246 } 1247 1248 encrypt_ms_key(const u8 * key,size_t key_len,u16 salt,const u8 * req_authenticator,const u8 * secret,size_t secret_len,u8 * ebuf,size_t * elen)1249 static int encrypt_ms_key(const u8 *key, size_t key_len, u16 salt, 1250 const u8 *req_authenticator, 1251 const u8 *secret, size_t secret_len, 1252 u8 *ebuf, size_t *elen) 1253 { 1254 int i, len, first = 1; 1255 u8 hash[MD5_MAC_LEN], saltbuf[2], *pos; 1256 const u8 *addr[3]; 1257 size_t _len[3]; 1258 1259 WPA_PUT_BE16(saltbuf, salt); 1260 1261 len = 1 + key_len; 1262 if (len & 0x0f) { 1263 len = (len & 0xf0) + 16; 1264 } 1265 os_memset(ebuf, 0, len); 1266 ebuf[0] = key_len; 1267 os_memcpy(ebuf + 1, key, key_len); 1268 1269 *elen = len; 1270 1271 pos = ebuf; 1272 while (len > 0) { 1273 /* b(1) = MD5(Secret + Request-Authenticator + Salt) 1274 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ 1275 addr[0] = secret; 1276 _len[0] = secret_len; 1277 if (first) { 1278 addr[1] = req_authenticator; 1279 _len[1] = MD5_MAC_LEN; 1280 addr[2] = saltbuf; 1281 _len[2] = sizeof(saltbuf); 1282 } else { 1283 addr[1] = pos - MD5_MAC_LEN; 1284 _len[1] = MD5_MAC_LEN; 1285 } 1286 if (md5_vector(first ? 3 : 2, addr, _len, hash) < 0) { 1287 wpa_printf(MSG_INFO, "RADIUS: MD5 not available"); 1288 return -1; 1289 } 1290 first = 0; 1291 1292 for (i = 0; i < MD5_MAC_LEN; i++) 1293 *pos++ ^= hash[i]; 1294 1295 len -= MD5_MAC_LEN; 1296 } 1297 1298 return 0; 1299 } 1300 1301 1302 struct radius_ms_mppe_keys * radius_msg_get_ms_keys(struct radius_msg * msg,struct radius_msg * sent_msg,const u8 * secret,size_t secret_len)1303 radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg, 1304 const u8 *secret, size_t secret_len) 1305 { 1306 u8 *key; 1307 size_t keylen; 1308 struct radius_ms_mppe_keys *keys; 1309 1310 if (msg == NULL || sent_msg == NULL) 1311 return NULL; 1312 1313 keys = os_zalloc(sizeof(*keys)); 1314 if (keys == NULL) 1315 return NULL; 1316 1317 key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, 1318 RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY, 1319 &keylen); 1320 if (key) { 1321 keys->send = decrypt_ms_key(key, keylen, 1322 sent_msg->hdr->authenticator, 1323 secret, secret_len, 1324 &keys->send_len); 1325 if (!keys->send) { 1326 wpa_printf(MSG_DEBUG, 1327 "RADIUS: Failed to decrypt send key"); 1328 } 1329 os_free(key); 1330 } 1331 1332 key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, 1333 RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY, 1334 &keylen); 1335 if (key) { 1336 keys->recv = decrypt_ms_key(key, keylen, 1337 sent_msg->hdr->authenticator, 1338 secret, secret_len, 1339 &keys->recv_len); 1340 if (!keys->recv) { 1341 wpa_printf(MSG_DEBUG, 1342 "RADIUS: Failed to decrypt recv key"); 1343 } 1344 os_free(key); 1345 } 1346 1347 return keys; 1348 } 1349 1350 1351 struct radius_ms_mppe_keys * radius_msg_get_cisco_keys(struct radius_msg * msg,struct radius_msg * sent_msg,const u8 * secret,size_t secret_len)1352 radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg, 1353 const u8 *secret, size_t secret_len) 1354 { 1355 u8 *key; 1356 size_t keylen; 1357 struct radius_ms_mppe_keys *keys; 1358 1359 if (msg == NULL || sent_msg == NULL) 1360 return NULL; 1361 1362 keys = os_zalloc(sizeof(*keys)); 1363 if (keys == NULL) 1364 return NULL; 1365 1366 key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO, 1367 RADIUS_CISCO_AV_PAIR, &keylen); 1368 if (key && keylen == 51 && 1369 os_memcmp(key, "leap:session-key=", 17) == 0) { 1370 keys->recv = decrypt_ms_key(key + 17, keylen - 17, 1371 sent_msg->hdr->authenticator, 1372 secret, secret_len, 1373 &keys->recv_len); 1374 } 1375 os_free(key); 1376 1377 return keys; 1378 } 1379 1380 radius_msg_add_mppe_keys(struct radius_msg * msg,const u8 * req_authenticator,const u8 * secret,size_t secret_len,const u8 * send_key,size_t send_key_len,const u8 * recv_key,size_t recv_key_len)1381 int radius_msg_add_mppe_keys(struct radius_msg *msg, 1382 const u8 *req_authenticator, 1383 const u8 *secret, size_t secret_len, 1384 const u8 *send_key, size_t send_key_len, 1385 const u8 *recv_key, size_t recv_key_len) 1386 { 1387 struct radius_attr_hdr *attr; 1388 u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT); 1389 u8 *buf; 1390 struct radius_attr_vendor *vhdr; 1391 u8 *pos; 1392 size_t elen; 1393 int hlen; 1394 u16 salt; 1395 1396 hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2; 1397 1398 /* MS-MPPE-Send-Key */ 1399 buf = os_malloc(hlen + send_key_len + 16); 1400 if (buf == NULL) { 1401 return 0; 1402 } 1403 pos = buf; 1404 os_memcpy(pos, &vendor_id, sizeof(vendor_id)); 1405 pos += sizeof(vendor_id); 1406 vhdr = (struct radius_attr_vendor *) pos; 1407 vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY; 1408 pos = (u8 *) (vhdr + 1); 1409 if (os_get_random((u8 *) &salt, sizeof(salt)) < 0) { 1410 os_free(buf); 1411 return 0; 1412 } 1413 salt |= 0x8000; 1414 WPA_PUT_BE16(pos, salt); 1415 pos += 2; 1416 if (encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, 1417 secret, secret_len, pos, &elen) < 0) 1418 return 0; 1419 vhdr->vendor_length = hlen + elen - sizeof(vendor_id); 1420 1421 attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 1422 buf, hlen + elen); 1423 os_free(buf); 1424 if (attr == NULL) { 1425 return 0; 1426 } 1427 1428 /* MS-MPPE-Recv-Key */ 1429 buf = os_malloc(hlen + recv_key_len + 16); 1430 if (buf == NULL) { 1431 return 0; 1432 } 1433 pos = buf; 1434 os_memcpy(pos, &vendor_id, sizeof(vendor_id)); 1435 pos += sizeof(vendor_id); 1436 vhdr = (struct radius_attr_vendor *) pos; 1437 vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY; 1438 pos = (u8 *) (vhdr + 1); 1439 salt ^= 1; 1440 WPA_PUT_BE16(pos, salt); 1441 pos += 2; 1442 if (encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, 1443 secret, secret_len, pos, &elen) < 0) 1444 return 0; 1445 vhdr->vendor_length = hlen + elen - sizeof(vendor_id); 1446 1447 attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 1448 buf, hlen + elen); 1449 os_free(buf); 1450 if (attr == NULL) { 1451 return 0; 1452 } 1453 1454 return 1; 1455 } 1456 1457 radius_msg_add_wfa(struct radius_msg * msg,u8 subtype,const u8 * data,size_t len)1458 int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data, 1459 size_t len) 1460 { 1461 struct radius_attr_hdr *attr; 1462 u8 *buf, *pos; 1463 size_t alen; 1464 1465 alen = 4 + 2 + len; 1466 buf = os_malloc(alen); 1467 if (buf == NULL) 1468 return 0; 1469 pos = buf; 1470 WPA_PUT_BE32(pos, RADIUS_VENDOR_ID_WFA); 1471 pos += 4; 1472 *pos++ = subtype; 1473 *pos++ = 2 + len; 1474 os_memcpy(pos, data, len); 1475 attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 1476 buf, alen); 1477 os_free(buf); 1478 if (attr == NULL) 1479 return 0; 1480 1481 return 1; 1482 } 1483 1484 radius_msg_add_ext_vs(struct radius_msg * msg,u16 type,u32 vendor_id,u8 vendor_type,const u8 * data,size_t len)1485 int radius_msg_add_ext_vs(struct radius_msg *msg, u16 type, u32 vendor_id, 1486 u8 vendor_type, const u8 *data, size_t len) 1487 { 1488 struct radius_attr_hdr *attr; 1489 u8 *buf, *pos; 1490 size_t alen; 1491 1492 alen = 4 + 1 + len; 1493 buf = os_malloc(alen); 1494 if (!buf) 1495 return 0; 1496 pos = buf; 1497 WPA_PUT_BE32(pos, vendor_id); 1498 pos += 4; 1499 *pos++ = vendor_type; 1500 os_memcpy(pos, data, len); 1501 attr = radius_msg_add_attr(msg, type, buf, alen); 1502 os_free(buf); 1503 return attr != NULL; 1504 } 1505 1506 radius_user_password_hide(struct radius_msg * msg,const u8 * data,size_t data_len,const u8 * secret,size_t secret_len,u8 * buf,size_t buf_len)1507 int radius_user_password_hide(struct radius_msg *msg, 1508 const u8 *data, size_t data_len, 1509 const u8 *secret, size_t secret_len, 1510 u8 *buf, size_t buf_len) 1511 { 1512 size_t padlen, i, pos; 1513 const u8 *addr[2]; 1514 size_t len[2]; 1515 u8 hash[16]; 1516 1517 if (data_len + 16 > buf_len) 1518 return -1; 1519 1520 os_memcpy(buf, data, data_len); 1521 1522 padlen = data_len % 16; 1523 if (padlen && data_len < buf_len) { 1524 padlen = 16 - padlen; 1525 os_memset(buf + data_len, 0, padlen); 1526 buf_len = data_len + padlen; 1527 } else { 1528 buf_len = data_len; 1529 } 1530 1531 addr[0] = secret; 1532 len[0] = secret_len; 1533 addr[1] = msg->hdr->authenticator; 1534 len[1] = 16; 1535 if (md5_vector(2, addr, len, hash) < 0) { 1536 wpa_printf(MSG_INFO, "RADIUS: MD5 not available"); 1537 return -1; 1538 } 1539 1540 for (i = 0; i < 16; i++) 1541 buf[i] ^= hash[i]; 1542 pos = 16; 1543 1544 while (pos < buf_len) { 1545 addr[0] = secret; 1546 len[0] = secret_len; 1547 addr[1] = &buf[pos - 16]; 1548 len[1] = 16; 1549 if (md5_vector(2, addr, len, hash) < 0) { 1550 wpa_printf(MSG_INFO, "RADIUS: MD5 not available"); 1551 return -1; 1552 } 1553 1554 for (i = 0; i < 16; i++) 1555 buf[pos + i] ^= hash[i]; 1556 1557 pos += 16; 1558 } 1559 1560 return buf_len; 1561 } 1562 1563 1564 /* Add User-Password attribute to a RADIUS message and encrypt it as specified 1565 * in RFC 2865, Chap. 5.2 */ 1566 struct radius_attr_hdr * radius_msg_add_attr_user_password(struct radius_msg * msg,const u8 * data,size_t data_len,const u8 * secret,size_t secret_len)1567 radius_msg_add_attr_user_password(struct radius_msg *msg, 1568 const u8 *data, size_t data_len, 1569 const u8 *secret, size_t secret_len) 1570 { 1571 u8 buf[128]; 1572 int res; 1573 1574 res = radius_user_password_hide(msg, data, data_len, 1575 secret, secret_len, buf, sizeof(buf)); 1576 if (res < 0) 1577 return NULL; 1578 1579 return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD, 1580 buf, res); 1581 } 1582 1583 radius_msg_get_attr(struct radius_msg * msg,u8 type,u8 * buf,size_t len)1584 int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len) 1585 { 1586 struct radius_attr_hdr *attr = NULL, *tmp; 1587 size_t i, dlen; 1588 1589 for (i = 0; i < msg->attr_used; i++) { 1590 tmp = radius_get_attr_hdr(msg, i); 1591 if (tmp->type == type) { 1592 attr = tmp; 1593 break; 1594 } 1595 } 1596 1597 if (!attr || attr->length < sizeof(*attr)) 1598 return -1; 1599 1600 dlen = attr->length - sizeof(*attr); 1601 if (buf) 1602 os_memcpy(buf, (attr + 1), dlen > len ? len : dlen); 1603 return dlen; 1604 } 1605 1606 radius_msg_get_attr_ptr(struct radius_msg * msg,u8 type,u8 ** buf,size_t * len,const u8 * start)1607 int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf, 1608 size_t *len, const u8 *start) 1609 { 1610 size_t i; 1611 struct radius_attr_hdr *attr = NULL, *tmp; 1612 1613 for (i = 0; i < msg->attr_used; i++) { 1614 tmp = radius_get_attr_hdr(msg, i); 1615 if (tmp->type == type && 1616 (start == NULL || (u8 *) tmp > start)) { 1617 attr = tmp; 1618 break; 1619 } 1620 } 1621 1622 if (!attr || attr->length < sizeof(*attr)) 1623 return -1; 1624 1625 *buf = (u8 *) (attr + 1); 1626 *len = attr->length - sizeof(*attr); 1627 return 0; 1628 } 1629 1630 radius_msg_count_attr(struct radius_msg * msg,u8 type,int min_len)1631 int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len) 1632 { 1633 size_t i; 1634 int count; 1635 1636 for (count = 0, i = 0; i < msg->attr_used; i++) { 1637 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 1638 if (attr->type == type && 1639 attr->length >= sizeof(struct radius_attr_hdr) + min_len) 1640 count++; 1641 } 1642 1643 return count; 1644 } 1645 1646 1647 struct radius_tunnel_attrs { 1648 int tag_used; 1649 int type; /* Tunnel-Type */ 1650 int medium_type; /* Tunnel-Medium-Type */ 1651 int vlanid; 1652 }; 1653 1654 cmp_int(const void * a,const void * b)1655 static int cmp_int(const void *a, const void *b) 1656 { 1657 int x, y; 1658 1659 x = *((int *) a); 1660 y = *((int *) b); 1661 return (x - y); 1662 } 1663 1664 1665 /** 1666 * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information 1667 * The k tagged vlans found are sorted by vlan_id and stored in the first k 1668 * items of tagged. 1669 * 1670 * @msg: RADIUS message 1671 * @untagged: Pointer to store untagged vid 1672 * @numtagged: Size of tagged 1673 * @tagged: Pointer to store tagged list 1674 * 1675 * Returns: 0 if neither tagged nor untagged configuration is found, 1 otherwise 1676 */ radius_msg_get_vlanid(struct radius_msg * msg,int * untagged,int numtagged,int * tagged)1677 int radius_msg_get_vlanid(struct radius_msg *msg, int *untagged, int numtagged, 1678 int *tagged) 1679 { 1680 struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun; 1681 size_t i; 1682 struct radius_attr_hdr *attr = NULL; 1683 const u8 *data; 1684 char buf[10]; 1685 size_t dlen; 1686 int j, taggedidx = 0, vlan_id; 1687 1688 os_memset(&tunnel, 0, sizeof(tunnel)); 1689 for (j = 0; j < numtagged; j++) 1690 tagged[j] = 0; 1691 *untagged = 0; 1692 1693 for (i = 0; i < msg->attr_used; i++) { 1694 attr = radius_get_attr_hdr(msg, i); 1695 if (attr->length < sizeof(*attr)) 1696 return -1; 1697 data = (const u8 *) (attr + 1); 1698 dlen = attr->length - sizeof(*attr); 1699 if (attr->length < 3) 1700 continue; 1701 if (data[0] >= RADIUS_TUNNEL_TAGS) 1702 tun = &tunnel[0]; 1703 else 1704 tun = &tunnel[data[0]]; 1705 1706 switch (attr->type) { 1707 case RADIUS_ATTR_TUNNEL_TYPE: 1708 if (attr->length != 6) 1709 break; 1710 tun->tag_used++; 1711 tun->type = WPA_GET_BE24(data + 1); 1712 break; 1713 case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE: 1714 if (attr->length != 6) 1715 break; 1716 tun->tag_used++; 1717 tun->medium_type = WPA_GET_BE24(data + 1); 1718 break; 1719 case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID: 1720 if (data[0] < RADIUS_TUNNEL_TAGS) { 1721 data++; 1722 dlen--; 1723 } 1724 if (dlen >= sizeof(buf)) 1725 break; 1726 os_memcpy(buf, data, dlen); 1727 buf[dlen] = '\0'; 1728 vlan_id = atoi(buf); 1729 if (vlan_id <= 0) 1730 break; 1731 tun->tag_used++; 1732 tun->vlanid = vlan_id; 1733 break; 1734 case RADIUS_ATTR_EGRESS_VLANID: /* RFC 4675 */ 1735 if (attr->length != 6) 1736 break; 1737 vlan_id = WPA_GET_BE24(data + 1); 1738 if (vlan_id <= 0) 1739 break; 1740 if (data[0] == 0x32) 1741 *untagged = vlan_id; 1742 else if (data[0] == 0x31 && tagged && 1743 taggedidx < numtagged) 1744 tagged[taggedidx++] = vlan_id; 1745 break; 1746 } 1747 } 1748 1749 /* Use tunnel with the lowest tag for untagged VLAN id */ 1750 for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) { 1751 tun = &tunnel[i]; 1752 if (tun->tag_used && 1753 tun->type == RADIUS_TUNNEL_TYPE_VLAN && 1754 tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 && 1755 tun->vlanid > 0) { 1756 *untagged = tun->vlanid; 1757 break; 1758 } 1759 } 1760 1761 if (taggedidx) 1762 qsort(tagged, taggedidx, sizeof(int), cmp_int); 1763 1764 if (*untagged > 0 || taggedidx) 1765 return 1; 1766 return 0; 1767 } 1768 1769 1770 /** 1771 * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password 1772 * @msg: Received RADIUS message 1773 * @keylen: Length of returned password 1774 * @secret: RADIUS shared secret 1775 * @secret_len: Length of secret 1776 * @sent_msg: Sent RADIUS message 1777 * @n: Number of password attribute to return (starting with 0) 1778 * Returns: Pointer to n-th password (free with os_free) or %NULL 1779 */ radius_msg_get_tunnel_password(struct radius_msg * msg,int * keylen,const u8 * secret,size_t secret_len,struct radius_msg * sent_msg,size_t n)1780 char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen, 1781 const u8 *secret, size_t secret_len, 1782 struct radius_msg *sent_msg, size_t n) 1783 { 1784 u8 *buf = NULL; 1785 size_t buflen; 1786 const u8 *salt; 1787 u8 *str; 1788 const u8 *addr[3]; 1789 size_t len[3]; 1790 u8 hash[16]; 1791 u8 *pos; 1792 size_t i, j = 0; 1793 struct radius_attr_hdr *attr; 1794 const u8 *data; 1795 size_t dlen; 1796 const u8 *fdata = NULL; /* points to found item */ 1797 size_t fdlen = -1; 1798 char *ret = NULL; 1799 1800 /* find n-th valid Tunnel-Password attribute */ 1801 for (i = 0; i < msg->attr_used; i++) { 1802 attr = radius_get_attr_hdr(msg, i); 1803 if (attr == NULL || 1804 attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) { 1805 continue; 1806 } 1807 if (attr->length <= 5) 1808 continue; 1809 data = (const u8 *) (attr + 1); 1810 dlen = attr->length - sizeof(*attr); 1811 if (dlen <= 3 || dlen % 16 != 3) 1812 continue; 1813 j++; 1814 if (j <= n) 1815 continue; 1816 1817 fdata = data; 1818 fdlen = dlen; 1819 break; 1820 } 1821 if (fdata == NULL) 1822 goto out; 1823 1824 /* alloc writable memory for decryption */ 1825 buf = os_memdup(fdata, fdlen); 1826 if (buf == NULL) 1827 goto out; 1828 buflen = fdlen; 1829 1830 /* init pointers */ 1831 salt = buf + 1; 1832 str = buf + 3; 1833 1834 /* decrypt blocks */ 1835 pos = buf + buflen - 16; /* last block */ 1836 while (pos >= str + 16) { /* all but the first block */ 1837 addr[0] = secret; 1838 len[0] = secret_len; 1839 addr[1] = pos - 16; 1840 len[1] = 16; 1841 if (md5_vector(2, addr, len, hash) < 0) { 1842 wpa_printf(MSG_INFO, "RADIUS: MD5 not available"); 1843 goto out; 1844 } 1845 1846 for (i = 0; i < 16; i++) 1847 pos[i] ^= hash[i]; 1848 1849 pos -= 16; 1850 } 1851 1852 /* decrypt first block */ 1853 if (str != pos) 1854 goto out; 1855 addr[0] = secret; 1856 len[0] = secret_len; 1857 addr[1] = sent_msg->hdr->authenticator; 1858 len[1] = 16; 1859 addr[2] = salt; 1860 len[2] = 2; 1861 if (md5_vector(3, addr, len, hash) < 0) { 1862 wpa_printf(MSG_INFO, "RADIUS: MD5 not available"); 1863 goto out; 1864 } 1865 1866 for (i = 0; i < 16; i++) 1867 pos[i] ^= hash[i]; 1868 1869 /* derive plaintext length from first subfield */ 1870 *keylen = (unsigned char) str[0]; 1871 if ((u8 *) (str + *keylen) >= (u8 *) (buf + buflen)) { 1872 /* decryption error - invalid key length */ 1873 goto out; 1874 } 1875 if (*keylen == 0) { 1876 /* empty password */ 1877 goto out; 1878 } 1879 1880 /* copy passphrase into new buffer */ 1881 ret = os_malloc(*keylen); 1882 if (ret) 1883 os_memcpy(ret, str + 1, *keylen); 1884 1885 out: 1886 /* return new buffer */ 1887 os_free(buf); 1888 return ret; 1889 } 1890 1891 radius_free_class(struct radius_class_data * c)1892 void radius_free_class(struct radius_class_data *c) 1893 { 1894 size_t i; 1895 if (c == NULL) 1896 return; 1897 for (i = 0; i < c->count; i++) 1898 os_free(c->attr[i].data); 1899 os_free(c->attr); 1900 c->attr = NULL; 1901 c->count = 0; 1902 } 1903 1904 radius_copy_class(struct radius_class_data * dst,const struct radius_class_data * src)1905 int radius_copy_class(struct radius_class_data *dst, 1906 const struct radius_class_data *src) 1907 { 1908 size_t i; 1909 1910 if (src->attr == NULL) 1911 return 0; 1912 1913 dst->attr = os_calloc(src->count, sizeof(struct radius_attr_data)); 1914 if (dst->attr == NULL) 1915 return -1; 1916 1917 dst->count = 0; 1918 1919 for (i = 0; i < src->count; i++) { 1920 dst->attr[i].data = os_memdup(src->attr[i].data, 1921 src->attr[i].len); 1922 if (dst->attr[i].data == NULL) 1923 break; 1924 dst->count++; 1925 dst->attr[i].len = src->attr[i].len; 1926 } 1927 1928 return 0; 1929 } 1930 1931 radius_msg_find_unlisted_attr(struct radius_msg * msg,u8 * attrs)1932 u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs) 1933 { 1934 size_t i, j; 1935 struct radius_attr_hdr *attr; 1936 1937 for (i = 0; i < msg->attr_used; i++) { 1938 attr = radius_get_attr_hdr(msg, i); 1939 1940 for (j = 0; attrs[j]; j++) { 1941 if (attr->type == attrs[j]) 1942 break; 1943 } 1944 1945 if (attrs[j] == 0) 1946 return attr->type; /* unlisted attr */ 1947 } 1948 1949 return 0; 1950 } 1951 1952 radius_gen_session_id(u8 * id,size_t len)1953 int radius_gen_session_id(u8 *id, size_t len) 1954 { 1955 /* 1956 * Acct-Session-Id and Acct-Multi-Session-Id should be globally and 1957 * temporarily unique. A high quality random number is required 1958 * therefore. This could be be improved by switching to a GUID. 1959 */ 1960 return os_get_random(id, len); 1961 } 1962