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