1  /*
2   * RADIUS message processing
3   * Copyright (c) 2002-2009, 2011-2022, Jouni Malinen <j@w1.fi>
4   *
5   * This software may be distributed under the terms of the BSD license.
6   * See README for more details.
7   */
8  
9  #include "utils/includes.h"
10  
11  #include "utils/common.h"
12  #include "utils/wpabuf.h"
13  #include "crypto/md5.h"
14  #include "crypto/crypto.h"
15  #include "radius.h"
16  
17  
18  /**
19   * struct radius_msg - RADIUS message structure for new and parsed messages
20   */
21  struct radius_msg {
22  	/**
23  	 * buf - Allocated buffer for RADIUS message
24  	 */
25  	struct wpabuf *buf;
26  
27  	/**
28  	 * hdr - Pointer to the RADIUS header in buf
29  	 */
30  	struct radius_hdr *hdr;
31  
32  	/**
33  	 * attr_pos - Array of indexes to attributes
34  	 *
35  	 * The values are number of bytes from buf to the beginning of
36  	 * struct radius_attr_hdr.
37  	 */
38  	size_t *attr_pos;
39  
40  	/**
41  	 * attr_size - Total size of the attribute pointer array
42  	 */
43  	size_t attr_size;
44  
45  	/**
46  	 * attr_used - Total number of attributes in the array
47  	 */
48  	size_t attr_used;
49  };
50  
51  
radius_msg_get_hdr(struct radius_msg * msg)52  struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg)
53  {
54  	return msg->hdr;
55  }
56  
57  
radius_msg_get_buf(struct radius_msg * msg)58  struct wpabuf * radius_msg_get_buf(struct radius_msg *msg)
59  {
60  	return msg->buf;
61  }
62  
63  
64  static struct radius_attr_hdr *
radius_get_attr_hdr(struct radius_msg * msg,int idx)65  radius_get_attr_hdr(struct radius_msg *msg, int idx)
66  {
67  	return (struct radius_attr_hdr *)
68  		(wpabuf_mhead_u8(msg->buf) + msg->attr_pos[idx]);
69  }
70  
71  
radius_msg_set_hdr(struct radius_msg * msg,u8 code,u8 identifier)72  static void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
73  {
74  	msg->hdr->code = code;
75  	msg->hdr->identifier = identifier;
76  }
77  
78  
radius_msg_initialize(struct radius_msg * msg)79  static int radius_msg_initialize(struct radius_msg *msg)
80  {
81  	msg->attr_pos = os_calloc(RADIUS_DEFAULT_ATTR_COUNT,
82  				  sizeof(*msg->attr_pos));
83  	if (msg->attr_pos == NULL)
84  		return -1;
85  
86  	msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT;
87  	msg->attr_used = 0;
88  
89  	return 0;
90  }
91  
92  
93  /**
94   * radius_msg_new - Create a new RADIUS message
95   * @code: Code for RADIUS header
96   * @identifier: Identifier for RADIUS header
97   * Returns: Context for RADIUS message or %NULL on failure
98   *
99   * The caller is responsible for freeing the returned data with
100   * radius_msg_free().
101   */
radius_msg_new(u8 code,u8 identifier)102  struct radius_msg * radius_msg_new(u8 code, u8 identifier)
103  {
104  	struct radius_msg *msg;
105  
106  	msg = os_zalloc(sizeof(*msg));
107  	if (msg == NULL)
108  		return NULL;
109  
110  	msg->buf = wpabuf_alloc(RADIUS_DEFAULT_MSG_SIZE);
111  	if (msg->buf == NULL || radius_msg_initialize(msg)) {
112  		radius_msg_free(msg);
113  		return NULL;
114  	}
115  	msg->hdr = wpabuf_put(msg->buf, sizeof(struct radius_hdr));
116  
117  	radius_msg_set_hdr(msg, code, identifier);
118  
119  	return msg;
120  }
121  
122  
123  /**
124   * radius_msg_free - Free a RADIUS message
125   * @msg: RADIUS message from radius_msg_new() or radius_msg_parse()
126   */
radius_msg_free(struct radius_msg * msg)127  void radius_msg_free(struct radius_msg *msg)
128  {
129  	if (msg == NULL)
130  		return;
131  
132  	wpabuf_free(msg->buf);
133  	os_free(msg->attr_pos);
134  	os_free(msg);
135  }
136  
137  
radius_code_string(u8 code)138  static const char *radius_code_string(u8 code)
139  {
140  	switch (code) {
141  	case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request";
142  	case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept";
143  	case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject";
144  	case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request";
145  	case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response";
146  	case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge";
147  	case RADIUS_CODE_STATUS_SERVER: return "Status-Server";
148  	case RADIUS_CODE_STATUS_CLIENT: return "Status-Client";
149  	case RADIUS_CODE_RESERVED: return "Reserved";
150  	case RADIUS_CODE_DISCONNECT_REQUEST: return "Disconnect-Request";
151  	case RADIUS_CODE_DISCONNECT_ACK: return "Disconnect-ACK";
152  	case RADIUS_CODE_DISCONNECT_NAK: return "Disconnect-NAK";
153  	case RADIUS_CODE_COA_REQUEST: return "CoA-Request";
154  	case RADIUS_CODE_COA_ACK: return "CoA-ACK";
155  	case RADIUS_CODE_COA_NAK: return "CoA-NAK";
156  	default: return "?Unknown?";
157  	}
158  }
159  
160  
161  struct radius_attr_type {
162  	u16 type; /* 0..255 for basic types;
163  		   * (241 << 8) | <ext-type> for extended types */
164  	char *name;
165  	enum {
166  		RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
167  		RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6
168  	} data_type;
169  };
170  
171  static const struct radius_attr_type radius_attrs[] =
172  {
173  	{ RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT },
174  	{ RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST },
175  	{ RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP },
176  	{ RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 },
177  	{ RADIUS_ATTR_SERVICE_TYPE, "Service-Type", RADIUS_ATTR_INT32 },
178  	{ RADIUS_ATTR_FRAMED_IP_ADDRESS, "Framed-IP-Address", RADIUS_ATTR_IP },
179  	{ RADIUS_ATTR_FILTER_ID, "Filter-Id", RADIUS_ATTR_TEXT },
180  	{ RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 },
181  	{ RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT },
182  	{ RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST },
183  	{ RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST },
184  	{ RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST },
185  	{ RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 },
186  	{ RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 },
187  	{ RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action",
188  	  RADIUS_ATTR_INT32 },
189  	{ RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id",
190  	  RADIUS_ATTR_TEXT },
191  	{ RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id",
192  	  RADIUS_ATTR_TEXT },
193  	{ RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT },
194  	{ RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST },
195  	{ RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type",
196  	  RADIUS_ATTR_INT32 },
197  	{ RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 },
198  	{ RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets",
199  	  RADIUS_ATTR_INT32 },
200  	{ RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets",
201  	  RADIUS_ATTR_INT32 },
202  	{ RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT },
203  	{ RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 },
204  	{ RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time",
205  	  RADIUS_ATTR_INT32 },
206  	{ RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets",
207  	  RADIUS_ATTR_INT32 },
208  	{ RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets",
209  	  RADIUS_ATTR_INT32 },
210  	{ RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause",
211  	  RADIUS_ATTR_INT32 },
212  	{ RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id",
213  	  RADIUS_ATTR_TEXT },
214  	{ RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 },
215  	{ RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords",
216  	  RADIUS_ATTR_INT32 },
217  	{ RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords",
218  	  RADIUS_ATTR_INT32 },
219  	{ RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",
220  	  RADIUS_ATTR_INT32 },
221  	{ RADIUS_ATTR_EGRESS_VLANID, "EGRESS-VLANID", RADIUS_ATTR_HEXDUMP },
222  	{ RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 },
223  	{ RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
224  	{ RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
225  	  RADIUS_ATTR_HEXDUMP },
226  	{ RADIUS_ATTR_TUNNEL_PASSWORD, "Tunnel-Password",
227  	  RADIUS_ATTR_UNDIST },
228  	{ RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
229  	{ RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
230  	{ RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
231  	  RADIUS_ATTR_UNDIST },
232  	{ RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id",
233  	  RADIUS_ATTR_HEXDUMP },
234  	{ RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
235  	  RADIUS_ATTR_INT32 },
236  	{ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity",
237  	  RADIUS_ATTR_TEXT },
238  	{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
239  	{ RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 },
240  	{ RADIUS_ATTR_EAP_KEY_NAME, "EAP-Key-Name", RADIUS_ATTR_HEXDUMP },
241  	{ RADIUS_ATTR_OPERATOR_NAME, "Operator-Name", RADIUS_ATTR_TEXT },
242  	{ RADIUS_ATTR_LOCATION_INFO, "Location-Information",
243  	  RADIUS_ATTR_HEXDUMP },
244  	{ RADIUS_ATTR_LOCATION_DATA, "Location-Data", RADIUS_ATTR_HEXDUMP },
245  	{ RADIUS_ATTR_BASIC_LOCATION_POLICY_RULES,
246  	  "Basic-Location-Policy-Rules", RADIUS_ATTR_HEXDUMP },
247  	{ RADIUS_ATTR_EXTENDED_LOCATION_POLICY_RULES,
248  	  "Extended-Location-Policy-Rules", RADIUS_ATTR_HEXDUMP },
249  	{ RADIUS_ATTR_LOCATION_CAPABLE, "Location-Capable", RADIUS_ATTR_INT32 },
250  	{ RADIUS_ATTR_REQUESTED_LOCATION_INFO, "Requested-Location-Info",
251  	  RADIUS_ATTR_INT32 },
252  	{ RADIUS_ATTR_MOBILITY_DOMAIN_ID, "Mobility-Domain-Id",
253  	  RADIUS_ATTR_INT32 },
254  	{ RADIUS_ATTR_WLAN_HESSID, "WLAN-HESSID", RADIUS_ATTR_TEXT },
255  	{ RADIUS_ATTR_WLAN_REASON_CODE, "WLAN-Reason-Code",
256  	  RADIUS_ATTR_INT32 },
257  	{ RADIUS_ATTR_WLAN_PAIRWISE_CIPHER, "WLAN-Pairwise-Cipher",
258  	  RADIUS_ATTR_HEXDUMP },
259  	{ RADIUS_ATTR_WLAN_GROUP_CIPHER, "WLAN-Group-Cipher",
260  	  RADIUS_ATTR_HEXDUMP },
261  	{ RADIUS_ATTR_WLAN_AKM_SUITE, "WLAN-AKM-Suite",
262  	  RADIUS_ATTR_HEXDUMP },
263  	{ RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, "WLAN-Group-Mgmt-Pairwise-Cipher",
264  	  RADIUS_ATTR_HEXDUMP },
265  	{ RADIUS_ATTR_EXT_TYPE_1, "Extended-Type-1", RADIUS_ATTR_UNDIST },
266  	{ RADIUS_ATTR_EXT_TYPE_2, "Extended-Type-2", RADIUS_ATTR_UNDIST },
267  	{ RADIUS_ATTR_EXT_TYPE_3, "Extended-Type-3", RADIUS_ATTR_UNDIST },
268  	{ RADIUS_ATTR_EXT_TYPE_4, "Extended-Type-4", RADIUS_ATTR_UNDIST },
269  	{ RADIUS_ATTR_LONG_EXT_TYPE_1, "Long-Extended-Type-1",
270  	  RADIUS_ATTR_UNDIST },
271  	{ RADIUS_ATTR_LONG_EXT_TYPE_2, "Long-Extended-Type-2",
272  	  RADIUS_ATTR_UNDIST },
273  	{ RADIUS_ATTR_EXT_VENDOR_SPECIFIC_1, "Extended-Vendor-Specific-1",
274  	  RADIUS_ATTR_UNDIST },
275  	{ RADIUS_ATTR_EXT_VENDOR_SPECIFIC_2, "Extended-Vendor-Specific-2",
276  	  RADIUS_ATTR_UNDIST },
277  	{ RADIUS_ATTR_EXT_VENDOR_SPECIFIC_3, "Extended-Vendor-Specific-3",
278  	  RADIUS_ATTR_UNDIST },
279  	{ RADIUS_ATTR_EXT_VENDOR_SPECIFIC_4, "Extended-Vendor-Specific-4",
280  	  RADIUS_ATTR_UNDIST },
281  	{ RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5, "Extended-Vendor-Specific-5",
282  	  RADIUS_ATTR_UNDIST },
283  	{ RADIUS_ATTR_EXT_VENDOR_SPECIFIC_6, "Extended-Vendor-Specific-6",
284  	  RADIUS_ATTR_UNDIST },
285  };
286  #define RADIUS_ATTRS ARRAY_SIZE(radius_attrs)
287  
288  
radius_get_attr_type(u16 type)289  static const struct radius_attr_type * radius_get_attr_type(u16 type)
290  {
291  	size_t i;
292  
293  	for (i = 0; i < RADIUS_ATTRS; i++) {
294  		if (type == radius_attrs[i].type)
295  			return &radius_attrs[i];
296  	}
297  
298  	return NULL;
299  }
300  
301  
radius_is_long_ext_type(u8 type)302  static bool radius_is_long_ext_type(u8 type)
303  {
304  	return type == RADIUS_ATTR_LONG_EXT_TYPE_1 ||
305  		type == RADIUS_ATTR_LONG_EXT_TYPE_2;
306  }
307  
308  
radius_is_ext_type(u8 type)309  static bool radius_is_ext_type(u8 type)
310  {
311  	return type >= RADIUS_ATTR_EXT_TYPE_1 &&
312  		type <= RADIUS_ATTR_LONG_EXT_TYPE_2;
313  }
314  
315  
radius_msg_dump_attr(struct radius_attr_hdr * hdr)316  static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
317  {
318  	struct radius_attr_hdr_ext *ext = NULL;
319  	const struct radius_attr_type *attr;
320  	int len;
321  	unsigned char *pos;
322  	char buf[1000];
323  
324  	if (hdr->length < sizeof(struct radius_attr_hdr))
325  		return;
326  
327  	if (radius_is_ext_type(hdr->type)) {
328  		if (hdr->length < 4) {
329  			wpa_printf(MSG_INFO,
330  				   "   Invalid attribute %d (too short for extended type)",
331  				hdr->type);
332  			return;
333  		}
334  
335  		ext = (struct radius_attr_hdr_ext *) hdr;
336  	}
337  
338  	if (ext) {
339  		attr = radius_get_attr_type((ext->type << 8) | ext->ext_type);
340  		wpa_printf(MSG_INFO, "   Attribute %d.%d (%s) length=%d",
341  			   ext->type, ext->ext_type,
342  			   attr ? attr->name : "?Unknown?", ext->length);
343  		pos = (unsigned char *) (ext + 1);
344  		len = ext->length - sizeof(struct radius_attr_hdr_ext);
345  	} else {
346  		attr = radius_get_attr_type(hdr->type);
347  		wpa_printf(MSG_INFO, "   Attribute %d (%s) length=%d",
348  			   hdr->type, attr ? attr->name : "?Unknown?",
349  			   hdr->length);
350  		pos = (unsigned char *) (hdr + 1);
351  		len = hdr->length - sizeof(struct radius_attr_hdr);
352  	}
353  
354  	if (!attr)
355  		return;
356  
357  	switch (attr->data_type) {
358  	case RADIUS_ATTR_TEXT:
359  		printf_encode(buf, sizeof(buf), pos, len);
360  		wpa_printf(MSG_INFO, "      Value: '%s'", buf);
361  		break;
362  
363  	case RADIUS_ATTR_IP:
364  		if (len == 4) {
365  			struct in_addr addr;
366  			os_memcpy(&addr, pos, 4);
367  			wpa_printf(MSG_INFO, "      Value: %s",
368  				   inet_ntoa(addr));
369  		} else {
370  			wpa_printf(MSG_INFO, "      Invalid IP address length %d",
371  				   len);
372  		}
373  		break;
374  
375  #ifdef CONFIG_IPV6
376  	case RADIUS_ATTR_IPV6:
377  		if (len == 16) {
378  			const char *atxt;
379  			struct in6_addr *addr = (struct in6_addr *) pos;
380  			atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf));
381  			wpa_printf(MSG_INFO, "      Value: %s",
382  				   atxt ? atxt : "?");
383  		} else {
384  			wpa_printf(MSG_INFO, "      Invalid IPv6 address length %d",
385  				   len);
386  		}
387  		break;
388  #endif /* CONFIG_IPV6 */
389  
390  	case RADIUS_ATTR_HEXDUMP:
391  	case RADIUS_ATTR_UNDIST:
392  		wpa_snprintf_hex(buf, sizeof(buf), pos, len);
393  		wpa_printf(MSG_INFO, "      Value: %s", buf);
394  		break;
395  
396  	case RADIUS_ATTR_INT32:
397  		if (len == 4)
398  			wpa_printf(MSG_INFO, "      Value: %u",
399  				   WPA_GET_BE32(pos));
400  		else
401  			wpa_printf(MSG_INFO, "      Invalid INT32 length %d",
402  				   len);
403  		break;
404  
405  	default:
406  		break;
407  	}
408  }
409  
410  
radius_msg_dump(struct radius_msg * msg)411  void radius_msg_dump(struct radius_msg *msg)
412  {
413  	size_t i;
414  
415  	wpa_printf(MSG_INFO, "RADIUS message: code=%d (%s) identifier=%d length=%d",
416  		   msg->hdr->code, radius_code_string(msg->hdr->code),
417  		   msg->hdr->identifier, be_to_host16(msg->hdr->length));
418  
419  	for (i = 0; i < msg->attr_used; i++) {
420  		struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
421  		radius_msg_dump_attr(attr);
422  	}
423  }
424  
425  
radius_msg_add_msg_auth(struct radius_msg * msg)426  u8 * radius_msg_add_msg_auth(struct radius_msg *msg)
427  {
428  	u8 auth[MD5_MAC_LEN];
429  	struct radius_attr_hdr *attr;
430  
431  	os_memset(auth, 0, MD5_MAC_LEN);
432  	attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
433  				   auth, MD5_MAC_LEN);
434  	if (!attr) {
435  		wpa_printf(MSG_ERROR,
436  			   "WARNING: Could not add Message-Authenticator");
437  		return NULL;
438  	}
439  
440  	return (u8 *) (attr + 1);
441  }
442  
443  
radius_msg_auth_pos(struct radius_msg * msg)444  static u8 * radius_msg_auth_pos(struct radius_msg *msg)
445  {
446  	u8 *pos;
447  	size_t alen;
448  
449  	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
450  				    &pos, &alen, NULL) == 0 &&
451  	    alen == MD5_MAC_LEN) {
452  		/* Use already added Message-Authenticator attribute */
453  		return pos;
454  	}
455  
456  	/* Add a Message-Authenticator attribute */
457  	return radius_msg_add_msg_auth(msg);
458  }
459  
460  
radius_msg_finish(struct radius_msg * msg,const u8 * secret,size_t secret_len)461  int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
462  		      size_t secret_len)
463  {
464  	if (secret) {
465  		u8 *pos;
466  
467  		pos = radius_msg_auth_pos(msg);
468  		if (!pos)
469  			return -1;
470  		msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
471  		if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
472  			     wpabuf_len(msg->buf), pos) < 0) {
473  			wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
474  			return -1;
475  		}
476  	} else
477  		msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
478  
479  	if (wpabuf_len(msg->buf) > 0xffff) {
480  		wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
481  			   (unsigned long) wpabuf_len(msg->buf));
482  		return -1;
483  	}
484  	return 0;
485  }
486  
487  
radius_msg_finish_srv(struct radius_msg * msg,const u8 * secret,size_t secret_len,const u8 * req_authenticator)488  int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
489  			  size_t secret_len, const u8 *req_authenticator)
490  {
491  	const u8 *addr[4];
492  	size_t len[4];
493  	u8 *pos;
494  
495  	pos = radius_msg_auth_pos(msg);
496  	if (!pos)
497  		return -1;
498  	msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
499  	os_memcpy(msg->hdr->authenticator, req_authenticator,
500  		  sizeof(msg->hdr->authenticator));
501  	if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
502  		     wpabuf_len(msg->buf), pos) < 0) {
503  		wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
504  		return -1;
505  	}
506  
507  	/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
508  	addr[0] = (u8 *) msg->hdr;
509  	len[0] = 1 + 1 + 2;
510  	addr[1] = req_authenticator;
511  	len[1] = MD5_MAC_LEN;
512  	addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
513  	len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
514  	addr[3] = secret;
515  	len[3] = secret_len;
516  	if (md5_vector(4, addr, len, msg->hdr->authenticator) < 0) {
517  		wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
518  		return -1;
519  	}
520  
521  	if (wpabuf_len(msg->buf) > 0xffff) {
522  		wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
523  			   (unsigned long) wpabuf_len(msg->buf));
524  		return -1;
525  	}
526  	return 0;
527  }
528  
529  
radius_msg_finish_das_resp(struct radius_msg * msg,const u8 * secret,size_t secret_len,const struct radius_hdr * req_hdr)530  int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret,
531  			       size_t secret_len,
532  			       const struct radius_hdr *req_hdr)
533  {
534  	const u8 *addr[2];
535  	size_t len[2];
536  	u8 *pos;
537  
538  	pos = radius_msg_auth_pos(msg);
539  	if (!pos)
540  		return -1;
541  
542  	msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
543  	os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16);
544  	if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
545  		     wpabuf_len(msg->buf), pos) < 0) {
546  		wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
547  		return -1;
548  	}
549  
550  	/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
551  	addr[0] = wpabuf_head_u8(msg->buf);
552  	len[0] = wpabuf_len(msg->buf);
553  	addr[1] = secret;
554  	len[1] = secret_len;
555  	if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0) {
556  		wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
557  		return -1;
558  	}
559  
560  	if (wpabuf_len(msg->buf) > 0xffff) {
561  		wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
562  			   (unsigned long) wpabuf_len(msg->buf));
563  		return -1;
564  	}
565  	return 0;
566  }
567  
568  
radius_msg_finish_acct(struct radius_msg * msg,const u8 * secret,size_t secret_len)569  int radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
570  			   size_t secret_len)
571  {
572  	const u8 *addr[2];
573  	size_t len[2];
574  
575  	msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
576  	os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
577  	addr[0] = wpabuf_head(msg->buf);
578  	len[0] = wpabuf_len(msg->buf);
579  	addr[1] = secret;
580  	len[1] = secret_len;
581  	if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0) {
582  		wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
583  		return -1;
584  	}
585  
586  	if (wpabuf_len(msg->buf) > 0xffff) {
587  		wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
588  			   (unsigned long) wpabuf_len(msg->buf));
589  		return -1;
590  	}
591  	return 0;
592  }
593  
594  
radius_msg_finish_acct_resp(struct radius_msg * msg,const u8 * secret,size_t secret_len,const u8 * req_authenticator)595  int radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
596  				size_t secret_len, const u8 *req_authenticator)
597  {
598  	const u8 *addr[2];
599  	size_t len[2];
600  
601  	msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
602  	os_memcpy(msg->hdr->authenticator, req_authenticator, MD5_MAC_LEN);
603  	addr[0] = wpabuf_head(msg->buf);
604  	len[0] = wpabuf_len(msg->buf);
605  	addr[1] = secret;
606  	len[1] = secret_len;
607  	if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0) {
608  		wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
609  		return -1;
610  	}
611  
612  	if (wpabuf_len(msg->buf) > 0xffff) {
613  		wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
614  			   (unsigned long) wpabuf_len(msg->buf));
615  		return -1;
616  	}
617  	return 0;
618  }
619  
620  
radius_msg_verify_acct_req(struct radius_msg * msg,const u8 * secret,size_t secret_len)621  int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
622  			       size_t secret_len)
623  {
624  	const u8 *addr[4];
625  	size_t len[4];
626  	u8 zero[MD5_MAC_LEN];
627  	u8 hash[MD5_MAC_LEN];
628  
629  	os_memset(zero, 0, sizeof(zero));
630  	addr[0] = (u8 *) msg->hdr;
631  	len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN;
632  	addr[1] = zero;
633  	len[1] = MD5_MAC_LEN;
634  	addr[2] = (u8 *) (msg->hdr + 1);
635  	len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
636  	addr[3] = secret;
637  	len[3] = secret_len;
638  	if (md5_vector(4, addr, len, hash) < 0) {
639  		wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
640  		return 1;
641  	}
642  	return os_memcmp_const(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0;
643  }
644  
645  
radius_msg_verify_das_req(struct radius_msg * msg,const u8 * secret,size_t secret_len,int require_message_authenticator)646  int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
647  			      size_t secret_len,
648  			      int require_message_authenticator)
649  {
650  	const u8 *addr[4];
651  	size_t len[4];
652  	u8 zero[MD5_MAC_LEN];
653  	u8 hash[MD5_MAC_LEN];
654  	u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
655  	u8 orig_authenticator[16];
656  
657  	struct radius_attr_hdr *attr = NULL, *tmp;
658  	size_t i;
659  
660  	os_memset(zero, 0, sizeof(zero));
661  	addr[0] = (u8 *) msg->hdr;
662  	len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN;
663  	addr[1] = zero;
664  	len[1] = MD5_MAC_LEN;
665  	addr[2] = (u8 *) (msg->hdr + 1);
666  	len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
667  	addr[3] = secret;
668  	len[3] = secret_len;
669  	if (md5_vector(4, addr, len, hash) < 0) {
670  		wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
671  		return 1;
672  	}
673  	if (os_memcmp_const(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0)
674  		return 1;
675  
676  	for (i = 0; i < msg->attr_used; i++) {
677  		tmp = radius_get_attr_hdr(msg, i);
678  		if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
679  			if (attr != NULL) {
680  				wpa_printf(MSG_WARNING, "Multiple "
681  					   "Message-Authenticator attributes "
682  					   "in RADIUS message");
683  				return 1;
684  			}
685  			attr = tmp;
686  		}
687  	}
688  
689  	if (attr == NULL) {
690  		if (require_message_authenticator) {
691  			wpa_printf(MSG_WARNING,
692  				   "Missing Message-Authenticator attribute in RADIUS message");
693  			return 1;
694  		}
695  		return 0;
696  	}
697  
698  	os_memcpy(orig, attr + 1, MD5_MAC_LEN);
699  	os_memset(attr + 1, 0, MD5_MAC_LEN);
700  	os_memcpy(orig_authenticator, msg->hdr->authenticator,
701  		  sizeof(orig_authenticator));
702  	os_memset(msg->hdr->authenticator, 0,
703  		  sizeof(msg->hdr->authenticator));
704  	if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
705  		     wpabuf_len(msg->buf), auth) < 0) {
706  		wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
707  		return 1;
708  	}
709  	os_memcpy(attr + 1, orig, MD5_MAC_LEN);
710  	os_memcpy(msg->hdr->authenticator, orig_authenticator,
711  		  sizeof(orig_authenticator));
712  
713  	return os_memcmp_const(orig, auth, MD5_MAC_LEN) != 0;
714  }
715  
716  
radius_msg_add_attr_to_array(struct radius_msg * msg,struct radius_attr_hdr * attr)717  static int radius_msg_add_attr_to_array(struct radius_msg *msg,
718  					struct radius_attr_hdr *attr)
719  {
720  	if (msg->attr_used >= msg->attr_size) {
721  		size_t *nattr_pos;
722  		size_t nlen = msg->attr_size * 2;
723  
724  		nattr_pos = os_realloc_array(msg->attr_pos, nlen,
725  					     sizeof(*msg->attr_pos));
726  		if (nattr_pos == NULL)
727  			return -1;
728  
729  		msg->attr_pos = nattr_pos;
730  		msg->attr_size = nlen;
731  	}
732  
733  	msg->attr_pos[msg->attr_used++] =
734  		(unsigned char *) attr - wpabuf_head_u8(msg->buf);
735  
736  	return 0;
737  }
738  
739  
radius_msg_add_attr(struct radius_msg * msg,u16 type,const u8 * data,size_t data_len)740  struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u16 type,
741  					     const u8 *data, size_t data_len)
742  {
743  	size_t buf_needed, max_len;
744  	struct radius_attr_hdr *attr = NULL;
745  	struct radius_attr_hdr_ext *ext;
746  	u8 ext_type = 0;
747  
748  	if (TEST_FAIL())
749  		return NULL;
750  
751  	if (type > 255) {
752  		if (!radius_is_ext_type(type >> 8)) {
753  			wpa_printf(MSG_ERROR,
754  				   "%s: Undefined extended type %d.%d",
755  				   __func__, type >> 8, type & 0xff);
756  			return NULL;
757  		}
758  		ext_type = type & 0xff;
759  		type >>= 8;
760  	} else if (radius_is_ext_type(type)) {
761  		wpa_printf(MSG_ERROR, "%s: Unexpected extended type use for %d",
762  			   __func__, type);
763  	}
764  
765  	if (radius_is_long_ext_type(type)) {
766  		size_t hdr_len = sizeof(struct radius_attr_hdr_ext) + 1;
767  		size_t plen = 255 - hdr_len;
768  		size_t num;
769  
770  		max_len = 4096;
771  		num = (data_len + plen - 1) / plen;
772  		if (num == 0)
773  			num = 1;
774  		buf_needed = num * hdr_len + data_len;
775  	} else if (radius_is_ext_type(type)) {
776  		max_len = RADIUS_MAX_EXT_ATTR_LEN;
777  		buf_needed = sizeof(struct radius_attr_hdr_ext) + data_len;
778  	} else {
779  		max_len = RADIUS_MAX_ATTR_LEN;
780  		buf_needed = sizeof(*attr) + data_len;
781  	}
782  	if (data_len > max_len) {
783  		wpa_printf(MSG_ERROR,
784  			   "%s: too long attribute (%zu > %zu bytes)",
785  			   __func__, data_len, max_len);
786  		return NULL;
787  	}
788  
789  	if (wpabuf_tailroom(msg->buf) < buf_needed) {
790  		/* allocate more space for message buffer */
791  		if (wpabuf_resize(&msg->buf, buf_needed) < 0)
792  			return NULL;
793  		msg->hdr = wpabuf_mhead(msg->buf);
794  	}
795  
796  	if (radius_is_long_ext_type(type)) {
797  		size_t plen = 255 - sizeof(struct radius_attr_hdr_ext) - 1;
798  		size_t alen;
799  
800  		do {
801  			alen = data_len > plen ? plen : data_len;
802  			ext = wpabuf_put(msg->buf,
803  					 sizeof(struct radius_attr_hdr_ext));
804  			if (!attr)
805  				attr = (struct radius_attr_hdr *) ext;
806  			ext->type = type;
807  			ext->length = sizeof(*ext) + 1 + alen;
808  			ext->ext_type = ext_type;
809  			wpabuf_put_u8(msg->buf, data_len > alen ? 0x80 : 0);
810  			wpabuf_put_data(msg->buf, data, data_len);
811  			data += alen;
812  			data_len -= alen;
813  			if (radius_msg_add_attr_to_array(
814  				    msg, (struct radius_attr_hdr *) ext))
815  				return NULL;
816  		} while (data_len > 0);
817  	} else if (radius_is_ext_type(type)) {
818  		ext = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr_ext));
819  		attr = (struct radius_attr_hdr *) ext;
820  		ext->type = type;
821  		ext->length = sizeof(*ext) + data_len;
822  		ext->ext_type = ext_type;
823  		wpabuf_put_data(msg->buf, data, data_len);
824  		if (radius_msg_add_attr_to_array(msg, attr))
825  			return NULL;
826  	} else {
827  		attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr));
828  		attr->type = type;
829  		attr->length = sizeof(*attr) + data_len;
830  		wpabuf_put_data(msg->buf, data, data_len);
831  		if (radius_msg_add_attr_to_array(msg, attr))
832  			return NULL;
833  	}
834  
835  	return attr;
836  }
837  
838  
839  /**
840   * radius_msg_parse - Parse a RADIUS message
841   * @data: RADIUS message to be parsed
842   * @len: Length of data buffer in octets
843   * Returns: Parsed RADIUS message or %NULL on failure
844   *
845   * This parses a RADIUS message and makes a copy of its data. The caller is
846   * responsible for freeing the returned data with radius_msg_free().
847   */
radius_msg_parse(const u8 * data,size_t len)848  struct radius_msg * radius_msg_parse(const u8 *data, size_t len)
849  {
850  	struct radius_msg *msg;
851  	struct radius_hdr *hdr;
852  	struct radius_attr_hdr *attr;
853  	size_t msg_len;
854  	unsigned char *pos, *end;
855  
856  	if (data == NULL || len < sizeof(*hdr))
857  		return NULL;
858  
859  	hdr = (struct radius_hdr *) data;
860  
861  	msg_len = be_to_host16(hdr->length);
862  	if (msg_len < sizeof(*hdr) || msg_len > len) {
863  		wpa_printf(MSG_INFO, "RADIUS: Invalid message length");
864  		return NULL;
865  	}
866  
867  	if (msg_len < len) {
868  		wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after "
869  			   "RADIUS message", (unsigned long) len - msg_len);
870  	}
871  
872  	msg = os_zalloc(sizeof(*msg));
873  	if (msg == NULL)
874  		return NULL;
875  
876  	msg->buf = wpabuf_alloc_copy(data, msg_len);
877  	if (msg->buf == NULL || radius_msg_initialize(msg)) {
878  		radius_msg_free(msg);
879  		return NULL;
880  	}
881  	msg->hdr = wpabuf_mhead(msg->buf);
882  
883  	/* parse attributes */
884  	pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr);
885  	end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf);
886  	while (pos < end) {
887  		if ((size_t) (end - pos) < sizeof(*attr))
888  			goto fail;
889  
890  		attr = (struct radius_attr_hdr *) pos;
891  
892  		if (attr->length > end - pos || attr->length < sizeof(*attr))
893  			goto fail;
894  
895  		/* TODO: check that attr->length is suitable for attr->type */
896  
897  		if (radius_msg_add_attr_to_array(msg, attr))
898  			goto fail;
899  
900  		pos += attr->length;
901  	}
902  
903  	return msg;
904  
905   fail:
906  	radius_msg_free(msg);
907  	return NULL;
908  }
909  
910  
radius_msg_add_eap(struct radius_msg * msg,const u8 * data,size_t data_len)911  int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len)
912  {
913  	const u8 *pos = data;
914  	size_t left = data_len;
915  
916  	while (left > 0) {
917  		int len;
918  		if (left > RADIUS_MAX_ATTR_LEN)
919  			len = RADIUS_MAX_ATTR_LEN;
920  		else
921  			len = left;
922  
923  		if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE,
924  					 pos, len))
925  			return 0;
926  
927  		pos += len;
928  		left -= len;
929  	}
930  
931  	return 1;
932  }
933  
934  
radius_msg_get_eap(struct radius_msg * msg)935  struct wpabuf * radius_msg_get_eap(struct radius_msg *msg)
936  {
937  	struct wpabuf *eap;
938  	size_t len, i;
939  	struct radius_attr_hdr *attr;
940  
941  	if (msg == NULL)
942  		return NULL;
943  
944  	len = 0;
945  	for (i = 0; i < msg->attr_used; i++) {
946  		attr = radius_get_attr_hdr(msg, i);
947  		if (attr->type == RADIUS_ATTR_EAP_MESSAGE &&
948  		    attr->length > sizeof(struct radius_attr_hdr))
949  			len += attr->length - sizeof(struct radius_attr_hdr);
950  	}
951  
952  	if (len == 0)
953  		return NULL;
954  
955  	eap = wpabuf_alloc(len);
956  	if (eap == NULL)
957  		return NULL;
958  
959  	for (i = 0; i < msg->attr_used; i++) {
960  		attr = radius_get_attr_hdr(msg, i);
961  		if (attr->type == RADIUS_ATTR_EAP_MESSAGE &&
962  		    attr->length > sizeof(struct radius_attr_hdr)) {
963  			int flen = attr->length - sizeof(*attr);
964  			wpabuf_put_data(eap, attr + 1, flen);
965  		}
966  	}
967  
968  	return eap;
969  }
970  
971  
radius_msg_verify_msg_auth(struct radius_msg * msg,const u8 * secret,size_t secret_len,const u8 * req_auth)972  int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
973  			       size_t secret_len, const u8 *req_auth)
974  {
975  	u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
976  	u8 orig_authenticator[16];
977  	struct radius_attr_hdr *attr = NULL, *tmp;
978  	size_t i;
979  
980  	for (i = 0; i < msg->attr_used; i++) {
981  		tmp = radius_get_attr_hdr(msg, i);
982  		if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
983  			if (attr != NULL) {
984  				wpa_printf(MSG_INFO, "Multiple Message-Authenticator attributes in RADIUS message");
985  				return 1;
986  			}
987  			attr = tmp;
988  		}
989  	}
990  
991  	if (attr == NULL) {
992  		wpa_printf(MSG_INFO, "No Message-Authenticator attribute found");
993  		return 1;
994  	}
995  
996  	os_memcpy(orig, attr + 1, MD5_MAC_LEN);
997  	os_memset(attr + 1, 0, MD5_MAC_LEN);
998  	if (req_auth) {
999  		os_memcpy(orig_authenticator, msg->hdr->authenticator,
1000  			  sizeof(orig_authenticator));
1001  		os_memcpy(msg->hdr->authenticator, req_auth,
1002  			  sizeof(msg->hdr->authenticator));
1003  	}
1004  	if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
1005  		     wpabuf_len(msg->buf), auth) < 0) {
1006  		wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
1007  		return 1;
1008  	}
1009  	os_memcpy(attr + 1, orig, MD5_MAC_LEN);
1010  	if (req_auth) {
1011  		os_memcpy(msg->hdr->authenticator, orig_authenticator,
1012  			  sizeof(orig_authenticator));
1013  	}
1014  
1015  	if (os_memcmp_const(orig, auth, MD5_MAC_LEN) != 0) {
1016  		wpa_printf(MSG_INFO, "Invalid Message-Authenticator!");
1017  		return 1;
1018  	}
1019  
1020  	return 0;
1021  }
1022  
1023  
radius_msg_verify(struct radius_msg * msg,const u8 * secret,size_t secret_len,struct radius_msg * sent_msg,int auth)1024  int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
1025  		      size_t secret_len, struct radius_msg *sent_msg, int auth)
1026  {
1027  	const u8 *addr[4];
1028  	size_t len[4];
1029  	u8 hash[MD5_MAC_LEN];
1030  
1031  	if (sent_msg == NULL) {
1032  		wpa_printf(MSG_INFO, "No matching Access-Request message found");
1033  		return 1;
1034  	}
1035  
1036  	if (!auth) {
1037  		u8 *pos;
1038  		size_t alen;
1039  
1040  		if (radius_msg_get_attr_ptr(msg,
1041  					    RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
1042  					    &pos, &alen, NULL) == 0) {
1043  			/* Check the Message-Authenticator attribute since it
1044  			 * was included even if we are configured to not
1045  			 * require it. */
1046  			auth = 1;
1047  		}
1048  	}
1049  
1050  	if (auth &&
1051  	    radius_msg_verify_msg_auth(msg, secret, secret_len,
1052  				       sent_msg->hdr->authenticator)) {
1053  		return 1;
1054  	}
1055  
1056  	/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
1057  	addr[0] = (u8 *) msg->hdr;
1058  	len[0] = 1 + 1 + 2;
1059  	addr[1] = sent_msg->hdr->authenticator;
1060  	len[1] = MD5_MAC_LEN;
1061  	addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
1062  	len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
1063  	addr[3] = secret;
1064  	len[3] = secret_len;
1065  	if (md5_vector(4, addr, len, hash) < 0 ||
1066  	    os_memcmp_const(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
1067  		wpa_printf(MSG_INFO, "Response Authenticator invalid!");
1068  		return 1;
1069  	}
1070  
1071  	return 0;
1072  }
1073  
1074  
radius_msg_copy_attr(struct radius_msg * dst,struct radius_msg * src,u8 type)1075  int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
1076  			 u8 type)
1077  {
1078  	struct radius_attr_hdr *attr;
1079  	size_t i;
1080  	int count = 0;
1081  
1082  	for (i = 0; i < src->attr_used; i++) {
1083  		attr = radius_get_attr_hdr(src, i);
1084  		if (attr->type == type && attr->length >= sizeof(*attr)) {
1085  			if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1),
1086  						 attr->length - sizeof(*attr)))
1087  				return -1;
1088  			count++;
1089  		}
1090  	}
1091  
1092  	return count;
1093  }
1094  
1095  
1096  /* Create Request Authenticator. The value should be unique over the lifetime
1097   * of the shared secret between authenticator and authentication server.
1098   */
radius_msg_make_authenticator(struct radius_msg * msg)1099  int radius_msg_make_authenticator(struct radius_msg *msg)
1100  {
1101  	return os_get_random((u8 *) &msg->hdr->authenticator,
1102  			     sizeof(msg->hdr->authenticator));
1103  }
1104  
1105  
1106  /* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message.
1107   * Returns the Attribute payload and sets alen to indicate the length of the
1108   * payload if a vendor attribute with subtype is found, otherwise returns NULL.
1109   * The returned payload is allocated with os_malloc() and caller must free it
1110   * by calling os_free().
1111   */
radius_msg_get_vendor_attr(struct radius_msg * msg,u32 vendor,u8 subtype,size_t * alen)1112  static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
1113  				      u8 subtype, size_t *alen)
1114  {
1115  	u8 *data, *pos;
1116  	size_t i, len;
1117  
1118  	if (msg == NULL)
1119  		return NULL;
1120  
1121  	for (i = 0; i < msg->attr_used; i++) {
1122  		struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
1123  		size_t left;
1124  		u32 vendor_id;
1125  		struct radius_attr_vendor *vhdr;
1126  
1127  		if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC ||
1128  		    attr->length < sizeof(*attr))
1129  			continue;
1130  
1131  		left = attr->length - sizeof(*attr);
1132  		if (left < 4)
1133  			continue;
1134  
1135  		pos = (u8 *) (attr + 1);
1136  
1137  		os_memcpy(&vendor_id, pos, 4);
1138  		pos += 4;
1139  		left -= 4;
1140  
1141  		if (ntohl(vendor_id) != vendor)
1142  			continue;
1143  
1144  		while (left >= sizeof(*vhdr)) {
1145  			vhdr = (struct radius_attr_vendor *) pos;
1146  			if (vhdr->vendor_length > left ||
1147  			    vhdr->vendor_length < sizeof(*vhdr)) {
1148  				break;
1149  			}
1150  			if (vhdr->vendor_type != subtype) {
1151  				pos += vhdr->vendor_length;
1152  				left -= vhdr->vendor_length;
1153  				continue;
1154  			}
1155  
1156  			len = vhdr->vendor_length - sizeof(*vhdr);
1157  			data = os_memdup(pos + sizeof(*vhdr), len);
1158  			if (data == NULL)
1159  				return NULL;
1160  			if (alen)
1161  				*alen = len;
1162  			return data;
1163  		}
1164  	}
1165  
1166  	return NULL;
1167  }
1168  
1169  
decrypt_ms_key(const u8 * key,size_t len,const u8 * req_authenticator,const u8 * secret,size_t secret_len,size_t * reslen)1170  static u8 * decrypt_ms_key(const u8 *key, size_t len,
1171  			   const u8 *req_authenticator,
1172  			   const u8 *secret, size_t secret_len, size_t *reslen)
1173  {
1174  	u8 *plain, *ppos, *res;
1175  	const u8 *pos;
1176  	size_t left, plen;
1177  	u8 hash[MD5_MAC_LEN];
1178  	int i, first = 1;
1179  	const u8 *addr[3];
1180  	size_t elen[3];
1181  
1182  	/* key: 16-bit salt followed by encrypted key info */
1183  
1184  	if (len < 2 + 16) {
1185  		wpa_printf(MSG_DEBUG, "RADIUS: %s: Len is too small: %d",
1186  			   __func__, (int) len);
1187  		return NULL;
1188  	}
1189  
1190  	pos = key + 2;
1191  	left = len - 2;
1192  	if (left % 16) {
1193  		wpa_printf(MSG_INFO, "RADIUS: Invalid ms key len %lu",
1194  			   (unsigned long) left);
1195  		return NULL;
1196  	}
1197  
1198  	plen = left;
1199  	ppos = plain = os_malloc(plen);
1200  	if (plain == NULL)
1201  		return NULL;
1202  	plain[0] = 0;
1203  
1204  	while (left > 0) {
1205  		/* b(1) = MD5(Secret + Request-Authenticator + Salt)
1206  		 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
1207  
1208  		addr[0] = secret;
1209  		elen[0] = secret_len;
1210  		if (first) {
1211  			addr[1] = req_authenticator;
1212  			elen[1] = MD5_MAC_LEN;
1213  			addr[2] = key;
1214  			elen[2] = 2; /* Salt */
1215  		} else {
1216  			addr[1] = pos - MD5_MAC_LEN;
1217  			elen[1] = MD5_MAC_LEN;
1218  		}
1219  		if (md5_vector(first ? 3 : 2, addr, elen, hash) < 0) {
1220  			wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
1221  			os_free(plain);
1222  			return NULL;
1223  		}
1224  		first = 0;
1225  
1226  		for (i = 0; i < MD5_MAC_LEN; i++)
1227  			*ppos++ = *pos++ ^ hash[i];
1228  		left -= MD5_MAC_LEN;
1229  	}
1230  
1231  	if (plain[0] == 0 || plain[0] > plen - 1) {
1232  		wpa_printf(MSG_INFO, "RADIUS: Failed to decrypt MPPE key");
1233  		os_free(plain);
1234  		return NULL;
1235  	}
1236  
1237  	res = os_memdup(plain + 1, plain[0]);
1238  	if (res == NULL) {
1239  		os_free(plain);
1240  		return NULL;
1241  	}
1242  	if (reslen)
1243  		*reslen = plain[0];
1244  	os_free(plain);
1245  	return res;
1246  }
1247  
1248  
encrypt_ms_key(const u8 * key,size_t key_len,u16 salt,const u8 * req_authenticator,const u8 * secret,size_t secret_len,u8 * ebuf,size_t * elen)1249  static int encrypt_ms_key(const u8 *key, size_t key_len, u16 salt,
1250  			  const u8 *req_authenticator,
1251  			  const u8 *secret, size_t secret_len,
1252  			  u8 *ebuf, size_t *elen)
1253  {
1254  	int i, len, first = 1;
1255  	u8 hash[MD5_MAC_LEN], saltbuf[2], *pos;
1256  	const u8 *addr[3];
1257  	size_t _len[3];
1258  
1259  	WPA_PUT_BE16(saltbuf, salt);
1260  
1261  	len = 1 + key_len;
1262  	if (len & 0x0f) {
1263  		len = (len & 0xf0) + 16;
1264  	}
1265  	os_memset(ebuf, 0, len);
1266  	ebuf[0] = key_len;
1267  	os_memcpy(ebuf + 1, key, key_len);
1268  
1269  	*elen = len;
1270  
1271  	pos = ebuf;
1272  	while (len > 0) {
1273  		/* b(1) = MD5(Secret + Request-Authenticator + Salt)
1274  		 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
1275  		addr[0] = secret;
1276  		_len[0] = secret_len;
1277  		if (first) {
1278  			addr[1] = req_authenticator;
1279  			_len[1] = MD5_MAC_LEN;
1280  			addr[2] = saltbuf;
1281  			_len[2] = sizeof(saltbuf);
1282  		} else {
1283  			addr[1] = pos - MD5_MAC_LEN;
1284  			_len[1] = MD5_MAC_LEN;
1285  		}
1286  		if (md5_vector(first ? 3 : 2, addr, _len, hash) < 0) {
1287  			wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
1288  			return -1;
1289  		}
1290  		first = 0;
1291  
1292  		for (i = 0; i < MD5_MAC_LEN; i++)
1293  			*pos++ ^= hash[i];
1294  
1295  		len -= MD5_MAC_LEN;
1296  	}
1297  
1298  	return 0;
1299  }
1300  
1301  
1302  struct radius_ms_mppe_keys *
radius_msg_get_ms_keys(struct radius_msg * msg,struct radius_msg * sent_msg,const u8 * secret,size_t secret_len)1303  radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
1304  		       const u8 *secret, size_t secret_len)
1305  {
1306  	u8 *key;
1307  	size_t keylen;
1308  	struct radius_ms_mppe_keys *keys;
1309  
1310  	if (msg == NULL || sent_msg == NULL)
1311  		return NULL;
1312  
1313  	keys = os_zalloc(sizeof(*keys));
1314  	if (keys == NULL)
1315  		return NULL;
1316  
1317  	key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
1318  					 RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY,
1319  					 &keylen);
1320  	if (key) {
1321  		keys->send = decrypt_ms_key(key, keylen,
1322  					    sent_msg->hdr->authenticator,
1323  					    secret, secret_len,
1324  					    &keys->send_len);
1325  		if (!keys->send) {
1326  			wpa_printf(MSG_DEBUG,
1327  				   "RADIUS: Failed to decrypt send key");
1328  		}
1329  		os_free(key);
1330  	}
1331  
1332  	key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
1333  					 RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY,
1334  					 &keylen);
1335  	if (key) {
1336  		keys->recv = decrypt_ms_key(key, keylen,
1337  					    sent_msg->hdr->authenticator,
1338  					    secret, secret_len,
1339  					    &keys->recv_len);
1340  		if (!keys->recv) {
1341  			wpa_printf(MSG_DEBUG,
1342  				   "RADIUS: Failed to decrypt recv key");
1343  		}
1344  		os_free(key);
1345  	}
1346  
1347  	return keys;
1348  }
1349  
1350  
1351  struct radius_ms_mppe_keys *
radius_msg_get_cisco_keys(struct radius_msg * msg,struct radius_msg * sent_msg,const u8 * secret,size_t secret_len)1352  radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
1353  			  const u8 *secret, size_t secret_len)
1354  {
1355  	u8 *key;
1356  	size_t keylen;
1357  	struct radius_ms_mppe_keys *keys;
1358  
1359  	if (msg == NULL || sent_msg == NULL)
1360  		return NULL;
1361  
1362  	keys = os_zalloc(sizeof(*keys));
1363  	if (keys == NULL)
1364  		return NULL;
1365  
1366  	key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO,
1367  					 RADIUS_CISCO_AV_PAIR, &keylen);
1368  	if (key && keylen == 51 &&
1369  	    os_memcmp(key, "leap:session-key=", 17) == 0) {
1370  		keys->recv = decrypt_ms_key(key + 17, keylen - 17,
1371  					    sent_msg->hdr->authenticator,
1372  					    secret, secret_len,
1373  					    &keys->recv_len);
1374  	}
1375  	os_free(key);
1376  
1377  	return keys;
1378  }
1379  
1380  
radius_msg_add_mppe_keys(struct radius_msg * msg,const u8 * req_authenticator,const u8 * secret,size_t secret_len,const u8 * send_key,size_t send_key_len,const u8 * recv_key,size_t recv_key_len)1381  int radius_msg_add_mppe_keys(struct radius_msg *msg,
1382  			     const u8 *req_authenticator,
1383  			     const u8 *secret, size_t secret_len,
1384  			     const u8 *send_key, size_t send_key_len,
1385  			     const u8 *recv_key, size_t recv_key_len)
1386  {
1387  	struct radius_attr_hdr *attr;
1388  	u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT);
1389  	u8 *buf;
1390  	struct radius_attr_vendor *vhdr;
1391  	u8 *pos;
1392  	size_t elen;
1393  	int hlen;
1394  	u16 salt;
1395  
1396  	hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2;
1397  
1398  	/* MS-MPPE-Send-Key */
1399  	buf = os_malloc(hlen + send_key_len + 16);
1400  	if (buf == NULL) {
1401  		return 0;
1402  	}
1403  	pos = buf;
1404  	os_memcpy(pos, &vendor_id, sizeof(vendor_id));
1405  	pos += sizeof(vendor_id);
1406  	vhdr = (struct radius_attr_vendor *) pos;
1407  	vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY;
1408  	pos = (u8 *) (vhdr + 1);
1409  	if (os_get_random((u8 *) &salt, sizeof(salt)) < 0) {
1410  		os_free(buf);
1411  		return 0;
1412  	}
1413  	salt |= 0x8000;
1414  	WPA_PUT_BE16(pos, salt);
1415  	pos += 2;
1416  	if (encrypt_ms_key(send_key, send_key_len, salt, req_authenticator,
1417  			   secret, secret_len, pos, &elen) < 0)
1418  		return 0;
1419  	vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
1420  
1421  	attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
1422  				   buf, hlen + elen);
1423  	os_free(buf);
1424  	if (attr == NULL) {
1425  		return 0;
1426  	}
1427  
1428  	/* MS-MPPE-Recv-Key */
1429  	buf = os_malloc(hlen + recv_key_len + 16);
1430  	if (buf == NULL) {
1431  		return 0;
1432  	}
1433  	pos = buf;
1434  	os_memcpy(pos, &vendor_id, sizeof(vendor_id));
1435  	pos += sizeof(vendor_id);
1436  	vhdr = (struct radius_attr_vendor *) pos;
1437  	vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY;
1438  	pos = (u8 *) (vhdr + 1);
1439  	salt ^= 1;
1440  	WPA_PUT_BE16(pos, salt);
1441  	pos += 2;
1442  	if (encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator,
1443  			   secret, secret_len, pos, &elen) < 0)
1444  		return 0;
1445  	vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
1446  
1447  	attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
1448  				   buf, hlen + elen);
1449  	os_free(buf);
1450  	if (attr == NULL) {
1451  		return 0;
1452  	}
1453  
1454  	return 1;
1455  }
1456  
1457  
radius_msg_add_wfa(struct radius_msg * msg,u8 subtype,const u8 * data,size_t len)1458  int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data,
1459  		       size_t len)
1460  {
1461  	struct radius_attr_hdr *attr;
1462  	u8 *buf, *pos;
1463  	size_t alen;
1464  
1465  	alen = 4 + 2 + len;
1466  	buf = os_malloc(alen);
1467  	if (buf == NULL)
1468  		return 0;
1469  	pos = buf;
1470  	WPA_PUT_BE32(pos, RADIUS_VENDOR_ID_WFA);
1471  	pos += 4;
1472  	*pos++ = subtype;
1473  	*pos++ = 2 + len;
1474  	os_memcpy(pos, data, len);
1475  	attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
1476  				   buf, alen);
1477  	os_free(buf);
1478  	if (attr == NULL)
1479  		return 0;
1480  
1481  	return 1;
1482  }
1483  
1484  
radius_msg_add_ext_vs(struct radius_msg * msg,u16 type,u32 vendor_id,u8 vendor_type,const u8 * data,size_t len)1485  int radius_msg_add_ext_vs(struct radius_msg *msg, u16 type, u32 vendor_id,
1486  			  u8 vendor_type, const u8 *data, size_t len)
1487  {
1488  	struct radius_attr_hdr *attr;
1489  	u8 *buf, *pos;
1490  	size_t alen;
1491  
1492  	alen = 4 + 1 + len;
1493  	buf = os_malloc(alen);
1494  	if (!buf)
1495  		return 0;
1496  	pos = buf;
1497  	WPA_PUT_BE32(pos, vendor_id);
1498  	pos += 4;
1499  	*pos++ = vendor_type;
1500  	os_memcpy(pos, data, len);
1501  	attr = radius_msg_add_attr(msg, type, buf, alen);
1502  	os_free(buf);
1503  	return attr != NULL;
1504  }
1505  
1506  
radius_user_password_hide(struct radius_msg * msg,const u8 * data,size_t data_len,const u8 * secret,size_t secret_len,u8 * buf,size_t buf_len)1507  int radius_user_password_hide(struct radius_msg *msg,
1508  			      const u8 *data, size_t data_len,
1509  			      const u8 *secret, size_t secret_len,
1510  			      u8 *buf, size_t buf_len)
1511  {
1512  	size_t padlen, i, pos;
1513  	const u8 *addr[2];
1514  	size_t len[2];
1515  	u8 hash[16];
1516  
1517  	if (data_len + 16 > buf_len)
1518  		return -1;
1519  
1520  	os_memcpy(buf, data, data_len);
1521  
1522  	padlen = data_len % 16;
1523  	if (padlen && data_len < buf_len) {
1524  		padlen = 16 - padlen;
1525  		os_memset(buf + data_len, 0, padlen);
1526  		buf_len = data_len + padlen;
1527  	} else {
1528  		buf_len = data_len;
1529  	}
1530  
1531  	addr[0] = secret;
1532  	len[0] = secret_len;
1533  	addr[1] = msg->hdr->authenticator;
1534  	len[1] = 16;
1535  	if (md5_vector(2, addr, len, hash) < 0) {
1536  		wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
1537  		return -1;
1538  	}
1539  
1540  	for (i = 0; i < 16; i++)
1541  		buf[i] ^= hash[i];
1542  	pos = 16;
1543  
1544  	while (pos < buf_len) {
1545  		addr[0] = secret;
1546  		len[0] = secret_len;
1547  		addr[1] = &buf[pos - 16];
1548  		len[1] = 16;
1549  		if (md5_vector(2, addr, len, hash) < 0) {
1550  			wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
1551  			return -1;
1552  		}
1553  
1554  		for (i = 0; i < 16; i++)
1555  			buf[pos + i] ^= hash[i];
1556  
1557  		pos += 16;
1558  	}
1559  
1560  	return buf_len;
1561  }
1562  
1563  
1564  /* Add User-Password attribute to a RADIUS message and encrypt it as specified
1565   * in RFC 2865, Chap. 5.2 */
1566  struct radius_attr_hdr *
radius_msg_add_attr_user_password(struct radius_msg * msg,const u8 * data,size_t data_len,const u8 * secret,size_t secret_len)1567  radius_msg_add_attr_user_password(struct radius_msg *msg,
1568  				  const u8 *data, size_t data_len,
1569  				  const u8 *secret, size_t secret_len)
1570  {
1571  	u8 buf[128];
1572  	int res;
1573  
1574  	res = radius_user_password_hide(msg, data, data_len,
1575  					secret, secret_len, buf, sizeof(buf));
1576  	if (res < 0)
1577  		return NULL;
1578  
1579  	return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD,
1580  				   buf, res);
1581  }
1582  
1583  
radius_msg_get_attr(struct radius_msg * msg,u8 type,u8 * buf,size_t len)1584  int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
1585  {
1586  	struct radius_attr_hdr *attr = NULL, *tmp;
1587  	size_t i, dlen;
1588  
1589  	for (i = 0; i < msg->attr_used; i++) {
1590  		tmp = radius_get_attr_hdr(msg, i);
1591  		if (tmp->type == type) {
1592  			attr = tmp;
1593  			break;
1594  		}
1595  	}
1596  
1597  	if (!attr || attr->length < sizeof(*attr))
1598  		return -1;
1599  
1600  	dlen = attr->length - sizeof(*attr);
1601  	if (buf)
1602  		os_memcpy(buf, (attr + 1), dlen > len ? len : dlen);
1603  	return dlen;
1604  }
1605  
1606  
radius_msg_get_attr_ptr(struct radius_msg * msg,u8 type,u8 ** buf,size_t * len,const u8 * start)1607  int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
1608  			    size_t *len, const u8 *start)
1609  {
1610  	size_t i;
1611  	struct radius_attr_hdr *attr = NULL, *tmp;
1612  
1613  	for (i = 0; i < msg->attr_used; i++) {
1614  		tmp = radius_get_attr_hdr(msg, i);
1615  		if (tmp->type == type &&
1616  		    (start == NULL || (u8 *) tmp > start)) {
1617  			attr = tmp;
1618  			break;
1619  		}
1620  	}
1621  
1622  	if (!attr || attr->length < sizeof(*attr))
1623  		return -1;
1624  
1625  	*buf = (u8 *) (attr + 1);
1626  	*len = attr->length - sizeof(*attr);
1627  	return 0;
1628  }
1629  
1630  
radius_msg_count_attr(struct radius_msg * msg,u8 type,int min_len)1631  int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len)
1632  {
1633  	size_t i;
1634  	int count;
1635  
1636  	for (count = 0, i = 0; i < msg->attr_used; i++) {
1637  		struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
1638  		if (attr->type == type &&
1639  		    attr->length >= sizeof(struct radius_attr_hdr) + min_len)
1640  			count++;
1641  	}
1642  
1643  	return count;
1644  }
1645  
1646  
1647  struct radius_tunnel_attrs {
1648  	int tag_used;
1649  	int type; /* Tunnel-Type */
1650  	int medium_type; /* Tunnel-Medium-Type */
1651  	int vlanid;
1652  };
1653  
1654  
cmp_int(const void * a,const void * b)1655  static int cmp_int(const void *a, const void *b)
1656  {
1657  	int x, y;
1658  
1659  	x = *((int *) a);
1660  	y = *((int *) b);
1661  	return (x - y);
1662  }
1663  
1664  
1665  /**
1666   * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
1667   * The k tagged vlans found are sorted by vlan_id and stored in the first k
1668   * items of tagged.
1669   *
1670   * @msg: RADIUS message
1671   * @untagged: Pointer to store untagged vid
1672   * @numtagged: Size of tagged
1673   * @tagged: Pointer to store tagged list
1674   *
1675   * Returns: 0 if neither tagged nor untagged configuration is found, 1 otherwise
1676   */
radius_msg_get_vlanid(struct radius_msg * msg,int * untagged,int numtagged,int * tagged)1677  int radius_msg_get_vlanid(struct radius_msg *msg, int *untagged, int numtagged,
1678  			  int *tagged)
1679  {
1680  	struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun;
1681  	size_t i;
1682  	struct radius_attr_hdr *attr = NULL;
1683  	const u8 *data;
1684  	char buf[10];
1685  	size_t dlen;
1686  	int j, taggedidx = 0, vlan_id;
1687  
1688  	os_memset(&tunnel, 0, sizeof(tunnel));
1689  	for (j = 0; j < numtagged; j++)
1690  		tagged[j] = 0;
1691  	*untagged = 0;
1692  
1693  	for (i = 0; i < msg->attr_used; i++) {
1694  		attr = radius_get_attr_hdr(msg, i);
1695  		if (attr->length < sizeof(*attr))
1696  			return -1;
1697  		data = (const u8 *) (attr + 1);
1698  		dlen = attr->length - sizeof(*attr);
1699  		if (attr->length < 3)
1700  			continue;
1701  		if (data[0] >= RADIUS_TUNNEL_TAGS)
1702  			tun = &tunnel[0];
1703  		else
1704  			tun = &tunnel[data[0]];
1705  
1706  		switch (attr->type) {
1707  		case RADIUS_ATTR_TUNNEL_TYPE:
1708  			if (attr->length != 6)
1709  				break;
1710  			tun->tag_used++;
1711  			tun->type = WPA_GET_BE24(data + 1);
1712  			break;
1713  		case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE:
1714  			if (attr->length != 6)
1715  				break;
1716  			tun->tag_used++;
1717  			tun->medium_type = WPA_GET_BE24(data + 1);
1718  			break;
1719  		case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID:
1720  			if (data[0] < RADIUS_TUNNEL_TAGS) {
1721  				data++;
1722  				dlen--;
1723  			}
1724  			if (dlen >= sizeof(buf))
1725  				break;
1726  			os_memcpy(buf, data, dlen);
1727  			buf[dlen] = '\0';
1728  			vlan_id = atoi(buf);
1729  			if (vlan_id <= 0)
1730  				break;
1731  			tun->tag_used++;
1732  			tun->vlanid = vlan_id;
1733  			break;
1734  		case RADIUS_ATTR_EGRESS_VLANID: /* RFC 4675 */
1735  			if (attr->length != 6)
1736  				break;
1737  			vlan_id = WPA_GET_BE24(data + 1);
1738  			if (vlan_id <= 0)
1739  				break;
1740  			if (data[0] == 0x32)
1741  				*untagged = vlan_id;
1742  			else if (data[0] == 0x31 && tagged &&
1743  				 taggedidx < numtagged)
1744  				tagged[taggedidx++] = vlan_id;
1745  			break;
1746  		}
1747  	}
1748  
1749  	/* Use tunnel with the lowest tag for untagged VLAN id */
1750  	for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) {
1751  		tun = &tunnel[i];
1752  		if (tun->tag_used &&
1753  		    tun->type == RADIUS_TUNNEL_TYPE_VLAN &&
1754  		    tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 &&
1755  		    tun->vlanid > 0) {
1756  			*untagged = tun->vlanid;
1757  			break;
1758  		}
1759  	}
1760  
1761  	if (taggedidx)
1762  		qsort(tagged, taggedidx, sizeof(int), cmp_int);
1763  
1764  	if (*untagged > 0 || taggedidx)
1765  		return 1;
1766  	return 0;
1767  }
1768  
1769  
1770  /**
1771   * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password
1772   * @msg: Received RADIUS message
1773   * @keylen: Length of returned password
1774   * @secret: RADIUS shared secret
1775   * @secret_len: Length of secret
1776   * @sent_msg: Sent RADIUS message
1777   * @n: Number of password attribute to return (starting with 0)
1778   * Returns: Pointer to n-th password (free with os_free) or %NULL
1779   */
radius_msg_get_tunnel_password(struct radius_msg * msg,int * keylen,const u8 * secret,size_t secret_len,struct radius_msg * sent_msg,size_t n)1780  char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
1781  				      const u8 *secret, size_t secret_len,
1782  				      struct radius_msg *sent_msg, size_t n)
1783  {
1784  	u8 *buf = NULL;
1785  	size_t buflen;
1786  	const u8 *salt;
1787  	u8 *str;
1788  	const u8 *addr[3];
1789  	size_t len[3];
1790  	u8 hash[16];
1791  	u8 *pos;
1792  	size_t i, j = 0;
1793  	struct radius_attr_hdr *attr;
1794  	const u8 *data;
1795  	size_t dlen;
1796  	const u8 *fdata = NULL; /* points to found item */
1797  	size_t fdlen = -1;
1798  	char *ret = NULL;
1799  
1800  	/* find n-th valid Tunnel-Password attribute */
1801  	for (i = 0; i < msg->attr_used; i++) {
1802  		attr = radius_get_attr_hdr(msg, i);
1803  		if (attr == NULL ||
1804  		    attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) {
1805  			continue;
1806  		}
1807  		if (attr->length <= 5)
1808  			continue;
1809  		data = (const u8 *) (attr + 1);
1810  		dlen = attr->length - sizeof(*attr);
1811  		if (dlen <= 3 || dlen % 16 != 3)
1812  			continue;
1813  		j++;
1814  		if (j <= n)
1815  			continue;
1816  
1817  		fdata = data;
1818  		fdlen = dlen;
1819  		break;
1820  	}
1821  	if (fdata == NULL)
1822  		goto out;
1823  
1824  	/* alloc writable memory for decryption */
1825  	buf = os_memdup(fdata, fdlen);
1826  	if (buf == NULL)
1827  		goto out;
1828  	buflen = fdlen;
1829  
1830  	/* init pointers */
1831  	salt = buf + 1;
1832  	str = buf + 3;
1833  
1834  	/* decrypt blocks */
1835  	pos = buf + buflen - 16; /* last block */
1836  	while (pos >= str + 16) { /* all but the first block */
1837  		addr[0] = secret;
1838  		len[0] = secret_len;
1839  		addr[1] = pos - 16;
1840  		len[1] = 16;
1841  		if (md5_vector(2, addr, len, hash) < 0) {
1842  			wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
1843  			goto out;
1844  		}
1845  
1846  		for (i = 0; i < 16; i++)
1847  			pos[i] ^= hash[i];
1848  
1849  		pos -= 16;
1850  	}
1851  
1852  	/* decrypt first block */
1853  	if (str != pos)
1854  		goto out;
1855  	addr[0] = secret;
1856  	len[0] = secret_len;
1857  	addr[1] = sent_msg->hdr->authenticator;
1858  	len[1] = 16;
1859  	addr[2] = salt;
1860  	len[2] = 2;
1861  	if (md5_vector(3, addr, len, hash) < 0) {
1862  		wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
1863  		goto out;
1864  	}
1865  
1866  	for (i = 0; i < 16; i++)
1867  		pos[i] ^= hash[i];
1868  
1869  	/* derive plaintext length from first subfield */
1870  	*keylen = (unsigned char) str[0];
1871  	if ((u8 *) (str + *keylen) >= (u8 *) (buf + buflen)) {
1872  		/* decryption error - invalid key length */
1873  		goto out;
1874  	}
1875  	if (*keylen == 0) {
1876  		/* empty password */
1877  		goto out;
1878  	}
1879  
1880  	/* copy passphrase into new buffer */
1881  	ret = os_malloc(*keylen);
1882  	if (ret)
1883  		os_memcpy(ret, str + 1, *keylen);
1884  
1885  out:
1886  	/* return new buffer */
1887  	os_free(buf);
1888  	return ret;
1889  }
1890  
1891  
radius_free_class(struct radius_class_data * c)1892  void radius_free_class(struct radius_class_data *c)
1893  {
1894  	size_t i;
1895  	if (c == NULL)
1896  		return;
1897  	for (i = 0; i < c->count; i++)
1898  		os_free(c->attr[i].data);
1899  	os_free(c->attr);
1900  	c->attr = NULL;
1901  	c->count = 0;
1902  }
1903  
1904  
radius_copy_class(struct radius_class_data * dst,const struct radius_class_data * src)1905  int radius_copy_class(struct radius_class_data *dst,
1906  		      const struct radius_class_data *src)
1907  {
1908  	size_t i;
1909  
1910  	if (src->attr == NULL)
1911  		return 0;
1912  
1913  	dst->attr = os_calloc(src->count, sizeof(struct radius_attr_data));
1914  	if (dst->attr == NULL)
1915  		return -1;
1916  
1917  	dst->count = 0;
1918  
1919  	for (i = 0; i < src->count; i++) {
1920  		dst->attr[i].data = os_memdup(src->attr[i].data,
1921  					      src->attr[i].len);
1922  		if (dst->attr[i].data == NULL)
1923  			break;
1924  		dst->count++;
1925  		dst->attr[i].len = src->attr[i].len;
1926  	}
1927  
1928  	return 0;
1929  }
1930  
1931  
radius_msg_find_unlisted_attr(struct radius_msg * msg,u8 * attrs)1932  u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs)
1933  {
1934  	size_t i, j;
1935  	struct radius_attr_hdr *attr;
1936  
1937  	for (i = 0; i < msg->attr_used; i++) {
1938  		attr = radius_get_attr_hdr(msg, i);
1939  
1940  		for (j = 0; attrs[j]; j++) {
1941  			if (attr->type == attrs[j])
1942  				break;
1943  		}
1944  
1945  		if (attrs[j] == 0)
1946  			return attr->type; /* unlisted attr */
1947  	}
1948  
1949  	return 0;
1950  }
1951  
1952  
radius_gen_session_id(u8 * id,size_t len)1953  int radius_gen_session_id(u8 *id, size_t len)
1954  {
1955  	/*
1956  	 * Acct-Session-Id and Acct-Multi-Session-Id should be globally and
1957  	 * temporarily unique. A high quality random number is required
1958  	 * therefore. This could be be improved by switching to a GUID.
1959  	 */
1960  	return os_get_random(id, len);
1961  }
1962