2 * RADIUS message processing
3 * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
15 #include "utils/includes.h"
17 #include "utils/common.h"
18 #include "crypto/md5.h"
19 #include "crypto/crypto.h"
23 static struct radius_attr_hdr *
24 radius_get_attr_hdr(struct radius_msg *msg, int idx)
26 return (struct radius_attr_hdr *) (msg->buf + msg->attr_pos[idx]);
30 static void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
32 msg->hdr->code = code;
33 msg->hdr->identifier = identifier;
37 static int radius_msg_initialize(struct radius_msg *msg, size_t init_len)
39 if (init_len < sizeof(struct radius_hdr))
42 msg->buf = os_zalloc(init_len);
46 msg->buf_size = init_len;
47 msg->hdr = (struct radius_hdr *) msg->buf;
48 msg->buf_used = sizeof(*msg->hdr);
51 os_zalloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attr_pos));
52 if (msg->attr_pos == NULL) {
59 msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT;
67 * radius_msg_new - Create a new RADIUS message
68 * @code: Code for RADIUS header
69 * @identifier: Identifier for RADIUS header
70 * Returns: Context for RADIUS message or %NULL on failure
72 * The caller is responsible for freeing the returned data with
75 struct radius_msg * radius_msg_new(u8 code, u8 identifier)
77 struct radius_msg *msg;
79 msg = os_zalloc(sizeof(*msg));
83 if (radius_msg_initialize(msg, RADIUS_DEFAULT_MSG_SIZE)) {
88 radius_msg_set_hdr(msg, code, identifier);
95 * radius_msg_free - Free a RADIUS message
96 * @msg: RADIUS message from radius_msg_new() or radius_msg_parse()
98 void radius_msg_free(struct radius_msg *msg)
104 os_free(msg->attr_pos);
109 static const char *radius_code_string(u8 code)
112 case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request";
113 case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept";
114 case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject";
115 case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request";
116 case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response";
117 case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge";
118 case RADIUS_CODE_STATUS_SERVER: return "Status-Server";
119 case RADIUS_CODE_STATUS_CLIENT: return "Status-Client";
120 case RADIUS_CODE_RESERVED: return "Reserved";
121 default: return "?Unknown?";
126 struct radius_attr_type {
130 RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
131 RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6
135 static struct radius_attr_type radius_attrs[] =
137 { RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT },
138 { RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST },
139 { RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP },
140 { RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 },
141 { RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 },
142 { RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT },
143 { RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST },
144 { RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST },
145 { RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST },
146 { RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 },
147 { RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 },
148 { RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action",
150 { RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id",
152 { RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id",
154 { RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT },
155 { RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST },
156 { RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type",
158 { RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 },
159 { RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets",
161 { RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets",
163 { RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT },
164 { RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 },
165 { RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time",
167 { RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets",
169 { RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets",
171 { RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause",
173 { RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id",
175 { RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 },
176 { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords",
178 { RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords",
180 { RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",
182 { RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 },
183 { RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
184 { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
185 RADIUS_ATTR_HEXDUMP },
186 { RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
187 { RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
188 { RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
189 RADIUS_ATTR_UNDIST },
190 { RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id",
191 RADIUS_ATTR_HEXDUMP },
192 { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
194 { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargable-User-Identity",
196 { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
198 #define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
201 static struct radius_attr_type *radius_get_attr_type(u8 type)
205 for (i = 0; i < RADIUS_ATTRS; i++) {
206 if (type == radius_attrs[i].type)
207 return &radius_attrs[i];
214 static void print_char(char c)
216 if (c >= 32 && c < 127)
223 static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
225 struct radius_attr_type *attr;
229 attr = radius_get_attr_type(hdr->type);
231 printf(" Attribute %d (%s) length=%d\n",
232 hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
237 len = hdr->length - sizeof(struct radius_attr_hdr);
238 pos = (unsigned char *) (hdr + 1);
240 switch (attr->data_type) {
241 case RADIUS_ATTR_TEXT:
243 for (i = 0; i < len; i++)
251 os_memcpy(&addr, pos, 4);
252 printf(" Value: %s\n", inet_ntoa(addr));
254 printf(" Invalid IP address length %d\n", len);
258 case RADIUS_ATTR_IPV6:
262 struct in6_addr *addr = (struct in6_addr *) pos;
263 atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf));
264 printf(" Value: %s\n", atxt ? atxt : "?");
266 printf(" Invalid IPv6 address length %d\n", len);
268 #endif /* CONFIG_IPV6 */
270 case RADIUS_ATTR_HEXDUMP:
271 case RADIUS_ATTR_UNDIST:
273 for (i = 0; i < len; i++)
274 printf(" %02x", pos[i]);
278 case RADIUS_ATTR_INT32:
280 printf(" Value: %u\n", WPA_GET_BE32(pos));
282 printf(" Invalid INT32 length %d\n", len);
291 void radius_msg_dump(struct radius_msg *msg)
295 printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",
296 msg->hdr->code, radius_code_string(msg->hdr->code),
297 msg->hdr->identifier, ntohs(msg->hdr->length));
299 for (i = 0; i < msg->attr_used; i++) {
300 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
301 radius_msg_dump_attr(attr);
306 int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
310 u8 auth[MD5_MAC_LEN];
311 struct radius_attr_hdr *attr;
313 os_memset(auth, 0, MD5_MAC_LEN);
314 attr = radius_msg_add_attr(msg,
315 RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
318 printf("WARNING: Could not add "
319 "Message-Authenticator\n");
322 msg->hdr->length = htons(msg->buf_used);
323 hmac_md5(secret, secret_len, msg->buf, msg->buf_used,
326 msg->hdr->length = htons(msg->buf_used);
328 if (msg->buf_used > 0xffff) {
329 printf("WARNING: too long RADIUS message (%lu)\n",
330 (unsigned long) msg->buf_used);
337 int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
338 size_t secret_len, const u8 *req_authenticator)
340 u8 auth[MD5_MAC_LEN];
341 struct radius_attr_hdr *attr;
345 os_memset(auth, 0, MD5_MAC_LEN);
346 attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
349 printf("WARNING: Could not add Message-Authenticator\n");
352 msg->hdr->length = htons(msg->buf_used);
353 os_memcpy(msg->hdr->authenticator, req_authenticator,
354 sizeof(msg->hdr->authenticator));
355 hmac_md5(secret, secret_len, msg->buf, msg->buf_used,
358 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
359 addr[0] = (u8 *) msg->hdr;
361 addr[1] = req_authenticator;
362 len[1] = MD5_MAC_LEN;
363 addr[2] = (u8 *) (msg->hdr + 1);
364 len[2] = msg->buf_used - sizeof(*msg->hdr);
367 md5_vector(4, addr, len, msg->hdr->authenticator);
369 if (msg->buf_used > 0xffff) {
370 printf("WARNING: too long RADIUS message (%lu)\n",
371 (unsigned long) msg->buf_used);
378 void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
384 msg->hdr->length = htons(msg->buf_used);
385 os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
387 len[0] = msg->buf_used;
390 md5_vector(2, addr, len, msg->hdr->authenticator);
392 if (msg->buf_used > 0xffff) {
393 printf("WARNING: too long RADIUS messages (%lu)\n",
394 (unsigned long) msg->buf_used);
399 static int radius_msg_add_attr_to_array(struct radius_msg *msg,
400 struct radius_attr_hdr *attr)
402 if (msg->attr_used >= msg->attr_size) {
404 int nlen = msg->attr_size * 2;
406 nattr_pos = os_realloc(msg->attr_pos,
407 nlen * sizeof(*msg->attr_pos));
408 if (nattr_pos == NULL)
411 msg->attr_pos = nattr_pos;
412 msg->attr_size = nlen;
415 msg->attr_pos[msg->attr_used++] = (unsigned char *) attr - msg->buf;
421 struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
422 const u8 *data, size_t data_len)
425 struct radius_attr_hdr *attr;
427 if (data_len > RADIUS_MAX_ATTR_LEN) {
428 printf("radius_msg_add_attr: too long attribute (%lu bytes)\n",
429 (unsigned long) data_len);
433 buf_needed = msg->buf_used + sizeof(*attr) + data_len;
435 if (msg->buf_size < buf_needed) {
436 /* allocate more space for message buffer */
438 size_t nlen = msg->buf_size;
440 while (nlen < buf_needed)
442 nbuf = os_realloc(msg->buf, nlen);
446 msg->hdr = (struct radius_hdr *) msg->buf;
447 os_memset(msg->buf + msg->buf_size, 0, nlen - msg->buf_size);
448 msg->buf_size = nlen;
451 attr = (struct radius_attr_hdr *) (msg->buf + msg->buf_used);
453 attr->length = sizeof(*attr) + data_len;
455 os_memcpy(attr + 1, data, data_len);
457 msg->buf_used += sizeof(*attr) + data_len;
459 if (radius_msg_add_attr_to_array(msg, attr))
467 * radius_msg_parse - Parse a RADIUS message
468 * @data: RADIUS message to be parsed
469 * @len: Length of data buffer in octets
470 * Returns: Parsed RADIUS message or %NULL on failure
472 * This parses a RADIUS message and makes a copy of its data. The caller is
473 * responsible for freeing the returned data with radius_msg_free().
475 struct radius_msg * radius_msg_parse(const u8 *data, size_t len)
477 struct radius_msg *msg;
478 struct radius_hdr *hdr;
479 struct radius_attr_hdr *attr;
481 unsigned char *pos, *end;
483 if (data == NULL || len < sizeof(*hdr))
486 hdr = (struct radius_hdr *) data;
488 msg_len = ntohs(hdr->length);
489 if (msg_len < sizeof(*hdr) || msg_len > len) {
490 wpa_printf(MSG_INFO, "RADIUS: Invalid message length");
495 wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after "
496 "RADIUS message", (unsigned long) len - msg_len);
499 msg = os_zalloc(sizeof(*msg));
503 if (radius_msg_initialize(msg, msg_len)) {
508 os_memcpy(msg->buf, data, msg_len);
509 msg->buf_size = msg->buf_used = msg_len;
511 /* parse attributes */
512 pos = (unsigned char *) (msg->hdr + 1);
513 end = msg->buf + msg->buf_used;
515 if ((size_t) (end - pos) < sizeof(*attr))
518 attr = (struct radius_attr_hdr *) pos;
520 if (pos + attr->length > end || attr->length < sizeof(*attr))
523 /* TODO: check that attr->length is suitable for attr->type */
525 if (radius_msg_add_attr_to_array(msg, attr))
534 radius_msg_free(msg);
539 int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len)
541 const u8 *pos = data;
542 size_t left = data_len;
546 if (left > RADIUS_MAX_ATTR_LEN)
547 len = RADIUS_MAX_ATTR_LEN;
551 if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE,
563 u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len)
567 struct radius_attr_hdr *attr;
573 for (i = 0; i < msg->attr_used; i++) {
574 attr = radius_get_attr_hdr(msg, i);
575 if (attr->type == RADIUS_ATTR_EAP_MESSAGE)
576 len += attr->length - sizeof(struct radius_attr_hdr);
582 eap = os_malloc(len);
587 for (i = 0; i < msg->attr_used; i++) {
588 attr = radius_get_attr_hdr(msg, i);
589 if (attr->type == RADIUS_ATTR_EAP_MESSAGE) {
590 int flen = attr->length - sizeof(*attr);
591 os_memcpy(pos, attr + 1, flen);
603 int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
604 size_t secret_len, const u8 *req_auth)
606 u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
607 u8 orig_authenticator[16];
608 struct radius_attr_hdr *attr = NULL, *tmp;
611 for (i = 0; i < msg->attr_used; i++) {
612 tmp = radius_get_attr_hdr(msg, i);
613 if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
615 printf("Multiple Message-Authenticator "
616 "attributes in RADIUS message\n");
624 printf("No Message-Authenticator attribute found\n");
628 os_memcpy(orig, attr + 1, MD5_MAC_LEN);
629 os_memset(attr + 1, 0, MD5_MAC_LEN);
631 os_memcpy(orig_authenticator, msg->hdr->authenticator,
632 sizeof(orig_authenticator));
633 os_memcpy(msg->hdr->authenticator, req_auth,
634 sizeof(msg->hdr->authenticator));
636 hmac_md5(secret, secret_len, msg->buf, msg->buf_used, auth);
637 os_memcpy(attr + 1, orig, MD5_MAC_LEN);
639 os_memcpy(msg->hdr->authenticator, orig_authenticator,
640 sizeof(orig_authenticator));
643 if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) {
644 printf("Invalid Message-Authenticator!\n");
652 int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
653 size_t secret_len, struct radius_msg *sent_msg, int auth)
657 u8 hash[MD5_MAC_LEN];
659 if (sent_msg == NULL) {
660 printf("No matching Access-Request message found\n");
665 radius_msg_verify_msg_auth(msg, secret, secret_len,
666 sent_msg->hdr->authenticator)) {
670 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
671 addr[0] = (u8 *) msg->hdr;
673 addr[1] = sent_msg->hdr->authenticator;
674 len[1] = MD5_MAC_LEN;
675 addr[2] = (u8 *) (msg->hdr + 1);
676 len[2] = msg->buf_used - sizeof(*msg->hdr);
679 md5_vector(4, addr, len, hash);
680 if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
681 printf("Response Authenticator invalid!\n");
689 int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
692 struct radius_attr_hdr *attr;
696 for (i = 0; i < src->attr_used; i++) {
697 attr = radius_get_attr_hdr(src, i);
698 if (attr->type == type) {
699 if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1),
700 attr->length - sizeof(*attr)))
710 /* Create Request Authenticator. The value should be unique over the lifetime
711 * of the shared secret between authenticator and authentication server.
712 * Use one-way MD5 hash calculated from current timestamp and some data given
714 void radius_msg_make_authenticator(struct radius_msg *msg,
715 const u8 *data, size_t len)
724 addr[0] = (u8 *) &tv;
725 elen[0] = sizeof(tv);
730 md5_vector(3, addr, elen, msg->hdr->authenticator);
734 /* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message.
735 * Returns the Attribute payload and sets alen to indicate the length of the
736 * payload if a vendor attribute with subtype is found, otherwise returns NULL.
737 * The returned payload is allocated with os_malloc() and caller must free it
738 * by calling os_free().
740 static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
741 u8 subtype, size_t *alen)
749 for (i = 0; i < msg->attr_used; i++) {
750 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
753 struct radius_attr_vendor *vhdr;
755 if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC)
758 left = attr->length - sizeof(*attr);
762 pos = (u8 *) (attr + 1);
764 os_memcpy(&vendor_id, pos, 4);
768 if (ntohl(vendor_id) != vendor)
771 while (left >= sizeof(*vhdr)) {
772 vhdr = (struct radius_attr_vendor *) pos;
773 if (vhdr->vendor_length > left ||
774 vhdr->vendor_length < sizeof(*vhdr)) {
778 if (vhdr->vendor_type != subtype) {
779 pos += vhdr->vendor_length;
780 left -= vhdr->vendor_length;
784 len = vhdr->vendor_length - sizeof(*vhdr);
785 data = os_malloc(len);
788 os_memcpy(data, pos + sizeof(*vhdr), len);
799 static u8 * decrypt_ms_key(const u8 *key, size_t len,
800 const u8 *req_authenticator,
801 const u8 *secret, size_t secret_len, size_t *reslen)
803 u8 *plain, *ppos, *res;
806 u8 hash[MD5_MAC_LEN];
811 /* key: 16-bit salt followed by encrypted key info */
819 printf("Invalid ms key len %lu\n", (unsigned long) left);
824 ppos = plain = os_malloc(plen);
830 /* b(1) = MD5(Secret + Request-Authenticator + Salt)
831 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
834 elen[0] = secret_len;
836 addr[1] = req_authenticator;
837 elen[1] = MD5_MAC_LEN;
839 elen[2] = 2; /* Salt */
841 addr[1] = pos - MD5_MAC_LEN;
842 elen[1] = MD5_MAC_LEN;
844 md5_vector(first ? 3 : 2, addr, elen, hash);
847 for (i = 0; i < MD5_MAC_LEN; i++)
848 *ppos++ = *pos++ ^ hash[i];
852 if (plain[0] == 0 || plain[0] > plen - 1) {
853 printf("Failed to decrypt MPPE key\n");
858 res = os_malloc(plain[0]);
863 os_memcpy(res, plain + 1, plain[0]);
871 static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt,
872 const u8 *req_authenticator,
873 const u8 *secret, size_t secret_len,
874 u8 *ebuf, size_t *elen)
876 int i, len, first = 1;
877 u8 hash[MD5_MAC_LEN], saltbuf[2], *pos;
881 WPA_PUT_BE16(saltbuf, salt);
885 len = (len & 0xf0) + 16;
887 os_memset(ebuf, 0, len);
889 os_memcpy(ebuf + 1, key, key_len);
895 /* b(1) = MD5(Secret + Request-Authenticator + Salt)
896 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
898 _len[0] = secret_len;
900 addr[1] = req_authenticator;
901 _len[1] = MD5_MAC_LEN;
903 _len[2] = sizeof(saltbuf);
905 addr[1] = pos - MD5_MAC_LEN;
906 _len[1] = MD5_MAC_LEN;
908 md5_vector(first ? 3 : 2, addr, _len, hash);
911 for (i = 0; i < MD5_MAC_LEN; i++)
919 struct radius_ms_mppe_keys *
920 radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
921 const u8 *secret, size_t secret_len)
925 struct radius_ms_mppe_keys *keys;
927 if (msg == NULL || sent_msg == NULL)
930 keys = os_zalloc(sizeof(*keys));
934 key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
935 RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY,
938 keys->send = decrypt_ms_key(key, keylen,
939 sent_msg->hdr->authenticator,
945 key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
946 RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY,
949 keys->recv = decrypt_ms_key(key, keylen,
950 sent_msg->hdr->authenticator,
960 struct radius_ms_mppe_keys *
961 radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
962 const u8 *secret, size_t secret_len)
966 struct radius_ms_mppe_keys *keys;
968 if (msg == NULL || sent_msg == NULL)
971 keys = os_zalloc(sizeof(*keys));
975 key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO,
976 RADIUS_CISCO_AV_PAIR, &keylen);
977 if (key && keylen == 51 &&
978 os_memcmp(key, "leap:session-key=", 17) == 0) {
979 keys->recv = decrypt_ms_key(key + 17, keylen - 17,
980 sent_msg->hdr->authenticator,
990 int radius_msg_add_mppe_keys(struct radius_msg *msg,
991 const u8 *req_authenticator,
992 const u8 *secret, size_t secret_len,
993 const u8 *send_key, size_t send_key_len,
994 const u8 *recv_key, size_t recv_key_len)
996 struct radius_attr_hdr *attr;
997 u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT);
999 struct radius_attr_vendor *vhdr;
1005 hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2;
1007 /* MS-MPPE-Send-Key */
1008 buf = os_malloc(hlen + send_key_len + 16);
1013 os_memcpy(pos, &vendor_id, sizeof(vendor_id));
1014 pos += sizeof(vendor_id);
1015 vhdr = (struct radius_attr_vendor *) pos;
1016 vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY;
1017 pos = (u8 *) (vhdr + 1);
1018 salt = os_random() | 0x8000;
1019 WPA_PUT_BE16(pos, salt);
1021 encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret,
1022 secret_len, pos, &elen);
1023 vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
1025 attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
1032 /* MS-MPPE-Recv-Key */
1033 buf = os_malloc(hlen + send_key_len + 16);
1038 os_memcpy(pos, &vendor_id, sizeof(vendor_id));
1039 pos += sizeof(vendor_id);
1040 vhdr = (struct radius_attr_vendor *) pos;
1041 vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY;
1042 pos = (u8 *) (vhdr + 1);
1044 WPA_PUT_BE16(pos, salt);
1046 encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret,
1047 secret_len, pos, &elen);
1048 vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
1050 attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
1061 /* Add User-Password attribute to a RADIUS message and encrypt it as specified
1062 * in RFC 2865, Chap. 5.2 */
1063 struct radius_attr_hdr *
1064 radius_msg_add_attr_user_password(struct radius_msg *msg,
1065 const u8 *data, size_t data_len,
1066 const u8 *secret, size_t secret_len)
1070 size_t buf_len, pos;
1078 os_memcpy(buf, data, data_len);
1081 padlen = data_len % 16;
1083 padlen = 16 - padlen;
1084 os_memset(buf + data_len, 0, padlen);
1089 len[0] = secret_len;
1090 addr[1] = msg->hdr->authenticator;
1092 md5_vector(2, addr, len, hash);
1094 for (i = 0; i < 16; i++)
1098 while (pos < buf_len) {
1100 len[0] = secret_len;
1101 addr[1] = &buf[pos - 16];
1103 md5_vector(2, addr, len, hash);
1105 for (i = 0; i < 16; i++)
1106 buf[pos + i] ^= hash[i];
1111 return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD,
1116 int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
1118 struct radius_attr_hdr *attr = NULL, *tmp;
1121 for (i = 0; i < msg->attr_used; i++) {
1122 tmp = radius_get_attr_hdr(msg, i);
1123 if (tmp->type == type) {
1132 dlen = attr->length - sizeof(*attr);
1134 os_memcpy(buf, (attr + 1), dlen > len ? len : dlen);
1139 int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
1140 size_t *len, const u8 *start)
1143 struct radius_attr_hdr *attr = NULL, *tmp;
1145 for (i = 0; i < msg->attr_used; i++) {
1146 tmp = radius_get_attr_hdr(msg, i);
1147 if (tmp->type == type &&
1148 (start == NULL || (u8 *) tmp > start)) {
1157 *buf = (u8 *) (attr + 1);
1158 *len = attr->length - sizeof(*attr);
1163 int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len)
1168 for (count = 0, i = 0; i < msg->attr_used; i++) {
1169 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
1170 if (attr->type == type &&
1171 attr->length >= sizeof(struct radius_attr_hdr) + min_len)
1179 struct radius_tunnel_attrs {
1181 int type; /* Tunnel-Type */
1182 int medium_type; /* Tunnel-Medium-Type */
1188 * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
1189 * @msg: RADIUS message
1190 * Returns: VLAN ID for the first tunnel configuration of -1 if none is found
1192 int radius_msg_get_vlanid(struct radius_msg *msg)
1194 struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun;
1196 struct radius_attr_hdr *attr = NULL;
1201 os_memset(&tunnel, 0, sizeof(tunnel));
1203 for (i = 0; i < msg->attr_used; i++) {
1204 attr = radius_get_attr_hdr(msg, i);
1205 data = (const u8 *) (attr + 1);
1206 dlen = attr->length - sizeof(*attr);
1207 if (attr->length < 3)
1209 if (data[0] >= RADIUS_TUNNEL_TAGS)
1212 tun = &tunnel[data[0]];
1214 switch (attr->type) {
1215 case RADIUS_ATTR_TUNNEL_TYPE:
1216 if (attr->length != 6)
1219 tun->type = WPA_GET_BE24(data + 1);
1221 case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE:
1222 if (attr->length != 6)
1225 tun->medium_type = WPA_GET_BE24(data + 1);
1227 case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID:
1228 if (data[0] < RADIUS_TUNNEL_TAGS) {
1232 if (dlen >= sizeof(buf))
1234 os_memcpy(buf, data, dlen);
1237 tun->vlanid = atoi(buf);
1242 for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) {
1244 if (tun->tag_used &&
1245 tun->type == RADIUS_TUNNEL_TYPE_VLAN &&
1246 tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 &&
1255 void radius_free_class(struct radius_class_data *c)
1260 for (i = 0; i < c->count; i++)
1261 os_free(c->attr[i].data);
1268 int radius_copy_class(struct radius_class_data *dst,
1269 const struct radius_class_data *src)
1273 if (src->attr == NULL)
1276 dst->attr = os_zalloc(src->count * sizeof(struct radius_attr_data));
1277 if (dst->attr == NULL)
1282 for (i = 0; i < src->count; i++) {
1283 dst->attr[i].data = os_malloc(src->attr[i].len);
1284 if (dst->attr[i].data == NULL)
1287 os_memcpy(dst->attr[i].data, src->attr[i].data,
1289 dst->attr[i].len = src->attr[i].len;