1 /* 2 * RADIUS message processing 3 * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15 #include "utils/includes.h" 16 17 #include "utils/common.h" 18 #include "utils/wpabuf.h" 19 #include "crypto/md5.h" 20 #include "crypto/crypto.h" 21 #include "radius.h" 22 23 24 /** 25 * struct radius_msg - RADIUS message structure for new and parsed messages 26 */ 27 struct radius_msg { 28 /** 29 * buf - Allocated buffer for RADIUS message 30 */ 31 struct wpabuf *buf; 32 33 /** 34 * hdr - Pointer to the RADIUS header in buf 35 */ 36 struct radius_hdr *hdr; 37 38 /** 39 * attr_pos - Array of indexes to attributes 40 * 41 * The values are number of bytes from buf to the beginning of 42 * struct radius_attr_hdr. 43 */ 44 size_t *attr_pos; 45 46 /** 47 * attr_size - Total size of the attribute pointer array 48 */ 49 size_t attr_size; 50 51 /** 52 * attr_used - Total number of attributes in the array 53 */ 54 size_t attr_used; 55 }; 56 57 58 struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg) 59 { 60 return msg->hdr; 61 } 62 63 64 struct wpabuf * radius_msg_get_buf(struct radius_msg *msg) 65 { 66 return msg->buf; 67 } 68 69 70 static struct radius_attr_hdr * 71 radius_get_attr_hdr(struct radius_msg *msg, int idx) 72 { 73 return (struct radius_attr_hdr *) 74 (wpabuf_mhead_u8(msg->buf) + msg->attr_pos[idx]); 75 } 76 77 78 static void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier) 79 { 80 msg->hdr->code = code; 81 msg->hdr->identifier = identifier; 82 } 83 84 85 static int radius_msg_initialize(struct radius_msg *msg) 86 { 87 msg->attr_pos = 88 os_zalloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attr_pos)); 89 if (msg->attr_pos == NULL) 90 return -1; 91 92 msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT; 93 msg->attr_used = 0; 94 95 return 0; 96 } 97 98 99 /** 100 * radius_msg_new - Create a new RADIUS message 101 * @code: Code for RADIUS header 102 * @identifier: Identifier for RADIUS header 103 * Returns: Context for RADIUS message or %NULL on failure 104 * 105 * The caller is responsible for freeing the returned data with 106 * radius_msg_free(). 107 */ 108 struct radius_msg * radius_msg_new(u8 code, u8 identifier) 109 { 110 struct radius_msg *msg; 111 112 msg = os_zalloc(sizeof(*msg)); 113 if (msg == NULL) 114 return NULL; 115 116 msg->buf = wpabuf_alloc(RADIUS_DEFAULT_MSG_SIZE); 117 if (msg->buf == NULL || radius_msg_initialize(msg)) { 118 radius_msg_free(msg); 119 return NULL; 120 } 121 msg->hdr = wpabuf_put(msg->buf, sizeof(struct radius_hdr)); 122 123 radius_msg_set_hdr(msg, code, identifier); 124 125 return msg; 126 } 127 128 129 /** 130 * radius_msg_free - Free a RADIUS message 131 * @msg: RADIUS message from radius_msg_new() or radius_msg_parse() 132 */ 133 void radius_msg_free(struct radius_msg *msg) 134 { 135 if (msg == NULL) 136 return; 137 138 wpabuf_free(msg->buf); 139 os_free(msg->attr_pos); 140 os_free(msg); 141 } 142 143 144 static const char *radius_code_string(u8 code) 145 { 146 switch (code) { 147 case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request"; 148 case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept"; 149 case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject"; 150 case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request"; 151 case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response"; 152 case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge"; 153 case RADIUS_CODE_STATUS_SERVER: return "Status-Server"; 154 case RADIUS_CODE_STATUS_CLIENT: return "Status-Client"; 155 case RADIUS_CODE_RESERVED: return "Reserved"; 156 default: return "?Unknown?"; 157 } 158 } 159 160 161 struct 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 170 static 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_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT }, 222 { RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST }, 223 { RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator", 224 RADIUS_ATTR_UNDIST }, 225 { RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id", 226 RADIUS_ATTR_HEXDUMP }, 227 { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval", 228 RADIUS_ATTR_INT32 }, 229 { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargable-User-Identity", 230 RADIUS_ATTR_TEXT }, 231 { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 }, 232 }; 233 #define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0])) 234 235 236 static struct radius_attr_type *radius_get_attr_type(u8 type) 237 { 238 size_t i; 239 240 for (i = 0; i < RADIUS_ATTRS; i++) { 241 if (type == radius_attrs[i].type) 242 return &radius_attrs[i]; 243 } 244 245 return NULL; 246 } 247 248 249 static void print_char(char c) 250 { 251 if (c >= 32 && c < 127) 252 printf("%c", c); 253 else 254 printf("<%02x>", c); 255 } 256 257 258 static void radius_msg_dump_attr(struct radius_attr_hdr *hdr) 259 { 260 struct radius_attr_type *attr; 261 int i, len; 262 unsigned char *pos; 263 264 attr = radius_get_attr_type(hdr->type); 265 266 printf(" Attribute %d (%s) length=%d\n", 267 hdr->type, attr ? attr->name : "?Unknown?", hdr->length); 268 269 if (attr == NULL) 270 return; 271 272 len = hdr->length - sizeof(struct radius_attr_hdr); 273 pos = (unsigned char *) (hdr + 1); 274 275 switch (attr->data_type) { 276 case RADIUS_ATTR_TEXT: 277 printf(" Value: '"); 278 for (i = 0; i < len; i++) 279 print_char(pos[i]); 280 printf("'\n"); 281 break; 282 283 case RADIUS_ATTR_IP: 284 if (len == 4) { 285 struct in_addr addr; 286 os_memcpy(&addr, pos, 4); 287 printf(" Value: %s\n", inet_ntoa(addr)); 288 } else 289 printf(" Invalid IP address length %d\n", len); 290 break; 291 292 #ifdef CONFIG_IPV6 293 case RADIUS_ATTR_IPV6: 294 if (len == 16) { 295 char buf[128]; 296 const char *atxt; 297 struct in6_addr *addr = (struct in6_addr *) pos; 298 atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf)); 299 printf(" Value: %s\n", atxt ? atxt : "?"); 300 } else 301 printf(" Invalid IPv6 address length %d\n", len); 302 break; 303 #endif /* CONFIG_IPV6 */ 304 305 case RADIUS_ATTR_HEXDUMP: 306 case RADIUS_ATTR_UNDIST: 307 printf(" Value:"); 308 for (i = 0; i < len; i++) 309 printf(" %02x", pos[i]); 310 printf("\n"); 311 break; 312 313 case RADIUS_ATTR_INT32: 314 if (len == 4) 315 printf(" Value: %u\n", WPA_GET_BE32(pos)); 316 else 317 printf(" Invalid INT32 length %d\n", len); 318 break; 319 320 default: 321 break; 322 } 323 } 324 325 326 void radius_msg_dump(struct radius_msg *msg) 327 { 328 size_t i; 329 330 printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n", 331 msg->hdr->code, radius_code_string(msg->hdr->code), 332 msg->hdr->identifier, ntohs(msg->hdr->length)); 333 334 for (i = 0; i < msg->attr_used; i++) { 335 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 336 radius_msg_dump_attr(attr); 337 } 338 } 339 340 341 int radius_msg_finish(struct radius_msg *msg, const u8 *secret, 342 size_t secret_len) 343 { 344 if (secret) { 345 u8 auth[MD5_MAC_LEN]; 346 struct radius_attr_hdr *attr; 347 348 os_memset(auth, 0, MD5_MAC_LEN); 349 attr = radius_msg_add_attr(msg, 350 RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 351 auth, MD5_MAC_LEN); 352 if (attr == NULL) { 353 wpa_printf(MSG_WARNING, "RADIUS: Could not add " 354 "Message-Authenticator"); 355 return -1; 356 } 357 msg->hdr->length = htons(wpabuf_len(msg->buf)); 358 hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 359 wpabuf_len(msg->buf), (u8 *) (attr + 1)); 360 } else 361 msg->hdr->length = htons(wpabuf_len(msg->buf)); 362 363 if (wpabuf_len(msg->buf) > 0xffff) { 364 wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 365 (unsigned long) wpabuf_len(msg->buf)); 366 return -1; 367 } 368 return 0; 369 } 370 371 372 int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, 373 size_t secret_len, const u8 *req_authenticator) 374 { 375 u8 auth[MD5_MAC_LEN]; 376 struct radius_attr_hdr *attr; 377 const u8 *addr[4]; 378 size_t len[4]; 379 380 os_memset(auth, 0, MD5_MAC_LEN); 381 attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 382 auth, MD5_MAC_LEN); 383 if (attr == NULL) { 384 printf("WARNING: Could not add Message-Authenticator\n"); 385 return -1; 386 } 387 msg->hdr->length = htons(wpabuf_len(msg->buf)); 388 os_memcpy(msg->hdr->authenticator, req_authenticator, 389 sizeof(msg->hdr->authenticator)); 390 hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 391 wpabuf_len(msg->buf), (u8 *) (attr + 1)); 392 393 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 394 addr[0] = (u8 *) msg->hdr; 395 len[0] = 1 + 1 + 2; 396 addr[1] = req_authenticator; 397 len[1] = MD5_MAC_LEN; 398 addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); 399 len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 400 addr[3] = secret; 401 len[3] = secret_len; 402 md5_vector(4, addr, len, msg->hdr->authenticator); 403 404 if (wpabuf_len(msg->buf) > 0xffff) { 405 wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", 406 (unsigned long) wpabuf_len(msg->buf)); 407 return -1; 408 } 409 return 0; 410 } 411 412 413 void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret, 414 size_t secret_len) 415 { 416 const u8 *addr[2]; 417 size_t len[2]; 418 419 msg->hdr->length = htons(wpabuf_len(msg->buf)); 420 os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN); 421 addr[0] = wpabuf_head(msg->buf); 422 len[0] = wpabuf_len(msg->buf); 423 addr[1] = secret; 424 len[1] = secret_len; 425 md5_vector(2, addr, len, msg->hdr->authenticator); 426 427 if (wpabuf_len(msg->buf) > 0xffff) { 428 wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)", 429 (unsigned long) wpabuf_len(msg->buf)); 430 } 431 } 432 433 434 static int radius_msg_add_attr_to_array(struct radius_msg *msg, 435 struct radius_attr_hdr *attr) 436 { 437 if (msg->attr_used >= msg->attr_size) { 438 size_t *nattr_pos; 439 int nlen = msg->attr_size * 2; 440 441 nattr_pos = os_realloc(msg->attr_pos, 442 nlen * sizeof(*msg->attr_pos)); 443 if (nattr_pos == NULL) 444 return -1; 445 446 msg->attr_pos = nattr_pos; 447 msg->attr_size = nlen; 448 } 449 450 msg->attr_pos[msg->attr_used++] = 451 (unsigned char *) attr - wpabuf_head_u8(msg->buf); 452 453 return 0; 454 } 455 456 457 struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, 458 const u8 *data, size_t data_len) 459 { 460 size_t buf_needed; 461 struct radius_attr_hdr *attr; 462 463 if (data_len > RADIUS_MAX_ATTR_LEN) { 464 printf("radius_msg_add_attr: too long attribute (%lu bytes)\n", 465 (unsigned long) data_len); 466 return NULL; 467 } 468 469 buf_needed = sizeof(*attr) + data_len; 470 471 if (wpabuf_tailroom(msg->buf) < buf_needed) { 472 /* allocate more space for message buffer */ 473 if (wpabuf_resize(&msg->buf, buf_needed) < 0) 474 return NULL; 475 msg->hdr = wpabuf_mhead(msg->buf); 476 } 477 478 attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr)); 479 attr->type = type; 480 attr->length = sizeof(*attr) + data_len; 481 wpabuf_put_data(msg->buf, data, data_len); 482 483 if (radius_msg_add_attr_to_array(msg, attr)) 484 return NULL; 485 486 return attr; 487 } 488 489 490 /** 491 * radius_msg_parse - Parse a RADIUS message 492 * @data: RADIUS message to be parsed 493 * @len: Length of data buffer in octets 494 * Returns: Parsed RADIUS message or %NULL on failure 495 * 496 * This parses a RADIUS message and makes a copy of its data. The caller is 497 * responsible for freeing the returned data with radius_msg_free(). 498 */ 499 struct radius_msg * radius_msg_parse(const u8 *data, size_t len) 500 { 501 struct radius_msg *msg; 502 struct radius_hdr *hdr; 503 struct radius_attr_hdr *attr; 504 size_t msg_len; 505 unsigned char *pos, *end; 506 507 if (data == NULL || len < sizeof(*hdr)) 508 return NULL; 509 510 hdr = (struct radius_hdr *) data; 511 512 msg_len = ntohs(hdr->length); 513 if (msg_len < sizeof(*hdr) || msg_len > len) { 514 wpa_printf(MSG_INFO, "RADIUS: Invalid message length"); 515 return NULL; 516 } 517 518 if (msg_len < len) { 519 wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after " 520 "RADIUS message", (unsigned long) len - msg_len); 521 } 522 523 msg = os_zalloc(sizeof(*msg)); 524 if (msg == NULL) 525 return NULL; 526 527 msg->buf = wpabuf_alloc_copy(data, msg_len); 528 if (msg->buf == NULL || radius_msg_initialize(msg)) { 529 radius_msg_free(msg); 530 return NULL; 531 } 532 msg->hdr = wpabuf_mhead(msg->buf); 533 534 /* parse attributes */ 535 pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr); 536 end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf); 537 while (pos < end) { 538 if ((size_t) (end - pos) < sizeof(*attr)) 539 goto fail; 540 541 attr = (struct radius_attr_hdr *) pos; 542 543 if (pos + attr->length > end || attr->length < sizeof(*attr)) 544 goto fail; 545 546 /* TODO: check that attr->length is suitable for attr->type */ 547 548 if (radius_msg_add_attr_to_array(msg, attr)) 549 goto fail; 550 551 pos += attr->length; 552 } 553 554 return msg; 555 556 fail: 557 radius_msg_free(msg); 558 return NULL; 559 } 560 561 562 int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len) 563 { 564 const u8 *pos = data; 565 size_t left = data_len; 566 567 while (left > 0) { 568 int len; 569 if (left > RADIUS_MAX_ATTR_LEN) 570 len = RADIUS_MAX_ATTR_LEN; 571 else 572 len = left; 573 574 if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE, 575 pos, len)) 576 return 0; 577 578 pos += len; 579 left -= len; 580 } 581 582 return 1; 583 } 584 585 586 u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len) 587 { 588 u8 *eap, *pos; 589 size_t len, i; 590 struct radius_attr_hdr *attr; 591 592 if (msg == NULL) 593 return NULL; 594 595 len = 0; 596 for (i = 0; i < msg->attr_used; i++) { 597 attr = radius_get_attr_hdr(msg, i); 598 if (attr->type == RADIUS_ATTR_EAP_MESSAGE) 599 len += attr->length - sizeof(struct radius_attr_hdr); 600 } 601 602 if (len == 0) 603 return NULL; 604 605 eap = os_malloc(len); 606 if (eap == NULL) 607 return NULL; 608 609 pos = eap; 610 for (i = 0; i < msg->attr_used; i++) { 611 attr = radius_get_attr_hdr(msg, i); 612 if (attr->type == RADIUS_ATTR_EAP_MESSAGE) { 613 int flen = attr->length - sizeof(*attr); 614 os_memcpy(pos, attr + 1, flen); 615 pos += flen; 616 } 617 } 618 619 if (eap_len) 620 *eap_len = len; 621 622 return eap; 623 } 624 625 626 int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, 627 size_t secret_len, const u8 *req_auth) 628 { 629 u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN]; 630 u8 orig_authenticator[16]; 631 struct radius_attr_hdr *attr = NULL, *tmp; 632 size_t i; 633 634 for (i = 0; i < msg->attr_used; i++) { 635 tmp = radius_get_attr_hdr(msg, i); 636 if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) { 637 if (attr != NULL) { 638 printf("Multiple Message-Authenticator " 639 "attributes in RADIUS message\n"); 640 return 1; 641 } 642 attr = tmp; 643 } 644 } 645 646 if (attr == NULL) { 647 printf("No Message-Authenticator attribute found\n"); 648 return 1; 649 } 650 651 os_memcpy(orig, attr + 1, MD5_MAC_LEN); 652 os_memset(attr + 1, 0, MD5_MAC_LEN); 653 if (req_auth) { 654 os_memcpy(orig_authenticator, msg->hdr->authenticator, 655 sizeof(orig_authenticator)); 656 os_memcpy(msg->hdr->authenticator, req_auth, 657 sizeof(msg->hdr->authenticator)); 658 } 659 hmac_md5(secret, secret_len, wpabuf_head(msg->buf), 660 wpabuf_len(msg->buf), auth); 661 os_memcpy(attr + 1, orig, MD5_MAC_LEN); 662 if (req_auth) { 663 os_memcpy(msg->hdr->authenticator, orig_authenticator, 664 sizeof(orig_authenticator)); 665 } 666 667 if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) { 668 printf("Invalid Message-Authenticator!\n"); 669 return 1; 670 } 671 672 return 0; 673 } 674 675 676 int radius_msg_verify(struct radius_msg *msg, const u8 *secret, 677 size_t secret_len, struct radius_msg *sent_msg, int auth) 678 { 679 const u8 *addr[4]; 680 size_t len[4]; 681 u8 hash[MD5_MAC_LEN]; 682 683 if (sent_msg == NULL) { 684 printf("No matching Access-Request message found\n"); 685 return 1; 686 } 687 688 if (auth && 689 radius_msg_verify_msg_auth(msg, secret, secret_len, 690 sent_msg->hdr->authenticator)) { 691 return 1; 692 } 693 694 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ 695 addr[0] = (u8 *) msg->hdr; 696 len[0] = 1 + 1 + 2; 697 addr[1] = sent_msg->hdr->authenticator; 698 len[1] = MD5_MAC_LEN; 699 addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); 700 len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); 701 addr[3] = secret; 702 len[3] = secret_len; 703 md5_vector(4, addr, len, hash); 704 if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) { 705 printf("Response Authenticator invalid!\n"); 706 return 1; 707 } 708 709 return 0; 710 } 711 712 713 int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src, 714 u8 type) 715 { 716 struct radius_attr_hdr *attr; 717 size_t i; 718 int count = 0; 719 720 for (i = 0; i < src->attr_used; i++) { 721 attr = radius_get_attr_hdr(src, i); 722 if (attr->type == type) { 723 if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1), 724 attr->length - sizeof(*attr))) 725 return -1; 726 count++; 727 } 728 } 729 730 return count; 731 } 732 733 734 /* Create Request Authenticator. The value should be unique over the lifetime 735 * of the shared secret between authenticator and authentication server. 736 * Use one-way MD5 hash calculated from current timestamp and some data given 737 * by the caller. */ 738 void radius_msg_make_authenticator(struct radius_msg *msg, 739 const u8 *data, size_t len) 740 { 741 struct os_time tv; 742 long int l; 743 const u8 *addr[3]; 744 size_t elen[3]; 745 746 os_get_time(&tv); 747 l = os_random(); 748 addr[0] = (u8 *) &tv; 749 elen[0] = sizeof(tv); 750 addr[1] = data; 751 elen[1] = len; 752 addr[2] = (u8 *) &l; 753 elen[2] = sizeof(l); 754 md5_vector(3, addr, elen, msg->hdr->authenticator); 755 } 756 757 758 /* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message. 759 * Returns the Attribute payload and sets alen to indicate the length of the 760 * payload if a vendor attribute with subtype is found, otherwise returns NULL. 761 * The returned payload is allocated with os_malloc() and caller must free it 762 * by calling os_free(). 763 */ 764 static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor, 765 u8 subtype, size_t *alen) 766 { 767 u8 *data, *pos; 768 size_t i, len; 769 770 if (msg == NULL) 771 return NULL; 772 773 for (i = 0; i < msg->attr_used; i++) { 774 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 775 size_t left; 776 u32 vendor_id; 777 struct radius_attr_vendor *vhdr; 778 779 if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC) 780 continue; 781 782 left = attr->length - sizeof(*attr); 783 if (left < 4) 784 continue; 785 786 pos = (u8 *) (attr + 1); 787 788 os_memcpy(&vendor_id, pos, 4); 789 pos += 4; 790 left -= 4; 791 792 if (ntohl(vendor_id) != vendor) 793 continue; 794 795 while (left >= sizeof(*vhdr)) { 796 vhdr = (struct radius_attr_vendor *) pos; 797 if (vhdr->vendor_length > left || 798 vhdr->vendor_length < sizeof(*vhdr)) { 799 left = 0; 800 break; 801 } 802 if (vhdr->vendor_type != subtype) { 803 pos += vhdr->vendor_length; 804 left -= vhdr->vendor_length; 805 continue; 806 } 807 808 len = vhdr->vendor_length - sizeof(*vhdr); 809 data = os_malloc(len); 810 if (data == NULL) 811 return NULL; 812 os_memcpy(data, pos + sizeof(*vhdr), len); 813 if (alen) 814 *alen = len; 815 return data; 816 } 817 } 818 819 return NULL; 820 } 821 822 823 static u8 * decrypt_ms_key(const u8 *key, size_t len, 824 const u8 *req_authenticator, 825 const u8 *secret, size_t secret_len, size_t *reslen) 826 { 827 u8 *plain, *ppos, *res; 828 const u8 *pos; 829 size_t left, plen; 830 u8 hash[MD5_MAC_LEN]; 831 int i, first = 1; 832 const u8 *addr[3]; 833 size_t elen[3]; 834 835 /* key: 16-bit salt followed by encrypted key info */ 836 837 if (len < 2 + 16) 838 return NULL; 839 840 pos = key + 2; 841 left = len - 2; 842 if (left % 16) { 843 printf("Invalid ms key len %lu\n", (unsigned long) left); 844 return NULL; 845 } 846 847 plen = left; 848 ppos = plain = os_malloc(plen); 849 if (plain == NULL) 850 return NULL; 851 plain[0] = 0; 852 853 while (left > 0) { 854 /* b(1) = MD5(Secret + Request-Authenticator + Salt) 855 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ 856 857 addr[0] = secret; 858 elen[0] = secret_len; 859 if (first) { 860 addr[1] = req_authenticator; 861 elen[1] = MD5_MAC_LEN; 862 addr[2] = key; 863 elen[2] = 2; /* Salt */ 864 } else { 865 addr[1] = pos - MD5_MAC_LEN; 866 elen[1] = MD5_MAC_LEN; 867 } 868 md5_vector(first ? 3 : 2, addr, elen, hash); 869 first = 0; 870 871 for (i = 0; i < MD5_MAC_LEN; i++) 872 *ppos++ = *pos++ ^ hash[i]; 873 left -= MD5_MAC_LEN; 874 } 875 876 if (plain[0] == 0 || plain[0] > plen - 1) { 877 printf("Failed to decrypt MPPE key\n"); 878 os_free(plain); 879 return NULL; 880 } 881 882 res = os_malloc(plain[0]); 883 if (res == NULL) { 884 os_free(plain); 885 return NULL; 886 } 887 os_memcpy(res, plain + 1, plain[0]); 888 if (reslen) 889 *reslen = plain[0]; 890 os_free(plain); 891 return res; 892 } 893 894 895 static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt, 896 const u8 *req_authenticator, 897 const u8 *secret, size_t secret_len, 898 u8 *ebuf, size_t *elen) 899 { 900 int i, len, first = 1; 901 u8 hash[MD5_MAC_LEN], saltbuf[2], *pos; 902 const u8 *addr[3]; 903 size_t _len[3]; 904 905 WPA_PUT_BE16(saltbuf, salt); 906 907 len = 1 + key_len; 908 if (len & 0x0f) { 909 len = (len & 0xf0) + 16; 910 } 911 os_memset(ebuf, 0, len); 912 ebuf[0] = key_len; 913 os_memcpy(ebuf + 1, key, key_len); 914 915 *elen = len; 916 917 pos = ebuf; 918 while (len > 0) { 919 /* b(1) = MD5(Secret + Request-Authenticator + Salt) 920 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ 921 addr[0] = secret; 922 _len[0] = secret_len; 923 if (first) { 924 addr[1] = req_authenticator; 925 _len[1] = MD5_MAC_LEN; 926 addr[2] = saltbuf; 927 _len[2] = sizeof(saltbuf); 928 } else { 929 addr[1] = pos - MD5_MAC_LEN; 930 _len[1] = MD5_MAC_LEN; 931 } 932 md5_vector(first ? 3 : 2, addr, _len, hash); 933 first = 0; 934 935 for (i = 0; i < MD5_MAC_LEN; i++) 936 *pos++ ^= hash[i]; 937 938 len -= MD5_MAC_LEN; 939 } 940 } 941 942 943 struct radius_ms_mppe_keys * 944 radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg, 945 const u8 *secret, size_t secret_len) 946 { 947 u8 *key; 948 size_t keylen; 949 struct radius_ms_mppe_keys *keys; 950 951 if (msg == NULL || sent_msg == NULL) 952 return NULL; 953 954 keys = os_zalloc(sizeof(*keys)); 955 if (keys == NULL) 956 return NULL; 957 958 key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, 959 RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY, 960 &keylen); 961 if (key) { 962 keys->send = decrypt_ms_key(key, keylen, 963 sent_msg->hdr->authenticator, 964 secret, secret_len, 965 &keys->send_len); 966 os_free(key); 967 } 968 969 key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, 970 RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY, 971 &keylen); 972 if (key) { 973 keys->recv = decrypt_ms_key(key, keylen, 974 sent_msg->hdr->authenticator, 975 secret, secret_len, 976 &keys->recv_len); 977 os_free(key); 978 } 979 980 return keys; 981 } 982 983 984 struct radius_ms_mppe_keys * 985 radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg, 986 const u8 *secret, size_t secret_len) 987 { 988 u8 *key; 989 size_t keylen; 990 struct radius_ms_mppe_keys *keys; 991 992 if (msg == NULL || sent_msg == NULL) 993 return NULL; 994 995 keys = os_zalloc(sizeof(*keys)); 996 if (keys == NULL) 997 return NULL; 998 999 key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO, 1000 RADIUS_CISCO_AV_PAIR, &keylen); 1001 if (key && keylen == 51 && 1002 os_memcmp(key, "leap:session-key=", 17) == 0) { 1003 keys->recv = decrypt_ms_key(key + 17, keylen - 17, 1004 sent_msg->hdr->authenticator, 1005 secret, secret_len, 1006 &keys->recv_len); 1007 } 1008 os_free(key); 1009 1010 return keys; 1011 } 1012 1013 1014 int radius_msg_add_mppe_keys(struct radius_msg *msg, 1015 const u8 *req_authenticator, 1016 const u8 *secret, size_t secret_len, 1017 const u8 *send_key, size_t send_key_len, 1018 const u8 *recv_key, size_t recv_key_len) 1019 { 1020 struct radius_attr_hdr *attr; 1021 u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT); 1022 u8 *buf; 1023 struct radius_attr_vendor *vhdr; 1024 u8 *pos; 1025 size_t elen; 1026 int hlen; 1027 u16 salt; 1028 1029 hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2; 1030 1031 /* MS-MPPE-Send-Key */ 1032 buf = os_malloc(hlen + send_key_len + 16); 1033 if (buf == NULL) { 1034 return 0; 1035 } 1036 pos = buf; 1037 os_memcpy(pos, &vendor_id, sizeof(vendor_id)); 1038 pos += sizeof(vendor_id); 1039 vhdr = (struct radius_attr_vendor *) pos; 1040 vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY; 1041 pos = (u8 *) (vhdr + 1); 1042 salt = os_random() | 0x8000; 1043 WPA_PUT_BE16(pos, salt); 1044 pos += 2; 1045 encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret, 1046 secret_len, pos, &elen); 1047 vhdr->vendor_length = hlen + elen - sizeof(vendor_id); 1048 1049 attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 1050 buf, hlen + elen); 1051 os_free(buf); 1052 if (attr == NULL) { 1053 return 0; 1054 } 1055 1056 /* MS-MPPE-Recv-Key */ 1057 buf = os_malloc(hlen + send_key_len + 16); 1058 if (buf == NULL) { 1059 return 0; 1060 } 1061 pos = buf; 1062 os_memcpy(pos, &vendor_id, sizeof(vendor_id)); 1063 pos += sizeof(vendor_id); 1064 vhdr = (struct radius_attr_vendor *) pos; 1065 vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY; 1066 pos = (u8 *) (vhdr + 1); 1067 salt ^= 1; 1068 WPA_PUT_BE16(pos, salt); 1069 pos += 2; 1070 encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret, 1071 secret_len, pos, &elen); 1072 vhdr->vendor_length = hlen + elen - sizeof(vendor_id); 1073 1074 attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 1075 buf, hlen + elen); 1076 os_free(buf); 1077 if (attr == NULL) { 1078 return 0; 1079 } 1080 1081 return 1; 1082 } 1083 1084 1085 /* Add User-Password attribute to a RADIUS message and encrypt it as specified 1086 * in RFC 2865, Chap. 5.2 */ 1087 struct radius_attr_hdr * 1088 radius_msg_add_attr_user_password(struct radius_msg *msg, 1089 const u8 *data, size_t data_len, 1090 const u8 *secret, size_t secret_len) 1091 { 1092 u8 buf[128]; 1093 int padlen, i; 1094 size_t buf_len, pos; 1095 const u8 *addr[2]; 1096 size_t len[2]; 1097 u8 hash[16]; 1098 1099 if (data_len > 128) 1100 return NULL; 1101 1102 os_memcpy(buf, data, data_len); 1103 buf_len = data_len; 1104 1105 padlen = data_len % 16; 1106 if (padlen) { 1107 padlen = 16 - padlen; 1108 os_memset(buf + data_len, 0, padlen); 1109 buf_len += padlen; 1110 } 1111 1112 addr[0] = secret; 1113 len[0] = secret_len; 1114 addr[1] = msg->hdr->authenticator; 1115 len[1] = 16; 1116 md5_vector(2, addr, len, hash); 1117 1118 for (i = 0; i < 16; i++) 1119 buf[i] ^= hash[i]; 1120 pos = 16; 1121 1122 while (pos < buf_len) { 1123 addr[0] = secret; 1124 len[0] = secret_len; 1125 addr[1] = &buf[pos - 16]; 1126 len[1] = 16; 1127 md5_vector(2, addr, len, hash); 1128 1129 for (i = 0; i < 16; i++) 1130 buf[pos + i] ^= hash[i]; 1131 1132 pos += 16; 1133 } 1134 1135 return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD, 1136 buf, buf_len); 1137 } 1138 1139 1140 int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len) 1141 { 1142 struct radius_attr_hdr *attr = NULL, *tmp; 1143 size_t i, dlen; 1144 1145 for (i = 0; i < msg->attr_used; i++) { 1146 tmp = radius_get_attr_hdr(msg, i); 1147 if (tmp->type == type) { 1148 attr = tmp; 1149 break; 1150 } 1151 } 1152 1153 if (!attr) 1154 return -1; 1155 1156 dlen = attr->length - sizeof(*attr); 1157 if (buf) 1158 os_memcpy(buf, (attr + 1), dlen > len ? len : dlen); 1159 return dlen; 1160 } 1161 1162 1163 int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf, 1164 size_t *len, const u8 *start) 1165 { 1166 size_t i; 1167 struct radius_attr_hdr *attr = NULL, *tmp; 1168 1169 for (i = 0; i < msg->attr_used; i++) { 1170 tmp = radius_get_attr_hdr(msg, i); 1171 if (tmp->type == type && 1172 (start == NULL || (u8 *) tmp > start)) { 1173 attr = tmp; 1174 break; 1175 } 1176 } 1177 1178 if (!attr) 1179 return -1; 1180 1181 *buf = (u8 *) (attr + 1); 1182 *len = attr->length - sizeof(*attr); 1183 return 0; 1184 } 1185 1186 1187 int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len) 1188 { 1189 size_t i; 1190 int count; 1191 1192 for (count = 0, i = 0; i < msg->attr_used; i++) { 1193 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); 1194 if (attr->type == type && 1195 attr->length >= sizeof(struct radius_attr_hdr) + min_len) 1196 count++; 1197 } 1198 1199 return count; 1200 } 1201 1202 1203 struct radius_tunnel_attrs { 1204 int tag_used; 1205 int type; /* Tunnel-Type */ 1206 int medium_type; /* Tunnel-Medium-Type */ 1207 int vlanid; 1208 }; 1209 1210 1211 /** 1212 * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information 1213 * @msg: RADIUS message 1214 * Returns: VLAN ID for the first tunnel configuration of -1 if none is found 1215 */ 1216 int radius_msg_get_vlanid(struct radius_msg *msg) 1217 { 1218 struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun; 1219 size_t i; 1220 struct radius_attr_hdr *attr = NULL; 1221 const u8 *data; 1222 char buf[10]; 1223 size_t dlen; 1224 1225 os_memset(&tunnel, 0, sizeof(tunnel)); 1226 1227 for (i = 0; i < msg->attr_used; i++) { 1228 attr = radius_get_attr_hdr(msg, i); 1229 data = (const u8 *) (attr + 1); 1230 dlen = attr->length - sizeof(*attr); 1231 if (attr->length < 3) 1232 continue; 1233 if (data[0] >= RADIUS_TUNNEL_TAGS) 1234 tun = &tunnel[0]; 1235 else 1236 tun = &tunnel[data[0]]; 1237 1238 switch (attr->type) { 1239 case RADIUS_ATTR_TUNNEL_TYPE: 1240 if (attr->length != 6) 1241 break; 1242 tun->tag_used++; 1243 tun->type = WPA_GET_BE24(data + 1); 1244 break; 1245 case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE: 1246 if (attr->length != 6) 1247 break; 1248 tun->tag_used++; 1249 tun->medium_type = WPA_GET_BE24(data + 1); 1250 break; 1251 case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID: 1252 if (data[0] < RADIUS_TUNNEL_TAGS) { 1253 data++; 1254 dlen--; 1255 } 1256 if (dlen >= sizeof(buf)) 1257 break; 1258 os_memcpy(buf, data, dlen); 1259 buf[dlen] = '\0'; 1260 tun->tag_used++; 1261 tun->vlanid = atoi(buf); 1262 break; 1263 } 1264 } 1265 1266 for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) { 1267 tun = &tunnel[i]; 1268 if (tun->tag_used && 1269 tun->type == RADIUS_TUNNEL_TYPE_VLAN && 1270 tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 && 1271 tun->vlanid > 0) 1272 return tun->vlanid; 1273 } 1274 1275 return -1; 1276 } 1277 1278 1279 void radius_free_class(struct radius_class_data *c) 1280 { 1281 size_t i; 1282 if (c == NULL) 1283 return; 1284 for (i = 0; i < c->count; i++) 1285 os_free(c->attr[i].data); 1286 os_free(c->attr); 1287 c->attr = NULL; 1288 c->count = 0; 1289 } 1290 1291 1292 int radius_copy_class(struct radius_class_data *dst, 1293 const struct radius_class_data *src) 1294 { 1295 size_t i; 1296 1297 if (src->attr == NULL) 1298 return 0; 1299 1300 dst->attr = os_zalloc(src->count * sizeof(struct radius_attr_data)); 1301 if (dst->attr == NULL) 1302 return -1; 1303 1304 dst->count = 0; 1305 1306 for (i = 0; i < src->count; i++) { 1307 dst->attr[i].data = os_malloc(src->attr[i].len); 1308 if (dst->attr[i].data == NULL) 1309 break; 1310 dst->count++; 1311 os_memcpy(dst->attr[i].data, src->attr[i].data, 1312 src->attr[i].len); 1313 dst->attr[i].len = src->attr[i].len; 1314 } 1315 1316 return 0; 1317 } 1318