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