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