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