radius.c revision f21452aea786ac056eb01f1cbba4f553bd502747
1/* 2 * RADIUS message processing 3 * Copyright (c) 2002-2009, 2011-2014, 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 */ 21struct 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 52struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg) 53{ 54 return msg->hdr; 55} 56 57 58struct wpabuf * radius_msg_get_buf(struct radius_msg *msg) 59{ 60 return msg->buf; 61} 62 63 64static struct radius_attr_hdr * 65radius_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 72static 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 79static 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 */ 102struct 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 */ 127void 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 138static 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 161struct radius_attr_type { 162 u8 type; 163 char *name; 164 enum { 165 RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP, 166 RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6 167 } data_type; 168}; 169 170static struct radius_attr_type radius_attrs[] = 171{ 172 { RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT }, 173 { RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST }, 174 { RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP }, 175 { RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 }, 176 { RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 }, 177 { RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT }, 178 { RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST }, 179 { RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST }, 180 { RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST }, 181 { RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 }, 182 { RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 }, 183 { RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action", 184 RADIUS_ATTR_INT32 }, 185 { RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id", 186 RADIUS_ATTR_TEXT }, 187 { RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id", 188 RADIUS_ATTR_TEXT }, 189 { RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT }, 190 { RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST }, 191 { RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type", 192 RADIUS_ATTR_INT32 }, 193 { RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 }, 194 { RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets", 195 RADIUS_ATTR_INT32 }, 196 { RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets", 197 RADIUS_ATTR_INT32 }, 198 { RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT }, 199 { RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 }, 200 { RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time", 201 RADIUS_ATTR_INT32 }, 202 { RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets", 203 RADIUS_ATTR_INT32 }, 204 { RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets", 205 RADIUS_ATTR_INT32 }, 206 { RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause", 207 RADIUS_ATTR_INT32 }, 208 { RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id", 209 RADIUS_ATTR_TEXT }, 210 { RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 }, 211 { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords", 212 RADIUS_ATTR_INT32 }, 213 { RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords", 214 RADIUS_ATTR_INT32 }, 215 { RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp", 216 RADIUS_ATTR_INT32 }, 217 { RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 }, 218 { RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP }, 219 { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type", 220 RADIUS_ATTR_HEXDUMP }, 221 { RADIUS_ATTR_TUNNEL_PASSWORD, "Tunnel-Password", 222 RADIUS_ATTR_UNDIST }, 223 { RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT }, 224 { RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST }, 225 { RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator", 226 RADIUS_ATTR_UNDIST }, 227 { RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id", 228 RADIUS_ATTR_HEXDUMP }, 229 { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval", 230 RADIUS_ATTR_INT32 }, 231 { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity", 232 RADIUS_ATTR_TEXT }, 233 { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 }, 234 { RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 } 235}; 236#define RADIUS_ATTRS ARRAY_SIZE(radius_attrs) 237 238 239static struct radius_attr_type *radius_get_attr_type(u8 type) 240{ 241 size_t i; 242 243 for (i = 0; i < RADIUS_ATTRS; i++) { 244 if (type == radius_attrs[i].type) 245 return &radius_attrs[i]; 246 } 247 248 return NULL; 249} 250 251 252static void radius_msg_dump_attr(struct radius_attr_hdr *hdr) 253{ 254 struct radius_attr_type *attr; 255 int len; 256 unsigned char *pos; 257 char buf[1000]; 258 259 attr = radius_get_attr_type(hdr->type); 260 261 wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d", 262 hdr->type, attr ? attr->name : "?Unknown?", hdr->length); 263 264 if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr)) 265 return; 266 267 len = hdr->length - sizeof(struct radius_attr_hdr); 268 pos = (unsigned char *) (hdr + 1); 269 270 switch (attr->data_type) { 271 case RADIUS_ATTR_TEXT: 272 printf_encode(buf, sizeof(buf), pos, len); 273 wpa_printf(MSG_INFO, " Value: '%s'", buf); 274 break; 275 276 case RADIUS_ATTR_IP: 277 if (len == 4) { 278 struct in_addr addr; 279 os_memcpy(&addr, pos, 4); 280 wpa_printf(MSG_INFO, " Value: %s", 281 inet_ntoa(addr)); 282 } else { 283 wpa_printf(MSG_INFO, " Invalid IP address length %d", 284 len); 285 } 286 break; 287 288#ifdef CONFIG_IPV6 289 case RADIUS_ATTR_IPV6: 290 if (len == 16) { 291 const char *atxt; 292 struct in6_addr *addr = (struct in6_addr *) pos; 293 atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf)); 294 wpa_printf(MSG_INFO, " Value: %s", 295 atxt ? atxt : "?"); 296 } else { 297 wpa_printf(MSG_INFO, " Invalid IPv6 address length %d", 298 len); 299 } 300 break; 301#endif /* CONFIG_IPV6 */ 302 303 case RADIUS_ATTR_HEXDUMP: 304 case RADIUS_ATTR_UNDIST: 305 wpa_snprintf_hex(buf, sizeof(buf), pos, len); 306 wpa_printf(MSG_INFO, " Value: %s", buf); 307 break; 308 309 case RADIUS_ATTR_INT32: 310 if (len == 4) 311 wpa_printf(MSG_INFO, " Value: %u", 312 WPA_GET_BE32(pos)); 313 else 314 wpa_printf(MSG_INFO, " Invalid INT32 length %d", 315 len); 316 break; 317 318 default: 319 break; 320 } 321} 322 323 324void radius_msg_dump(struct radius_msg *msg) 325{ 326 size_t i; 327 328 wpa_printf(MSG_INFO, "RADIUS message: code=%d (%s) identifier=%d length=%d", 329 msg->hdr->code, radius_code_string(msg->hdr->code), 330 msg->hdr->identifier, be_to_host16(msg->hdr->length)); 331 332 for (i = 0; i < msg->attr_used; i++) { 333 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 334 radius_msg_dump_attr(attr); 335 } 336} 337 338 339int radius_msg_finish(struct radius_msg *msg, const u8 *secret, 340 size_t secret_len) 341{ 342 if (secret) { 343 u8 auth[MD5_MAC_LEN]; 344 struct radius_attr_hdr *attr; 345 346 os_memset(auth, 0, MD5_MAC_LEN); 347 attr = radius_msg_add_attr(msg, 348 RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 349 auth, MD5_MAC_LEN); 350 if (attr == NULL) { 351 wpa_printf(MSG_WARNING, "RADIUS: Could not add " 352 "Message-Authenticator"); 353 return -1; 354 } 355 msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 356 hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 357 wpabuf_len(msg->buf), (u8 *) (attr + 1)); 358 } else 359 msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 360 361 if (wpabuf_len(msg->buf) > 0xffff) { 362 wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 363 (unsigned long) wpabuf_len(msg->buf)); 364 return -1; 365 } 366 return 0; 367} 368 369 370int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, 371 size_t secret_len, const u8 *req_authenticator) 372{ 373 u8 auth[MD5_MAC_LEN]; 374 struct radius_attr_hdr *attr; 375 const u8 *addr[4]; 376 size_t len[4]; 377 378 os_memset(auth, 0, MD5_MAC_LEN); 379 attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 380 auth, MD5_MAC_LEN); 381 if (attr == NULL) { 382 wpa_printf(MSG_ERROR, "WARNING: Could not add Message-Authenticator"); 383 return -1; 384 } 385 msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 386 os_memcpy(msg->hdr->authenticator, req_authenticator, 387 sizeof(msg->hdr->authenticator)); 388 hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 389 wpabuf_len(msg->buf), (u8 *) (attr + 1)); 390 391 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 392 addr[0] = (u8 *) msg->hdr; 393 len[0] = 1 + 1 + 2; 394 addr[1] = req_authenticator; 395 len[1] = MD5_MAC_LEN; 396 addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); 397 len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 398 addr[3] = secret; 399 len[3] = secret_len; 400 md5_vector(4, addr, len, msg->hdr->authenticator); 401 402 if (wpabuf_len(msg->buf) > 0xffff) { 403 wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 404 (unsigned long) wpabuf_len(msg->buf)); 405 return -1; 406 } 407 return 0; 408} 409 410 411int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret, 412 size_t secret_len, 413 const struct radius_hdr *req_hdr) 414{ 415 const u8 *addr[2]; 416 size_t len[2]; 417 u8 auth[MD5_MAC_LEN]; 418 struct radius_attr_hdr *attr; 419 420 os_memset(auth, 0, MD5_MAC_LEN); 421 attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 422 auth, MD5_MAC_LEN); 423 if (attr == NULL) { 424 wpa_printf(MSG_WARNING, "Could not add Message-Authenticator"); 425 return -1; 426 } 427 428 msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 429 os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16); 430 hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 431 wpabuf_len(msg->buf), (u8 *) (attr + 1)); 432 433 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 434 addr[0] = wpabuf_head_u8(msg->buf); 435 len[0] = wpabuf_len(msg->buf); 436 addr[1] = secret; 437 len[1] = secret_len; 438 if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0) 439 return -1; 440 441 if (wpabuf_len(msg->buf) > 0xffff) { 442 wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 443 (unsigned long) wpabuf_len(msg->buf)); 444 return -1; 445 } 446 return 0; 447} 448 449 450void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret, 451 size_t secret_len) 452{ 453 const u8 *addr[2]; 454 size_t len[2]; 455 456 msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 457 os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN); 458 addr[0] = wpabuf_head(msg->buf); 459 len[0] = wpabuf_len(msg->buf); 460 addr[1] = secret; 461 len[1] = secret_len; 462 md5_vector(2, addr, len, msg->hdr->authenticator); 463 464 if (wpabuf_len(msg->buf) > 0xffff) { 465 wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)", 466 (unsigned long) wpabuf_len(msg->buf)); 467 } 468} 469 470 471void radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret, 472 size_t secret_len, const u8 *req_authenticator) 473{ 474 const u8 *addr[2]; 475 size_t len[2]; 476 477 msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); 478 os_memcpy(msg->hdr->authenticator, req_authenticator, MD5_MAC_LEN); 479 addr[0] = wpabuf_head(msg->buf); 480 len[0] = wpabuf_len(msg->buf); 481 addr[1] = secret; 482 len[1] = secret_len; 483 md5_vector(2, addr, len, msg->hdr->authenticator); 484 485 if (wpabuf_len(msg->buf) > 0xffff) { 486 wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)", 487 (unsigned long) wpabuf_len(msg->buf)); 488 } 489} 490 491 492int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret, 493 size_t secret_len) 494{ 495 const u8 *addr[4]; 496 size_t len[4]; 497 u8 zero[MD5_MAC_LEN]; 498 u8 hash[MD5_MAC_LEN]; 499 500 os_memset(zero, 0, sizeof(zero)); 501 addr[0] = (u8 *) msg->hdr; 502 len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN; 503 addr[1] = zero; 504 len[1] = MD5_MAC_LEN; 505 addr[2] = (u8 *) (msg->hdr + 1); 506 len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 507 addr[3] = secret; 508 len[3] = secret_len; 509 md5_vector(4, addr, len, hash); 510 return os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0; 511} 512 513 514int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret, 515 size_t secret_len) 516{ 517 const u8 *addr[4]; 518 size_t len[4]; 519 u8 zero[MD5_MAC_LEN]; 520 u8 hash[MD5_MAC_LEN]; 521 u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN]; 522 u8 orig_authenticator[16]; 523 524 struct radius_attr_hdr *attr = NULL, *tmp; 525 size_t i; 526 527 os_memset(zero, 0, sizeof(zero)); 528 addr[0] = (u8 *) msg->hdr; 529 len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN; 530 addr[1] = zero; 531 len[1] = MD5_MAC_LEN; 532 addr[2] = (u8 *) (msg->hdr + 1); 533 len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 534 addr[3] = secret; 535 len[3] = secret_len; 536 md5_vector(4, addr, len, hash); 537 if (os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0) 538 return 1; 539 540 for (i = 0; i < msg->attr_used; i++) { 541 tmp = radius_get_attr_hdr(msg, i); 542 if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) { 543 if (attr != NULL) { 544 wpa_printf(MSG_WARNING, "Multiple " 545 "Message-Authenticator attributes " 546 "in RADIUS message"); 547 return 1; 548 } 549 attr = tmp; 550 } 551 } 552 553 if (attr == NULL) { 554 /* Message-Authenticator is MAY; not required */ 555 return 0; 556 } 557 558 os_memcpy(orig, attr + 1, MD5_MAC_LEN); 559 os_memset(attr + 1, 0, MD5_MAC_LEN); 560 os_memcpy(orig_authenticator, msg->hdr->authenticator, 561 sizeof(orig_authenticator)); 562 os_memset(msg->hdr->authenticator, 0, 563 sizeof(msg->hdr->authenticator)); 564 hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 565 wpabuf_len(msg->buf), auth); 566 os_memcpy(attr + 1, orig, MD5_MAC_LEN); 567 os_memcpy(msg->hdr->authenticator, orig_authenticator, 568 sizeof(orig_authenticator)); 569 570 return os_memcmp(orig, auth, MD5_MAC_LEN) != 0; 571} 572 573 574static int radius_msg_add_attr_to_array(struct radius_msg *msg, 575 struct radius_attr_hdr *attr) 576{ 577 if (msg->attr_used >= msg->attr_size) { 578 size_t *nattr_pos; 579 int nlen = msg->attr_size * 2; 580 581 nattr_pos = os_realloc_array(msg->attr_pos, nlen, 582 sizeof(*msg->attr_pos)); 583 if (nattr_pos == NULL) 584 return -1; 585 586 msg->attr_pos = nattr_pos; 587 msg->attr_size = nlen; 588 } 589 590 msg->attr_pos[msg->attr_used++] = 591 (unsigned char *) attr - wpabuf_head_u8(msg->buf); 592 593 return 0; 594} 595 596 597struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, 598 const u8 *data, size_t data_len) 599{ 600 size_t buf_needed; 601 struct radius_attr_hdr *attr; 602 603 if (data_len > RADIUS_MAX_ATTR_LEN) { 604 wpa_printf(MSG_ERROR, "radius_msg_add_attr: too long attribute (%lu bytes)", 605 (unsigned long) data_len); 606 return NULL; 607 } 608 609 buf_needed = sizeof(*attr) + data_len; 610 611 if (wpabuf_tailroom(msg->buf) < buf_needed) { 612 /* allocate more space for message buffer */ 613 if (wpabuf_resize(&msg->buf, buf_needed) < 0) 614 return NULL; 615 msg->hdr = wpabuf_mhead(msg->buf); 616 } 617 618 attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr)); 619 attr->type = type; 620 attr->length = sizeof(*attr) + data_len; 621 wpabuf_put_data(msg->buf, data, data_len); 622 623 if (radius_msg_add_attr_to_array(msg, attr)) 624 return NULL; 625 626 return attr; 627} 628 629 630/** 631 * radius_msg_parse - Parse a RADIUS message 632 * @data: RADIUS message to be parsed 633 * @len: Length of data buffer in octets 634 * Returns: Parsed RADIUS message or %NULL on failure 635 * 636 * This parses a RADIUS message and makes a copy of its data. The caller is 637 * responsible for freeing the returned data with radius_msg_free(). 638 */ 639struct radius_msg * radius_msg_parse(const u8 *data, size_t len) 640{ 641 struct radius_msg *msg; 642 struct radius_hdr *hdr; 643 struct radius_attr_hdr *attr; 644 size_t msg_len; 645 unsigned char *pos, *end; 646 647 if (data == NULL || len < sizeof(*hdr)) 648 return NULL; 649 650 hdr = (struct radius_hdr *) data; 651 652 msg_len = be_to_host16(hdr->length); 653 if (msg_len < sizeof(*hdr) || msg_len > len) { 654 wpa_printf(MSG_INFO, "RADIUS: Invalid message length"); 655 return NULL; 656 } 657 658 if (msg_len < len) { 659 wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after " 660 "RADIUS message", (unsigned long) len - msg_len); 661 } 662 663 msg = os_zalloc(sizeof(*msg)); 664 if (msg == NULL) 665 return NULL; 666 667 msg->buf = wpabuf_alloc_copy(data, msg_len); 668 if (msg->buf == NULL || radius_msg_initialize(msg)) { 669 radius_msg_free(msg); 670 return NULL; 671 } 672 msg->hdr = wpabuf_mhead(msg->buf); 673 674 /* parse attributes */ 675 pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr); 676 end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf); 677 while (pos < end) { 678 if ((size_t) (end - pos) < sizeof(*attr)) 679 goto fail; 680 681 attr = (struct radius_attr_hdr *) pos; 682 683 if (pos + attr->length > end || attr->length < sizeof(*attr)) 684 goto fail; 685 686 /* TODO: check that attr->length is suitable for attr->type */ 687 688 if (radius_msg_add_attr_to_array(msg, attr)) 689 goto fail; 690 691 pos += attr->length; 692 } 693 694 return msg; 695 696 fail: 697 radius_msg_free(msg); 698 return NULL; 699} 700 701 702int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len) 703{ 704 const u8 *pos = data; 705 size_t left = data_len; 706 707 while (left > 0) { 708 int len; 709 if (left > RADIUS_MAX_ATTR_LEN) 710 len = RADIUS_MAX_ATTR_LEN; 711 else 712 len = left; 713 714 if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE, 715 pos, len)) 716 return 0; 717 718 pos += len; 719 left -= len; 720 } 721 722 return 1; 723} 724 725 726struct wpabuf * radius_msg_get_eap(struct radius_msg *msg) 727{ 728 struct wpabuf *eap; 729 size_t len, i; 730 struct radius_attr_hdr *attr; 731 732 if (msg == NULL) 733 return NULL; 734 735 len = 0; 736 for (i = 0; i < msg->attr_used; i++) { 737 attr = radius_get_attr_hdr(msg, i); 738 if (attr->type == RADIUS_ATTR_EAP_MESSAGE && 739 attr->length > sizeof(struct radius_attr_hdr)) 740 len += attr->length - sizeof(struct radius_attr_hdr); 741 } 742 743 if (len == 0) 744 return NULL; 745 746 eap = wpabuf_alloc(len); 747 if (eap == NULL) 748 return NULL; 749 750 for (i = 0; i < msg->attr_used; i++) { 751 attr = radius_get_attr_hdr(msg, i); 752 if (attr->type == RADIUS_ATTR_EAP_MESSAGE && 753 attr->length > sizeof(struct radius_attr_hdr)) { 754 int flen = attr->length - sizeof(*attr); 755 wpabuf_put_data(eap, attr + 1, flen); 756 } 757 } 758 759 return eap; 760} 761 762 763int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, 764 size_t secret_len, const u8 *req_auth) 765{ 766 u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN]; 767 u8 orig_authenticator[16]; 768 struct radius_attr_hdr *attr = NULL, *tmp; 769 size_t i; 770 771 for (i = 0; i < msg->attr_used; i++) { 772 tmp = radius_get_attr_hdr(msg, i); 773 if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) { 774 if (attr != NULL) { 775 wpa_printf(MSG_INFO, "Multiple Message-Authenticator attributes in RADIUS message"); 776 return 1; 777 } 778 attr = tmp; 779 } 780 } 781 782 if (attr == NULL) { 783 wpa_printf(MSG_INFO, "No Message-Authenticator attribute found"); 784 return 1; 785 } 786 787 os_memcpy(orig, attr + 1, MD5_MAC_LEN); 788 os_memset(attr + 1, 0, MD5_MAC_LEN); 789 if (req_auth) { 790 os_memcpy(orig_authenticator, msg->hdr->authenticator, 791 sizeof(orig_authenticator)); 792 os_memcpy(msg->hdr->authenticator, req_auth, 793 sizeof(msg->hdr->authenticator)); 794 } 795 hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 796 wpabuf_len(msg->buf), auth); 797 os_memcpy(attr + 1, orig, MD5_MAC_LEN); 798 if (req_auth) { 799 os_memcpy(msg->hdr->authenticator, orig_authenticator, 800 sizeof(orig_authenticator)); 801 } 802 803 if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) { 804 wpa_printf(MSG_INFO, "Invalid Message-Authenticator!"); 805 return 1; 806 } 807 808 return 0; 809} 810 811 812int radius_msg_verify(struct radius_msg *msg, const u8 *secret, 813 size_t secret_len, struct radius_msg *sent_msg, int auth) 814{ 815 const u8 *addr[4]; 816 size_t len[4]; 817 u8 hash[MD5_MAC_LEN]; 818 819 if (sent_msg == NULL) { 820 wpa_printf(MSG_INFO, "No matching Access-Request message found"); 821 return 1; 822 } 823 824 if (auth && 825 radius_msg_verify_msg_auth(msg, secret, secret_len, 826 sent_msg->hdr->authenticator)) { 827 return 1; 828 } 829 830 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 831 addr[0] = (u8 *) msg->hdr; 832 len[0] = 1 + 1 + 2; 833 addr[1] = sent_msg->hdr->authenticator; 834 len[1] = MD5_MAC_LEN; 835 addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); 836 len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 837 addr[3] = secret; 838 len[3] = secret_len; 839 md5_vector(4, addr, len, hash); 840 if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) { 841 wpa_printf(MSG_INFO, "Response Authenticator invalid!"); 842 return 1; 843 } 844 845 return 0; 846} 847 848 849int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src, 850 u8 type) 851{ 852 struct radius_attr_hdr *attr; 853 size_t i; 854 int count = 0; 855 856 for (i = 0; i < src->attr_used; i++) { 857 attr = radius_get_attr_hdr(src, i); 858 if (attr->type == type && attr->length >= sizeof(*attr)) { 859 if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1), 860 attr->length - sizeof(*attr))) 861 return -1; 862 count++; 863 } 864 } 865 866 return count; 867} 868 869 870/* Create Request Authenticator. The value should be unique over the lifetime 871 * of the shared secret between authenticator and authentication server. 872 * Use one-way MD5 hash calculated from current timestamp and some data given 873 * by the caller. */ 874void radius_msg_make_authenticator(struct radius_msg *msg, 875 const u8 *data, size_t len) 876{ 877 struct os_time tv; 878 long int l; 879 const u8 *addr[3]; 880 size_t elen[3]; 881 882 os_get_time(&tv); 883 l = os_random(); 884 addr[0] = (u8 *) &tv; 885 elen[0] = sizeof(tv); 886 addr[1] = data; 887 elen[1] = len; 888 addr[2] = (u8 *) &l; 889 elen[2] = sizeof(l); 890 md5_vector(3, addr, elen, msg->hdr->authenticator); 891} 892 893 894/* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message. 895 * Returns the Attribute payload and sets alen to indicate the length of the 896 * payload if a vendor attribute with subtype is found, otherwise returns NULL. 897 * The returned payload is allocated with os_malloc() and caller must free it 898 * by calling os_free(). 899 */ 900static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor, 901 u8 subtype, size_t *alen) 902{ 903 u8 *data, *pos; 904 size_t i, len; 905 906 if (msg == NULL) 907 return NULL; 908 909 for (i = 0; i < msg->attr_used; i++) { 910 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 911 size_t left; 912 u32 vendor_id; 913 struct radius_attr_vendor *vhdr; 914 915 if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC || 916 attr->length < sizeof(*attr)) 917 continue; 918 919 left = attr->length - sizeof(*attr); 920 if (left < 4) 921 continue; 922 923 pos = (u8 *) (attr + 1); 924 925 os_memcpy(&vendor_id, pos, 4); 926 pos += 4; 927 left -= 4; 928 929 if (ntohl(vendor_id) != vendor) 930 continue; 931 932 while (left >= sizeof(*vhdr)) { 933 vhdr = (struct radius_attr_vendor *) pos; 934 if (vhdr->vendor_length > left || 935 vhdr->vendor_length < sizeof(*vhdr)) { 936 left = 0; 937 break; 938 } 939 if (vhdr->vendor_type != subtype) { 940 pos += vhdr->vendor_length; 941 left -= vhdr->vendor_length; 942 continue; 943 } 944 945 len = vhdr->vendor_length - sizeof(*vhdr); 946 data = os_malloc(len); 947 if (data == NULL) 948 return NULL; 949 os_memcpy(data, pos + sizeof(*vhdr), len); 950 if (alen) 951 *alen = len; 952 return data; 953 } 954 } 955 956 return NULL; 957} 958 959 960static u8 * decrypt_ms_key(const u8 *key, size_t len, 961 const u8 *req_authenticator, 962 const u8 *secret, size_t secret_len, size_t *reslen) 963{ 964 u8 *plain, *ppos, *res; 965 const u8 *pos; 966 size_t left, plen; 967 u8 hash[MD5_MAC_LEN]; 968 int i, first = 1; 969 const u8 *addr[3]; 970 size_t elen[3]; 971 972 /* key: 16-bit salt followed by encrypted key info */ 973 974 if (len < 2 + 16) 975 return NULL; 976 977 pos = key + 2; 978 left = len - 2; 979 if (left % 16) { 980 wpa_printf(MSG_INFO, "Invalid ms key len %lu", 981 (unsigned long) left); 982 return NULL; 983 } 984 985 plen = left; 986 ppos = plain = os_malloc(plen); 987 if (plain == NULL) 988 return NULL; 989 plain[0] = 0; 990 991 while (left > 0) { 992 /* b(1) = MD5(Secret + Request-Authenticator + Salt) 993 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ 994 995 addr[0] = secret; 996 elen[0] = secret_len; 997 if (first) { 998 addr[1] = req_authenticator; 999 elen[1] = MD5_MAC_LEN; 1000 addr[2] = key; 1001 elen[2] = 2; /* Salt */ 1002 } else { 1003 addr[1] = pos - MD5_MAC_LEN; 1004 elen[1] = MD5_MAC_LEN; 1005 } 1006 md5_vector(first ? 3 : 2, addr, elen, hash); 1007 first = 0; 1008 1009 for (i = 0; i < MD5_MAC_LEN; i++) 1010 *ppos++ = *pos++ ^ hash[i]; 1011 left -= MD5_MAC_LEN; 1012 } 1013 1014 if (plain[0] == 0 || plain[0] > plen - 1) { 1015 wpa_printf(MSG_INFO, "Failed to decrypt MPPE key"); 1016 os_free(plain); 1017 return NULL; 1018 } 1019 1020 res = os_malloc(plain[0]); 1021 if (res == NULL) { 1022 os_free(plain); 1023 return NULL; 1024 } 1025 os_memcpy(res, plain + 1, plain[0]); 1026 if (reslen) 1027 *reslen = plain[0]; 1028 os_free(plain); 1029 return res; 1030} 1031 1032 1033static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt, 1034 const u8 *req_authenticator, 1035 const u8 *secret, size_t secret_len, 1036 u8 *ebuf, size_t *elen) 1037{ 1038 int i, len, first = 1; 1039 u8 hash[MD5_MAC_LEN], saltbuf[2], *pos; 1040 const u8 *addr[3]; 1041 size_t _len[3]; 1042 1043 WPA_PUT_BE16(saltbuf, salt); 1044 1045 len = 1 + key_len; 1046 if (len & 0x0f) { 1047 len = (len & 0xf0) + 16; 1048 } 1049 os_memset(ebuf, 0, len); 1050 ebuf[0] = key_len; 1051 os_memcpy(ebuf + 1, key, key_len); 1052 1053 *elen = len; 1054 1055 pos = ebuf; 1056 while (len > 0) { 1057 /* b(1) = MD5(Secret + Request-Authenticator + Salt) 1058 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ 1059 addr[0] = secret; 1060 _len[0] = secret_len; 1061 if (first) { 1062 addr[1] = req_authenticator; 1063 _len[1] = MD5_MAC_LEN; 1064 addr[2] = saltbuf; 1065 _len[2] = sizeof(saltbuf); 1066 } else { 1067 addr[1] = pos - MD5_MAC_LEN; 1068 _len[1] = MD5_MAC_LEN; 1069 } 1070 md5_vector(first ? 3 : 2, addr, _len, hash); 1071 first = 0; 1072 1073 for (i = 0; i < MD5_MAC_LEN; i++) 1074 *pos++ ^= hash[i]; 1075 1076 len -= MD5_MAC_LEN; 1077 } 1078} 1079 1080 1081struct radius_ms_mppe_keys * 1082radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg, 1083 const u8 *secret, size_t secret_len) 1084{ 1085 u8 *key; 1086 size_t keylen; 1087 struct radius_ms_mppe_keys *keys; 1088 1089 if (msg == NULL || sent_msg == NULL) 1090 return NULL; 1091 1092 keys = os_zalloc(sizeof(*keys)); 1093 if (keys == NULL) 1094 return NULL; 1095 1096 key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, 1097 RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY, 1098 &keylen); 1099 if (key) { 1100 keys->send = decrypt_ms_key(key, keylen, 1101 sent_msg->hdr->authenticator, 1102 secret, secret_len, 1103 &keys->send_len); 1104 os_free(key); 1105 } 1106 1107 key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, 1108 RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY, 1109 &keylen); 1110 if (key) { 1111 keys->recv = decrypt_ms_key(key, keylen, 1112 sent_msg->hdr->authenticator, 1113 secret, secret_len, 1114 &keys->recv_len); 1115 os_free(key); 1116 } 1117 1118 return keys; 1119} 1120 1121 1122struct radius_ms_mppe_keys * 1123radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg, 1124 const u8 *secret, size_t secret_len) 1125{ 1126 u8 *key; 1127 size_t keylen; 1128 struct radius_ms_mppe_keys *keys; 1129 1130 if (msg == NULL || sent_msg == NULL) 1131 return NULL; 1132 1133 keys = os_zalloc(sizeof(*keys)); 1134 if (keys == NULL) 1135 return NULL; 1136 1137 key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO, 1138 RADIUS_CISCO_AV_PAIR, &keylen); 1139 if (key && keylen == 51 && 1140 os_memcmp(key, "leap:session-key=", 17) == 0) { 1141 keys->recv = decrypt_ms_key(key + 17, keylen - 17, 1142 sent_msg->hdr->authenticator, 1143 secret, secret_len, 1144 &keys->recv_len); 1145 } 1146 os_free(key); 1147 1148 return keys; 1149} 1150 1151 1152int radius_msg_add_mppe_keys(struct radius_msg *msg, 1153 const u8 *req_authenticator, 1154 const u8 *secret, size_t secret_len, 1155 const u8 *send_key, size_t send_key_len, 1156 const u8 *recv_key, size_t recv_key_len) 1157{ 1158 struct radius_attr_hdr *attr; 1159 u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT); 1160 u8 *buf; 1161 struct radius_attr_vendor *vhdr; 1162 u8 *pos; 1163 size_t elen; 1164 int hlen; 1165 u16 salt; 1166 1167 hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2; 1168 1169 /* MS-MPPE-Send-Key */ 1170 buf = os_malloc(hlen + send_key_len + 16); 1171 if (buf == NULL) { 1172 return 0; 1173 } 1174 pos = buf; 1175 os_memcpy(pos, &vendor_id, sizeof(vendor_id)); 1176 pos += sizeof(vendor_id); 1177 vhdr = (struct radius_attr_vendor *) pos; 1178 vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY; 1179 pos = (u8 *) (vhdr + 1); 1180 salt = os_random() | 0x8000; 1181 WPA_PUT_BE16(pos, salt); 1182 pos += 2; 1183 encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret, 1184 secret_len, pos, &elen); 1185 vhdr->vendor_length = hlen + elen - sizeof(vendor_id); 1186 1187 attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 1188 buf, hlen + elen); 1189 os_free(buf); 1190 if (attr == NULL) { 1191 return 0; 1192 } 1193 1194 /* MS-MPPE-Recv-Key */ 1195 buf = os_malloc(hlen + send_key_len + 16); 1196 if (buf == NULL) { 1197 return 0; 1198 } 1199 pos = buf; 1200 os_memcpy(pos, &vendor_id, sizeof(vendor_id)); 1201 pos += sizeof(vendor_id); 1202 vhdr = (struct radius_attr_vendor *) pos; 1203 vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY; 1204 pos = (u8 *) (vhdr + 1); 1205 salt ^= 1; 1206 WPA_PUT_BE16(pos, salt); 1207 pos += 2; 1208 encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret, 1209 secret_len, pos, &elen); 1210 vhdr->vendor_length = hlen + elen - sizeof(vendor_id); 1211 1212 attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 1213 buf, hlen + elen); 1214 os_free(buf); 1215 if (attr == NULL) { 1216 return 0; 1217 } 1218 1219 return 1; 1220} 1221 1222 1223int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data, 1224 size_t len) 1225{ 1226 struct radius_attr_hdr *attr; 1227 u8 *buf, *pos; 1228 size_t alen; 1229 1230 alen = 4 + 2 + len; 1231 buf = os_malloc(alen); 1232 if (buf == NULL) 1233 return 0; 1234 pos = buf; 1235 WPA_PUT_BE32(pos, RADIUS_VENDOR_ID_WFA); 1236 pos += 4; 1237 *pos++ = subtype; 1238 *pos++ = 2 + len; 1239 os_memcpy(pos, data, len); 1240 attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 1241 buf, alen); 1242 os_free(buf); 1243 if (attr == NULL) 1244 return 0; 1245 1246 return 1; 1247} 1248 1249 1250/* Add User-Password attribute to a RADIUS message and encrypt it as specified 1251 * in RFC 2865, Chap. 5.2 */ 1252struct radius_attr_hdr * 1253radius_msg_add_attr_user_password(struct radius_msg *msg, 1254 const u8 *data, size_t data_len, 1255 const u8 *secret, size_t secret_len) 1256{ 1257 u8 buf[128]; 1258 size_t padlen, i, buf_len, pos; 1259 const u8 *addr[2]; 1260 size_t len[2]; 1261 u8 hash[16]; 1262 1263 if (data_len > 128) 1264 return NULL; 1265 1266 os_memcpy(buf, data, data_len); 1267 buf_len = data_len; 1268 1269 padlen = data_len % 16; 1270 if (padlen && data_len < sizeof(buf)) { 1271 padlen = 16 - padlen; 1272 os_memset(buf + data_len, 0, padlen); 1273 buf_len += padlen; 1274 } 1275 1276 addr[0] = secret; 1277 len[0] = secret_len; 1278 addr[1] = msg->hdr->authenticator; 1279 len[1] = 16; 1280 md5_vector(2, addr, len, hash); 1281 1282 for (i = 0; i < 16; i++) 1283 buf[i] ^= hash[i]; 1284 pos = 16; 1285 1286 while (pos < buf_len) { 1287 addr[0] = secret; 1288 len[0] = secret_len; 1289 addr[1] = &buf[pos - 16]; 1290 len[1] = 16; 1291 md5_vector(2, addr, len, hash); 1292 1293 for (i = 0; i < 16; i++) 1294 buf[pos + i] ^= hash[i]; 1295 1296 pos += 16; 1297 } 1298 1299 return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD, 1300 buf, buf_len); 1301} 1302 1303 1304int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len) 1305{ 1306 struct radius_attr_hdr *attr = NULL, *tmp; 1307 size_t i, dlen; 1308 1309 for (i = 0; i < msg->attr_used; i++) { 1310 tmp = radius_get_attr_hdr(msg, i); 1311 if (tmp->type == type) { 1312 attr = tmp; 1313 break; 1314 } 1315 } 1316 1317 if (!attr || attr->length < sizeof(*attr)) 1318 return -1; 1319 1320 dlen = attr->length - sizeof(*attr); 1321 if (buf) 1322 os_memcpy(buf, (attr + 1), dlen > len ? len : dlen); 1323 return dlen; 1324} 1325 1326 1327int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf, 1328 size_t *len, const u8 *start) 1329{ 1330 size_t i; 1331 struct radius_attr_hdr *attr = NULL, *tmp; 1332 1333 for (i = 0; i < msg->attr_used; i++) { 1334 tmp = radius_get_attr_hdr(msg, i); 1335 if (tmp->type == type && 1336 (start == NULL || (u8 *) tmp > start)) { 1337 attr = tmp; 1338 break; 1339 } 1340 } 1341 1342 if (!attr || attr->length < sizeof(*attr)) 1343 return -1; 1344 1345 *buf = (u8 *) (attr + 1); 1346 *len = attr->length - sizeof(*attr); 1347 return 0; 1348} 1349 1350 1351int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len) 1352{ 1353 size_t i; 1354 int count; 1355 1356 for (count = 0, i = 0; i < msg->attr_used; i++) { 1357 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 1358 if (attr->type == type && 1359 attr->length >= sizeof(struct radius_attr_hdr) + min_len) 1360 count++; 1361 } 1362 1363 return count; 1364} 1365 1366 1367struct radius_tunnel_attrs { 1368 int tag_used; 1369 int type; /* Tunnel-Type */ 1370 int medium_type; /* Tunnel-Medium-Type */ 1371 int vlanid; 1372}; 1373 1374 1375/** 1376 * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information 1377 * @msg: RADIUS message 1378 * Returns: VLAN ID for the first tunnel configuration of -1 if none is found 1379 */ 1380int radius_msg_get_vlanid(struct radius_msg *msg) 1381{ 1382 struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun; 1383 size_t i; 1384 struct radius_attr_hdr *attr = NULL; 1385 const u8 *data; 1386 char buf[10]; 1387 size_t dlen; 1388 1389 os_memset(&tunnel, 0, sizeof(tunnel)); 1390 1391 for (i = 0; i < msg->attr_used; i++) { 1392 attr = radius_get_attr_hdr(msg, i); 1393 if (attr->length < sizeof(*attr)) 1394 return -1; 1395 data = (const u8 *) (attr + 1); 1396 dlen = attr->length - sizeof(*attr); 1397 if (attr->length < 3) 1398 continue; 1399 if (data[0] >= RADIUS_TUNNEL_TAGS) 1400 tun = &tunnel[0]; 1401 else 1402 tun = &tunnel[data[0]]; 1403 1404 switch (attr->type) { 1405 case RADIUS_ATTR_TUNNEL_TYPE: 1406 if (attr->length != 6) 1407 break; 1408 tun->tag_used++; 1409 tun->type = WPA_GET_BE24(data + 1); 1410 break; 1411 case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE: 1412 if (attr->length != 6) 1413 break; 1414 tun->tag_used++; 1415 tun->medium_type = WPA_GET_BE24(data + 1); 1416 break; 1417 case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID: 1418 if (data[0] < RADIUS_TUNNEL_TAGS) { 1419 data++; 1420 dlen--; 1421 } 1422 if (dlen >= sizeof(buf)) 1423 break; 1424 os_memcpy(buf, data, dlen); 1425 buf[dlen] = '\0'; 1426 tun->tag_used++; 1427 tun->vlanid = atoi(buf); 1428 break; 1429 } 1430 } 1431 1432 for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) { 1433 tun = &tunnel[i]; 1434 if (tun->tag_used && 1435 tun->type == RADIUS_TUNNEL_TYPE_VLAN && 1436 tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 && 1437 tun->vlanid > 0) 1438 return tun->vlanid; 1439 } 1440 1441 return -1; 1442} 1443 1444 1445/** 1446 * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password 1447 * @msg: Received RADIUS message 1448 * @keylen: Length of returned password 1449 * @secret: RADIUS shared secret 1450 * @secret_len: Length of secret 1451 * @sent_msg: Sent RADIUS message 1452 * @n: Number of password attribute to return (starting with 0) 1453 * Returns: Pointer to n-th password (free with os_free) or %NULL 1454 */ 1455char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen, 1456 const u8 *secret, size_t secret_len, 1457 struct radius_msg *sent_msg, size_t n) 1458{ 1459 u8 *buf = NULL; 1460 size_t buflen; 1461 const u8 *salt; 1462 u8 *str; 1463 const u8 *addr[3]; 1464 size_t len[3]; 1465 u8 hash[16]; 1466 u8 *pos; 1467 size_t i, j = 0; 1468 struct radius_attr_hdr *attr; 1469 const u8 *data; 1470 size_t dlen; 1471 const u8 *fdata = NULL; /* points to found item */ 1472 size_t fdlen = -1; 1473 char *ret = NULL; 1474 1475 /* find n-th valid Tunnel-Password attribute */ 1476 for (i = 0; i < msg->attr_used; i++) { 1477 attr = radius_get_attr_hdr(msg, i); 1478 if (attr == NULL || 1479 attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) { 1480 continue; 1481 } 1482 if (attr->length <= 5) 1483 continue; 1484 data = (const u8 *) (attr + 1); 1485 dlen = attr->length - sizeof(*attr); 1486 if (dlen <= 3 || dlen % 16 != 3) 1487 continue; 1488 j++; 1489 if (j <= n) 1490 continue; 1491 1492 fdata = data; 1493 fdlen = dlen; 1494 break; 1495 } 1496 if (fdata == NULL) 1497 goto out; 1498 1499 /* alloc writable memory for decryption */ 1500 buf = os_malloc(fdlen); 1501 if (buf == NULL) 1502 goto out; 1503 os_memcpy(buf, fdata, fdlen); 1504 buflen = fdlen; 1505 1506 /* init pointers */ 1507 salt = buf + 1; 1508 str = buf + 3; 1509 1510 /* decrypt blocks */ 1511 pos = buf + buflen - 16; /* last block */ 1512 while (pos >= str + 16) { /* all but the first block */ 1513 addr[0] = secret; 1514 len[0] = secret_len; 1515 addr[1] = pos - 16; 1516 len[1] = 16; 1517 md5_vector(2, addr, len, hash); 1518 1519 for (i = 0; i < 16; i++) 1520 pos[i] ^= hash[i]; 1521 1522 pos -= 16; 1523 } 1524 1525 /* decrypt first block */ 1526 if (str != pos) 1527 goto out; 1528 addr[0] = secret; 1529 len[0] = secret_len; 1530 addr[1] = sent_msg->hdr->authenticator; 1531 len[1] = 16; 1532 addr[2] = salt; 1533 len[2] = 2; 1534 md5_vector(3, addr, len, hash); 1535 1536 for (i = 0; i < 16; i++) 1537 pos[i] ^= hash[i]; 1538 1539 /* derive plaintext length from first subfield */ 1540 *keylen = (unsigned char) str[0]; 1541 if ((u8 *) (str + *keylen) >= (u8 *) (buf + buflen)) { 1542 /* decryption error - invalid key length */ 1543 goto out; 1544 } 1545 if (*keylen == 0) { 1546 /* empty password */ 1547 goto out; 1548 } 1549 1550 /* copy passphrase into new buffer */ 1551 ret = os_malloc(*keylen); 1552 if (ret) 1553 os_memcpy(ret, str + 1, *keylen); 1554 1555out: 1556 /* return new buffer */ 1557 os_free(buf); 1558 return ret; 1559} 1560 1561 1562void radius_free_class(struct radius_class_data *c) 1563{ 1564 size_t i; 1565 if (c == NULL) 1566 return; 1567 for (i = 0; i < c->count; i++) 1568 os_free(c->attr[i].data); 1569 os_free(c->attr); 1570 c->attr = NULL; 1571 c->count = 0; 1572} 1573 1574 1575int radius_copy_class(struct radius_class_data *dst, 1576 const struct radius_class_data *src) 1577{ 1578 size_t i; 1579 1580 if (src->attr == NULL) 1581 return 0; 1582 1583 dst->attr = os_calloc(src->count, sizeof(struct radius_attr_data)); 1584 if (dst->attr == NULL) 1585 return -1; 1586 1587 dst->count = 0; 1588 1589 for (i = 0; i < src->count; i++) { 1590 dst->attr[i].data = os_malloc(src->attr[i].len); 1591 if (dst->attr[i].data == NULL) 1592 break; 1593 dst->count++; 1594 os_memcpy(dst->attr[i].data, src->attr[i].data, 1595 src->attr[i].len); 1596 dst->attr[i].len = src->attr[i].len; 1597 } 1598 1599 return 0; 1600} 1601 1602 1603u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs) 1604{ 1605 size_t i, j; 1606 struct radius_attr_hdr *attr; 1607 1608 for (i = 0; i < msg->attr_used; i++) { 1609 attr = radius_get_attr_hdr(msg, i); 1610 1611 for (j = 0; attrs[j]; j++) { 1612 if (attr->type == attrs[j]) 1613 break; 1614 } 1615 1616 if (attrs[j] == 0) 1617 return attr->type; /* unlisted attr */ 1618 } 1619 1620 return 0; 1621} 1622