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