00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "utils/includes.h"
00016
00017 #include "utils/common.h"
00018 #include "utils/wpabuf.h"
00019 #include "crypto/md5.h"
00020 #include "crypto/crypto.h"
00021 #include "radius.h"
00022
00023
00027 struct radius_msg {
00031 struct wpabuf *buf;
00032
00036 struct radius_hdr *hdr;
00037
00044 size_t *attr_pos;
00045
00049 size_t attr_size;
00050
00054 size_t attr_used;
00055 };
00056
00057
00058 struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg)
00059 {
00060 return msg->hdr;
00061 }
00062
00063
00064 struct wpabuf * radius_msg_get_buf(struct radius_msg *msg)
00065 {
00066 return msg->buf;
00067 }
00068
00069
00070 static struct radius_attr_hdr *
00071 radius_get_attr_hdr(struct radius_msg *msg, int idx)
00072 {
00073 return (struct radius_attr_hdr *)
00074 (wpabuf_mhead_u8(msg->buf) + msg->attr_pos[idx]);
00075 }
00076
00077
00078 static void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
00079 {
00080 msg->hdr->code = code;
00081 msg->hdr->identifier = identifier;
00082 }
00083
00084
00085 static int radius_msg_initialize(struct radius_msg *msg)
00086 {
00087 msg->attr_pos =
00088 os_zalloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attr_pos));
00089 if (msg->attr_pos == NULL)
00090 return -1;
00091
00092 msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT;
00093 msg->attr_used = 0;
00094
00095 return 0;
00096 }
00097
00098
00108 struct radius_msg * radius_msg_new(u8 code, u8 identifier)
00109 {
00110 struct radius_msg *msg;
00111
00112 msg = os_zalloc(sizeof(*msg));
00113 if (msg == NULL)
00114 return NULL;
00115
00116 msg->buf = wpabuf_alloc(RADIUS_DEFAULT_MSG_SIZE);
00117 if (msg->buf == NULL || radius_msg_initialize(msg)) {
00118 radius_msg_free(msg);
00119 return NULL;
00120 }
00121 msg->hdr = wpabuf_put(msg->buf, sizeof(struct radius_hdr));
00122
00123 radius_msg_set_hdr(msg, code, identifier);
00124
00125 return msg;
00126 }
00127
00128
00133 void radius_msg_free(struct radius_msg *msg)
00134 {
00135 if (msg == NULL)
00136 return;
00137
00138 wpabuf_free(msg->buf);
00139 os_free(msg->attr_pos);
00140 os_free(msg);
00141 }
00142
00143
00144 static const char *radius_code_string(u8 code)
00145 {
00146 switch (code) {
00147 case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request";
00148 case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept";
00149 case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject";
00150 case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request";
00151 case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response";
00152 case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge";
00153 case RADIUS_CODE_STATUS_SERVER: return "Status-Server";
00154 case RADIUS_CODE_STATUS_CLIENT: return "Status-Client";
00155 case RADIUS_CODE_RESERVED: return "Reserved";
00156 default: return "?Unknown?";
00157 }
00158 }
00159
00160
00161 struct radius_attr_type {
00162 u8 type;
00163 char *name;
00164 enum {
00165 RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
00166 RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6
00167 } data_type;
00168 };
00169
00170 static struct radius_attr_type radius_attrs[] =
00171 {
00172 { RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT },
00173 { RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST },
00174 { RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP },
00175 { RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 },
00176 { RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 },
00177 { RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT },
00178 { RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST },
00179 { RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST },
00180 { RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST },
00181 { RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 },
00182 { RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 },
00183 { RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action",
00184 RADIUS_ATTR_INT32 },
00185 { RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id",
00186 RADIUS_ATTR_TEXT },
00187 { RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id",
00188 RADIUS_ATTR_TEXT },
00189 { RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT },
00190 { RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST },
00191 { RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type",
00192 RADIUS_ATTR_INT32 },
00193 { RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 },
00194 { RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets",
00195 RADIUS_ATTR_INT32 },
00196 { RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets",
00197 RADIUS_ATTR_INT32 },
00198 { RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT },
00199 { RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 },
00200 { RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time",
00201 RADIUS_ATTR_INT32 },
00202 { RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets",
00203 RADIUS_ATTR_INT32 },
00204 { RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets",
00205 RADIUS_ATTR_INT32 },
00206 { RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause",
00207 RADIUS_ATTR_INT32 },
00208 { RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id",
00209 RADIUS_ATTR_TEXT },
00210 { RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 },
00211 { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords",
00212 RADIUS_ATTR_INT32 },
00213 { RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords",
00214 RADIUS_ATTR_INT32 },
00215 { RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",
00216 RADIUS_ATTR_INT32 },
00217 { RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 },
00218 { RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
00219 { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
00220 RADIUS_ATTR_HEXDUMP },
00221 { RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
00222 { RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
00223 { RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
00224 RADIUS_ATTR_UNDIST },
00225 { RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id",
00226 RADIUS_ATTR_HEXDUMP },
00227 { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
00228 RADIUS_ATTR_INT32 },
00229 { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargable-User-Identity",
00230 RADIUS_ATTR_TEXT },
00231 { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
00232 };
00233 #define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
00234
00235
00236 static struct radius_attr_type *radius_get_attr_type(u8 type)
00237 {
00238 size_t i;
00239
00240 for (i = 0; i < RADIUS_ATTRS; i++) {
00241 if (type == radius_attrs[i].type)
00242 return &radius_attrs[i];
00243 }
00244
00245 return NULL;
00246 }
00247
00248
00249 static void print_char(char c)
00250 {
00251 if (c >= 32 && c < 127)
00252 printf("%c", c);
00253 else
00254 printf("<%02x>", c);
00255 }
00256
00257
00258 static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
00259 {
00260 struct radius_attr_type *attr;
00261 int i, len;
00262 unsigned char *pos;
00263
00264 attr = radius_get_attr_type(hdr->type);
00265
00266 printf(" Attribute %d (%s) length=%d\n",
00267 hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
00268
00269 if (attr == NULL)
00270 return;
00271
00272 len = hdr->length - sizeof(struct radius_attr_hdr);
00273 pos = (unsigned char *) (hdr + 1);
00274
00275 switch (attr->data_type) {
00276 case RADIUS_ATTR_TEXT:
00277 printf(" Value: '");
00278 for (i = 0; i < len; i++)
00279 print_char(pos[i]);
00280 printf("'\n");
00281 break;
00282
00283 case RADIUS_ATTR_IP:
00284 if (len == 4) {
00285 struct in_addr addr;
00286 os_memcpy(&addr, pos, 4);
00287 printf(" Value: %s\n", inet_ntoa(addr));
00288 } else
00289 printf(" Invalid IP address length %d\n", len);
00290 break;
00291
00292 #ifdef CONFIG_IPV6
00293 case RADIUS_ATTR_IPV6:
00294 if (len == 16) {
00295 char buf[128];
00296 const char *atxt;
00297 struct in6_addr *addr = (struct in6_addr *) pos;
00298 atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf));
00299 printf(" Value: %s\n", atxt ? atxt : "?");
00300 } else
00301 printf(" Invalid IPv6 address length %d\n", len);
00302 break;
00303 #endif
00304
00305 case RADIUS_ATTR_HEXDUMP:
00306 case RADIUS_ATTR_UNDIST:
00307 printf(" Value:");
00308 for (i = 0; i < len; i++)
00309 printf(" %02x", pos[i]);
00310 printf("\n");
00311 break;
00312
00313 case RADIUS_ATTR_INT32:
00314 if (len == 4)
00315 printf(" Value: %u\n", WPA_GET_BE32(pos));
00316 else
00317 printf(" Invalid INT32 length %d\n", len);
00318 break;
00319
00320 default:
00321 break;
00322 }
00323 }
00324
00325
00326 void radius_msg_dump(struct radius_msg *msg)
00327 {
00328 size_t i;
00329
00330 printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",
00331 msg->hdr->code, radius_code_string(msg->hdr->code),
00332 msg->hdr->identifier, ntohs(msg->hdr->length));
00333
00334 for (i = 0; i < msg->attr_used; i++) {
00335 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
00336 radius_msg_dump_attr(attr);
00337 }
00338 }
00339
00340
00341 int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
00342 size_t secret_len)
00343 {
00344 if (secret) {
00345 u8 auth[MD5_MAC_LEN];
00346 struct radius_attr_hdr *attr;
00347
00348 os_memset(auth, 0, MD5_MAC_LEN);
00349 attr = radius_msg_add_attr(msg,
00350 RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
00351 auth, MD5_MAC_LEN);
00352 if (attr == NULL) {
00353 wpa_printf(MSG_WARNING, "RADIUS: Could not add "
00354 "Message-Authenticator");
00355 return -1;
00356 }
00357 msg->hdr->length = htons(wpabuf_len(msg->buf));
00358 hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
00359 wpabuf_len(msg->buf), (u8 *) (attr + 1));
00360 } else
00361 msg->hdr->length = htons(wpabuf_len(msg->buf));
00362
00363 if (wpabuf_len(msg->buf) > 0xffff) {
00364 wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
00365 (unsigned long) wpabuf_len(msg->buf));
00366 return -1;
00367 }
00368 return 0;
00369 }
00370
00371
00372 int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
00373 size_t secret_len, const u8 *req_authenticator)
00374 {
00375 u8 auth[MD5_MAC_LEN];
00376 struct radius_attr_hdr *attr;
00377 const u8 *addr[4];
00378 size_t len[4];
00379
00380 os_memset(auth, 0, MD5_MAC_LEN);
00381 attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
00382 auth, MD5_MAC_LEN);
00383 if (attr == NULL) {
00384 printf("WARNING: Could not add Message-Authenticator\n");
00385 return -1;
00386 }
00387 msg->hdr->length = htons(wpabuf_len(msg->buf));
00388 os_memcpy(msg->hdr->authenticator, req_authenticator,
00389 sizeof(msg->hdr->authenticator));
00390 hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
00391 wpabuf_len(msg->buf), (u8 *) (attr + 1));
00392
00393
00394 addr[0] = (u8 *) msg->hdr;
00395 len[0] = 1 + 1 + 2;
00396 addr[1] = req_authenticator;
00397 len[1] = MD5_MAC_LEN;
00398 addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
00399 len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
00400 addr[3] = secret;
00401 len[3] = secret_len;
00402 md5_vector(4, addr, len, msg->hdr->authenticator);
00403
00404 if (wpabuf_len(msg->buf) > 0xffff) {
00405 wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
00406 (unsigned long) wpabuf_len(msg->buf));
00407 return -1;
00408 }
00409 return 0;
00410 }
00411
00412
00413 void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
00414 size_t secret_len)
00415 {
00416 const u8 *addr[2];
00417 size_t len[2];
00418
00419 msg->hdr->length = htons(wpabuf_len(msg->buf));
00420 os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
00421 addr[0] = wpabuf_head(msg->buf);
00422 len[0] = wpabuf_len(msg->buf);
00423 addr[1] = secret;
00424 len[1] = secret_len;
00425 md5_vector(2, addr, len, msg->hdr->authenticator);
00426
00427 if (wpabuf_len(msg->buf) > 0xffff) {
00428 wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
00429 (unsigned long) wpabuf_len(msg->buf));
00430 }
00431 }
00432
00433
00434 static int radius_msg_add_attr_to_array(struct radius_msg *msg,
00435 struct radius_attr_hdr *attr)
00436 {
00437 if (msg->attr_used >= msg->attr_size) {
00438 size_t *nattr_pos;
00439 int nlen = msg->attr_size * 2;
00440
00441 nattr_pos = os_realloc(msg->attr_pos,
00442 nlen * sizeof(*msg->attr_pos));
00443 if (nattr_pos == NULL)
00444 return -1;
00445
00446 msg->attr_pos = nattr_pos;
00447 msg->attr_size = nlen;
00448 }
00449
00450 msg->attr_pos[msg->attr_used++] =
00451 (unsigned char *) attr - wpabuf_head_u8(msg->buf);
00452
00453 return 0;
00454 }
00455
00456
00457 struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
00458 const u8 *data, size_t data_len)
00459 {
00460 size_t buf_needed;
00461 struct radius_attr_hdr *attr;
00462
00463 if (data_len > RADIUS_MAX_ATTR_LEN) {
00464 printf("radius_msg_add_attr: too long attribute (%lu bytes)\n",
00465 (unsigned long) data_len);
00466 return NULL;
00467 }
00468
00469 buf_needed = sizeof(*attr) + data_len;
00470
00471 if (wpabuf_tailroom(msg->buf) < buf_needed) {
00472
00473 if (wpabuf_resize(&msg->buf, buf_needed) < 0)
00474 return NULL;
00475 msg->hdr = wpabuf_mhead(msg->buf);
00476 }
00477
00478 attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr));
00479 attr->type = type;
00480 attr->length = sizeof(*attr) + data_len;
00481 wpabuf_put_data(msg->buf, data, data_len);
00482
00483 if (radius_msg_add_attr_to_array(msg, attr))
00484 return NULL;
00485
00486 return attr;
00487 }
00488
00489
00499 struct radius_msg * radius_msg_parse(const u8 *data, size_t len)
00500 {
00501 struct radius_msg *msg;
00502 struct radius_hdr *hdr;
00503 struct radius_attr_hdr *attr;
00504 size_t msg_len;
00505 unsigned char *pos, *end;
00506
00507 if (data == NULL || len < sizeof(*hdr))
00508 return NULL;
00509
00510 hdr = (struct radius_hdr *) data;
00511
00512 msg_len = ntohs(hdr->length);
00513 if (msg_len < sizeof(*hdr) || msg_len > len) {
00514 wpa_printf(MSG_INFO, "RADIUS: Invalid message length");
00515 return NULL;
00516 }
00517
00518 if (msg_len < len) {
00519 wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after "
00520 "RADIUS message", (unsigned long) len - msg_len);
00521 }
00522
00523 msg = os_zalloc(sizeof(*msg));
00524 if (msg == NULL)
00525 return NULL;
00526
00527 msg->buf = wpabuf_alloc_copy(data, msg_len);
00528 if (msg->buf == NULL || radius_msg_initialize(msg)) {
00529 radius_msg_free(msg);
00530 return NULL;
00531 }
00532 msg->hdr = wpabuf_mhead(msg->buf);
00533
00534
00535 pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr);
00536 end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf);
00537 while (pos < end) {
00538 if ((size_t) (end - pos) < sizeof(*attr))
00539 goto fail;
00540
00541 attr = (struct radius_attr_hdr *) pos;
00542
00543 if (pos + attr->length > end || attr->length < sizeof(*attr))
00544 goto fail;
00545
00546
00547
00548 if (radius_msg_add_attr_to_array(msg, attr))
00549 goto fail;
00550
00551 pos += attr->length;
00552 }
00553
00554 return msg;
00555
00556 fail:
00557 radius_msg_free(msg);
00558 return NULL;
00559 }
00560
00561
00562 int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len)
00563 {
00564 const u8 *pos = data;
00565 size_t left = data_len;
00566
00567 while (left > 0) {
00568 int len;
00569 if (left > RADIUS_MAX_ATTR_LEN)
00570 len = RADIUS_MAX_ATTR_LEN;
00571 else
00572 len = left;
00573
00574 if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE,
00575 pos, len))
00576 return 0;
00577
00578 pos += len;
00579 left -= len;
00580 }
00581
00582 return 1;
00583 }
00584
00585
00586 u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len)
00587 {
00588 u8 *eap, *pos;
00589 size_t len, i;
00590 struct radius_attr_hdr *attr;
00591
00592 if (msg == NULL)
00593 return NULL;
00594
00595 len = 0;
00596 for (i = 0; i < msg->attr_used; i++) {
00597 attr = radius_get_attr_hdr(msg, i);
00598 if (attr->type == RADIUS_ATTR_EAP_MESSAGE)
00599 len += attr->length - sizeof(struct radius_attr_hdr);
00600 }
00601
00602 if (len == 0)
00603 return NULL;
00604
00605 eap = os_malloc(len);
00606 if (eap == NULL)
00607 return NULL;
00608
00609 pos = eap;
00610 for (i = 0; i < msg->attr_used; i++) {
00611 attr = radius_get_attr_hdr(msg, i);
00612 if (attr->type == RADIUS_ATTR_EAP_MESSAGE) {
00613 int flen = attr->length - sizeof(*attr);
00614 os_memcpy(pos, attr + 1, flen);
00615 pos += flen;
00616 }
00617 }
00618
00619 if (eap_len)
00620 *eap_len = len;
00621
00622 return eap;
00623 }
00624
00625
00626 int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
00627 size_t secret_len, const u8 *req_auth)
00628 {
00629 u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
00630 u8 orig_authenticator[16];
00631 struct radius_attr_hdr *attr = NULL, *tmp;
00632 size_t i;
00633
00634 for (i = 0; i < msg->attr_used; i++) {
00635 tmp = radius_get_attr_hdr(msg, i);
00636 if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
00637 if (attr != NULL) {
00638 printf("Multiple Message-Authenticator "
00639 "attributes in RADIUS message\n");
00640 return 1;
00641 }
00642 attr = tmp;
00643 }
00644 }
00645
00646 if (attr == NULL) {
00647 printf("No Message-Authenticator attribute found\n");
00648 return 1;
00649 }
00650
00651 os_memcpy(orig, attr + 1, MD5_MAC_LEN);
00652 os_memset(attr + 1, 0, MD5_MAC_LEN);
00653 if (req_auth) {
00654 os_memcpy(orig_authenticator, msg->hdr->authenticator,
00655 sizeof(orig_authenticator));
00656 os_memcpy(msg->hdr->authenticator, req_auth,
00657 sizeof(msg->hdr->authenticator));
00658 }
00659 hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
00660 wpabuf_len(msg->buf), auth);
00661 os_memcpy(attr + 1, orig, MD5_MAC_LEN);
00662 if (req_auth) {
00663 os_memcpy(msg->hdr->authenticator, orig_authenticator,
00664 sizeof(orig_authenticator));
00665 }
00666
00667 if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) {
00668 printf("Invalid Message-Authenticator!\n");
00669 return 1;
00670 }
00671
00672 return 0;
00673 }
00674
00675
00676 int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
00677 size_t secret_len, struct radius_msg *sent_msg, int auth)
00678 {
00679 const u8 *addr[4];
00680 size_t len[4];
00681 u8 hash[MD5_MAC_LEN];
00682
00683 if (sent_msg == NULL) {
00684 printf("No matching Access-Request message found\n");
00685 return 1;
00686 }
00687
00688 if (auth &&
00689 radius_msg_verify_msg_auth(msg, secret, secret_len,
00690 sent_msg->hdr->authenticator)) {
00691 return 1;
00692 }
00693
00694
00695 addr[0] = (u8 *) msg->hdr;
00696 len[0] = 1 + 1 + 2;
00697 addr[1] = sent_msg->hdr->authenticator;
00698 len[1] = MD5_MAC_LEN;
00699 addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
00700 len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
00701 addr[3] = secret;
00702 len[3] = secret_len;
00703 md5_vector(4, addr, len, hash);
00704 if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
00705 printf("Response Authenticator invalid!\n");
00706 return 1;
00707 }
00708
00709 return 0;
00710 }
00711
00712
00713 int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
00714 u8 type)
00715 {
00716 struct radius_attr_hdr *attr;
00717 size_t i;
00718 int count = 0;
00719
00720 for (i = 0; i < src->attr_used; i++) {
00721 attr = radius_get_attr_hdr(src, i);
00722 if (attr->type == type) {
00723 if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1),
00724 attr->length - sizeof(*attr)))
00725 return -1;
00726 count++;
00727 }
00728 }
00729
00730 return count;
00731 }
00732
00733
00734
00735
00736
00737
00738 void radius_msg_make_authenticator(struct radius_msg *msg,
00739 const u8 *data, size_t len)
00740 {
00741 struct os_time tv;
00742 long int l;
00743 const u8 *addr[3];
00744 size_t elen[3];
00745
00746 os_get_time(&tv);
00747 l = os_random();
00748 addr[0] = (u8 *) &tv;
00749 elen[0] = sizeof(tv);
00750 addr[1] = data;
00751 elen[1] = len;
00752 addr[2] = (u8 *) &l;
00753 elen[2] = sizeof(l);
00754 md5_vector(3, addr, elen, msg->hdr->authenticator);
00755 }
00756
00757
00758
00759
00760
00761
00762
00763
00764 static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
00765 u8 subtype, size_t *alen)
00766 {
00767 u8 *data, *pos;
00768 size_t i, len;
00769
00770 if (msg == NULL)
00771 return NULL;
00772
00773 for (i = 0; i < msg->attr_used; i++) {
00774 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
00775 size_t left;
00776 u32 vendor_id;
00777 struct radius_attr_vendor *vhdr;
00778
00779 if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC)
00780 continue;
00781
00782 left = attr->length - sizeof(*attr);
00783 if (left < 4)
00784 continue;
00785
00786 pos = (u8 *) (attr + 1);
00787
00788 os_memcpy(&vendor_id, pos, 4);
00789 pos += 4;
00790 left -= 4;
00791
00792 if (ntohl(vendor_id) != vendor)
00793 continue;
00794
00795 while (left >= sizeof(*vhdr)) {
00796 vhdr = (struct radius_attr_vendor *) pos;
00797 if (vhdr->vendor_length > left ||
00798 vhdr->vendor_length < sizeof(*vhdr)) {
00799 left = 0;
00800 break;
00801 }
00802 if (vhdr->vendor_type != subtype) {
00803 pos += vhdr->vendor_length;
00804 left -= vhdr->vendor_length;
00805 continue;
00806 }
00807
00808 len = vhdr->vendor_length - sizeof(*vhdr);
00809 data = os_malloc(len);
00810 if (data == NULL)
00811 return NULL;
00812 os_memcpy(data, pos + sizeof(*vhdr), len);
00813 if (alen)
00814 *alen = len;
00815 return data;
00816 }
00817 }
00818
00819 return NULL;
00820 }
00821
00822
00823 static u8 * decrypt_ms_key(const u8 *key, size_t len,
00824 const u8 *req_authenticator,
00825 const u8 *secret, size_t secret_len, size_t *reslen)
00826 {
00827 u8 *plain, *ppos, *res;
00828 const u8 *pos;
00829 size_t left, plen;
00830 u8 hash[MD5_MAC_LEN];
00831 int i, first = 1;
00832 const u8 *addr[3];
00833 size_t elen[3];
00834
00835
00836
00837 if (len < 2 + 16)
00838 return NULL;
00839
00840 pos = key + 2;
00841 left = len - 2;
00842 if (left % 16) {
00843 printf("Invalid ms key len %lu\n", (unsigned long) left);
00844 return NULL;
00845 }
00846
00847 plen = left;
00848 ppos = plain = os_malloc(plen);
00849 if (plain == NULL)
00850 return NULL;
00851 plain[0] = 0;
00852
00853 while (left > 0) {
00854
00855
00856
00857 addr[0] = secret;
00858 elen[0] = secret_len;
00859 if (first) {
00860 addr[1] = req_authenticator;
00861 elen[1] = MD5_MAC_LEN;
00862 addr[2] = key;
00863 elen[2] = 2;
00864 } else {
00865 addr[1] = pos - MD5_MAC_LEN;
00866 elen[1] = MD5_MAC_LEN;
00867 }
00868 md5_vector(first ? 3 : 2, addr, elen, hash);
00869 first = 0;
00870
00871 for (i = 0; i < MD5_MAC_LEN; i++)
00872 *ppos++ = *pos++ ^ hash[i];
00873 left -= MD5_MAC_LEN;
00874 }
00875
00876 if (plain[0] == 0 || plain[0] > plen - 1) {
00877 printf("Failed to decrypt MPPE key\n");
00878 os_free(plain);
00879 return NULL;
00880 }
00881
00882 res = os_malloc(plain[0]);
00883 if (res == NULL) {
00884 os_free(plain);
00885 return NULL;
00886 }
00887 os_memcpy(res, plain + 1, plain[0]);
00888 if (reslen)
00889 *reslen = plain[0];
00890 os_free(plain);
00891 return res;
00892 }
00893
00894
00895 static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt,
00896 const u8 *req_authenticator,
00897 const u8 *secret, size_t secret_len,
00898 u8 *ebuf, size_t *elen)
00899 {
00900 int i, len, first = 1;
00901 u8 hash[MD5_MAC_LEN], saltbuf[2], *pos;
00902 const u8 *addr[3];
00903 size_t _len[3];
00904
00905 WPA_PUT_BE16(saltbuf, salt);
00906
00907 len = 1 + key_len;
00908 if (len & 0x0f) {
00909 len = (len & 0xf0) + 16;
00910 }
00911 os_memset(ebuf, 0, len);
00912 ebuf[0] = key_len;
00913 os_memcpy(ebuf + 1, key, key_len);
00914
00915 *elen = len;
00916
00917 pos = ebuf;
00918 while (len > 0) {
00919
00920
00921 addr[0] = secret;
00922 _len[0] = secret_len;
00923 if (first) {
00924 addr[1] = req_authenticator;
00925 _len[1] = MD5_MAC_LEN;
00926 addr[2] = saltbuf;
00927 _len[2] = sizeof(saltbuf);
00928 } else {
00929 addr[1] = pos - MD5_MAC_LEN;
00930 _len[1] = MD5_MAC_LEN;
00931 }
00932 md5_vector(first ? 3 : 2, addr, _len, hash);
00933 first = 0;
00934
00935 for (i = 0; i < MD5_MAC_LEN; i++)
00936 *pos++ ^= hash[i];
00937
00938 len -= MD5_MAC_LEN;
00939 }
00940 }
00941
00942
00943 struct radius_ms_mppe_keys *
00944 radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
00945 const u8 *secret, size_t secret_len)
00946 {
00947 u8 *key;
00948 size_t keylen;
00949 struct radius_ms_mppe_keys *keys;
00950
00951 if (msg == NULL || sent_msg == NULL)
00952 return NULL;
00953
00954 keys = os_zalloc(sizeof(*keys));
00955 if (keys == NULL)
00956 return NULL;
00957
00958 key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
00959 RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY,
00960 &keylen);
00961 if (key) {
00962 keys->send = decrypt_ms_key(key, keylen,
00963 sent_msg->hdr->authenticator,
00964 secret, secret_len,
00965 &keys->send_len);
00966 os_free(key);
00967 }
00968
00969 key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
00970 RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY,
00971 &keylen);
00972 if (key) {
00973 keys->recv = decrypt_ms_key(key, keylen,
00974 sent_msg->hdr->authenticator,
00975 secret, secret_len,
00976 &keys->recv_len);
00977 os_free(key);
00978 }
00979
00980 return keys;
00981 }
00982
00983
00984 struct radius_ms_mppe_keys *
00985 radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
00986 const u8 *secret, size_t secret_len)
00987 {
00988 u8 *key;
00989 size_t keylen;
00990 struct radius_ms_mppe_keys *keys;
00991
00992 if (msg == NULL || sent_msg == NULL)
00993 return NULL;
00994
00995 keys = os_zalloc(sizeof(*keys));
00996 if (keys == NULL)
00997 return NULL;
00998
00999 key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO,
01000 RADIUS_CISCO_AV_PAIR, &keylen);
01001 if (key && keylen == 51 &&
01002 os_memcmp(key, "leap:session-key=", 17) == 0) {
01003 keys->recv = decrypt_ms_key(key + 17, keylen - 17,
01004 sent_msg->hdr->authenticator,
01005 secret, secret_len,
01006 &keys->recv_len);
01007 }
01008 os_free(key);
01009
01010 return keys;
01011 }
01012
01013
01014 int radius_msg_add_mppe_keys(struct radius_msg *msg,
01015 const u8 *req_authenticator,
01016 const u8 *secret, size_t secret_len,
01017 const u8 *send_key, size_t send_key_len,
01018 const u8 *recv_key, size_t recv_key_len)
01019 {
01020 struct radius_attr_hdr *attr;
01021 u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT);
01022 u8 *buf;
01023 struct radius_attr_vendor *vhdr;
01024 u8 *pos;
01025 size_t elen;
01026 int hlen;
01027 u16 salt;
01028
01029 hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2;
01030
01031
01032 buf = os_malloc(hlen + send_key_len + 16);
01033 if (buf == NULL) {
01034 return 0;
01035 }
01036 pos = buf;
01037 os_memcpy(pos, &vendor_id, sizeof(vendor_id));
01038 pos += sizeof(vendor_id);
01039 vhdr = (struct radius_attr_vendor *) pos;
01040 vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY;
01041 pos = (u8 *) (vhdr + 1);
01042 salt = os_random() | 0x8000;
01043 WPA_PUT_BE16(pos, salt);
01044 pos += 2;
01045 encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret,
01046 secret_len, pos, &elen);
01047 vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
01048
01049 attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
01050 buf, hlen + elen);
01051 os_free(buf);
01052 if (attr == NULL) {
01053 return 0;
01054 }
01055
01056
01057 buf = os_malloc(hlen + send_key_len + 16);
01058 if (buf == NULL) {
01059 return 0;
01060 }
01061 pos = buf;
01062 os_memcpy(pos, &vendor_id, sizeof(vendor_id));
01063 pos += sizeof(vendor_id);
01064 vhdr = (struct radius_attr_vendor *) pos;
01065 vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY;
01066 pos = (u8 *) (vhdr + 1);
01067 salt ^= 1;
01068 WPA_PUT_BE16(pos, salt);
01069 pos += 2;
01070 encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret,
01071 secret_len, pos, &elen);
01072 vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
01073
01074 attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
01075 buf, hlen + elen);
01076 os_free(buf);
01077 if (attr == NULL) {
01078 return 0;
01079 }
01080
01081 return 1;
01082 }
01083
01084
01085
01086
01087 struct radius_attr_hdr *
01088 radius_msg_add_attr_user_password(struct radius_msg *msg,
01089 const u8 *data, size_t data_len,
01090 const u8 *secret, size_t secret_len)
01091 {
01092 u8 buf[128];
01093 int padlen, i;
01094 size_t buf_len, pos;
01095 const u8 *addr[2];
01096 size_t len[2];
01097 u8 hash[16];
01098
01099 if (data_len > 128)
01100 return NULL;
01101
01102 os_memcpy(buf, data, data_len);
01103 buf_len = data_len;
01104
01105 padlen = data_len % 16;
01106 if (padlen) {
01107 padlen = 16 - padlen;
01108 os_memset(buf + data_len, 0, padlen);
01109 buf_len += padlen;
01110 }
01111
01112 addr[0] = secret;
01113 len[0] = secret_len;
01114 addr[1] = msg->hdr->authenticator;
01115 len[1] = 16;
01116 md5_vector(2, addr, len, hash);
01117
01118 for (i = 0; i < 16; i++)
01119 buf[i] ^= hash[i];
01120 pos = 16;
01121
01122 while (pos < buf_len) {
01123 addr[0] = secret;
01124 len[0] = secret_len;
01125 addr[1] = &buf[pos - 16];
01126 len[1] = 16;
01127 md5_vector(2, addr, len, hash);
01128
01129 for (i = 0; i < 16; i++)
01130 buf[pos + i] ^= hash[i];
01131
01132 pos += 16;
01133 }
01134
01135 return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD,
01136 buf, buf_len);
01137 }
01138
01139
01140 int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
01141 {
01142 struct radius_attr_hdr *attr = NULL, *tmp;
01143 size_t i, dlen;
01144
01145 for (i = 0; i < msg->attr_used; i++) {
01146 tmp = radius_get_attr_hdr(msg, i);
01147 if (tmp->type == type) {
01148 attr = tmp;
01149 break;
01150 }
01151 }
01152
01153 if (!attr)
01154 return -1;
01155
01156 dlen = attr->length - sizeof(*attr);
01157 if (buf)
01158 os_memcpy(buf, (attr + 1), dlen > len ? len : dlen);
01159 return dlen;
01160 }
01161
01162
01163 int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
01164 size_t *len, const u8 *start)
01165 {
01166 size_t i;
01167 struct radius_attr_hdr *attr = NULL, *tmp;
01168
01169 for (i = 0; i < msg->attr_used; i++) {
01170 tmp = radius_get_attr_hdr(msg, i);
01171 if (tmp->type == type &&
01172 (start == NULL || (u8 *) tmp > start)) {
01173 attr = tmp;
01174 break;
01175 }
01176 }
01177
01178 if (!attr)
01179 return -1;
01180
01181 *buf = (u8 *) (attr + 1);
01182 *len = attr->length - sizeof(*attr);
01183 return 0;
01184 }
01185
01186
01187 int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len)
01188 {
01189 size_t i;
01190 int count;
01191
01192 for (count = 0, i = 0; i < msg->attr_used; i++) {
01193 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
01194 if (attr->type == type &&
01195 attr->length >= sizeof(struct radius_attr_hdr) + min_len)
01196 count++;
01197 }
01198
01199 return count;
01200 }
01201
01202
01203 struct radius_tunnel_attrs {
01204 int tag_used;
01205 int type;
01206 int medium_type;
01207 int vlanid;
01208 };
01209
01210
01216 int radius_msg_get_vlanid(struct radius_msg *msg)
01217 {
01218 struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun;
01219 size_t i;
01220 struct radius_attr_hdr *attr = NULL;
01221 const u8 *data;
01222 char buf[10];
01223 size_t dlen;
01224
01225 os_memset(&tunnel, 0, sizeof(tunnel));
01226
01227 for (i = 0; i < msg->attr_used; i++) {
01228 attr = radius_get_attr_hdr(msg, i);
01229 data = (const u8 *) (attr + 1);
01230 dlen = attr->length - sizeof(*attr);
01231 if (attr->length < 3)
01232 continue;
01233 if (data[0] >= RADIUS_TUNNEL_TAGS)
01234 tun = &tunnel[0];
01235 else
01236 tun = &tunnel[data[0]];
01237
01238 switch (attr->type) {
01239 case RADIUS_ATTR_TUNNEL_TYPE:
01240 if (attr->length != 6)
01241 break;
01242 tun->tag_used++;
01243 tun->type = WPA_GET_BE24(data + 1);
01244 break;
01245 case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE:
01246 if (attr->length != 6)
01247 break;
01248 tun->tag_used++;
01249 tun->medium_type = WPA_GET_BE24(data + 1);
01250 break;
01251 case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID:
01252 if (data[0] < RADIUS_TUNNEL_TAGS) {
01253 data++;
01254 dlen--;
01255 }
01256 if (dlen >= sizeof(buf))
01257 break;
01258 os_memcpy(buf, data, dlen);
01259 buf[dlen] = '\0';
01260 tun->tag_used++;
01261 tun->vlanid = atoi(buf);
01262 break;
01263 }
01264 }
01265
01266 for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) {
01267 tun = &tunnel[i];
01268 if (tun->tag_used &&
01269 tun->type == RADIUS_TUNNEL_TYPE_VLAN &&
01270 tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 &&
01271 tun->vlanid > 0)
01272 return tun->vlanid;
01273 }
01274
01275 return -1;
01276 }
01277
01278
01279 void radius_free_class(struct radius_class_data *c)
01280 {
01281 size_t i;
01282 if (c == NULL)
01283 return;
01284 for (i = 0; i < c->count; i++)
01285 os_free(c->attr[i].data);
01286 os_free(c->attr);
01287 c->attr = NULL;
01288 c->count = 0;
01289 }
01290
01291
01292 int radius_copy_class(struct radius_class_data *dst,
01293 const struct radius_class_data *src)
01294 {
01295 size_t i;
01296
01297 if (src->attr == NULL)
01298 return 0;
01299
01300 dst->attr = os_zalloc(src->count * sizeof(struct radius_attr_data));
01301 if (dst->attr == NULL)
01302 return -1;
01303
01304 dst->count = 0;
01305
01306 for (i = 0; i < src->count; i++) {
01307 dst->attr[i].data = os_malloc(src->attr[i].len);
01308 if (dst->attr[i].data == NULL)
01309 break;
01310 dst->count++;
01311 os_memcpy(dst->attr[i].data, src->attr[i].data,
01312 src->attr[i].len);
01313 dst->attr[i].len = src->attr[i].len;
01314 }
01315
01316 return 0;
01317 }