Line data Source code
1 : /*
2 : * RADIUS message processing
3 : * Copyright (c) 2002-2009, 2011-2014, 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 :
52 15677 : struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg)
53 : {
54 15677 : return msg->hdr;
55 : }
56 :
57 :
58 3279 : struct wpabuf * radius_msg_get_buf(struct radius_msg *msg)
59 : {
60 3279 : return msg->buf;
61 : }
62 :
63 :
64 : static struct radius_attr_hdr *
65 190650 : radius_get_attr_hdr(struct radius_msg *msg, int idx)
66 : {
67 190650 : return (struct radius_attr_hdr *)
68 190650 : (wpabuf_mhead_u8(msg->buf) + msg->attr_pos[idx]);
69 : }
70 :
71 :
72 3276 : static void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
73 : {
74 3276 : msg->hdr->code = code;
75 3276 : msg->hdr->identifier = identifier;
76 3276 : }
77 :
78 :
79 6545 : static int radius_msg_initialize(struct radius_msg *msg)
80 : {
81 6545 : msg->attr_pos = os_calloc(RADIUS_DEFAULT_ATTR_COUNT,
82 : sizeof(*msg->attr_pos));
83 6545 : if (msg->attr_pos == NULL)
84 0 : return -1;
85 :
86 6545 : msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT;
87 6545 : msg->attr_used = 0;
88 :
89 6545 : 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 : */
102 3276 : struct radius_msg * radius_msg_new(u8 code, u8 identifier)
103 : {
104 : struct radius_msg *msg;
105 :
106 3276 : msg = os_zalloc(sizeof(*msg));
107 3276 : if (msg == NULL)
108 0 : return NULL;
109 :
110 3276 : msg->buf = wpabuf_alloc(RADIUS_DEFAULT_MSG_SIZE);
111 3276 : if (msg->buf == NULL || radius_msg_initialize(msg)) {
112 0 : radius_msg_free(msg);
113 0 : return NULL;
114 : }
115 3276 : msg->hdr = wpabuf_put(msg->buf, sizeof(struct radius_hdr));
116 :
117 3276 : radius_msg_set_hdr(msg, code, identifier);
118 :
119 3276 : 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 : */
127 7579 : void radius_msg_free(struct radius_msg *msg)
128 : {
129 7579 : if (msg == NULL)
130 8613 : return;
131 :
132 6545 : wpabuf_free(msg->buf);
133 6545 : os_free(msg->attr_pos);
134 6545 : os_free(msg);
135 : }
136 :
137 :
138 6545 : static const char *radius_code_string(u8 code)
139 : {
140 6545 : switch (code) {
141 3209 : case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request";
142 508 : case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept";
143 96 : case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject";
144 55 : case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request";
145 46 : case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response";
146 2602 : case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge";
147 0 : case RADIUS_CODE_STATUS_SERVER: return "Status-Server";
148 0 : case RADIUS_CODE_STATUS_CLIENT: return "Status-Client";
149 0 : case RADIUS_CODE_RESERVED: return "Reserved";
150 15 : case RADIUS_CODE_DISCONNECT_REQUEST: return "Disconnect-Request";
151 5 : case RADIUS_CODE_DISCONNECT_ACK: return "Disconnect-ACK";
152 7 : case RADIUS_CODE_DISCONNECT_NAK: return "Disconnect-NAK";
153 1 : case RADIUS_CODE_COA_REQUEST: return "CoA-Request";
154 0 : case RADIUS_CODE_COA_ACK: return "CoA-ACK";
155 1 : case RADIUS_CODE_COA_NAK: return "CoA-NAK";
156 0 : default: return "?Unknown?";
157 : }
158 : }
159 :
160 :
161 : struct radius_attr_type {
162 : u8 type;
163 : char *name;
164 : enum {
165 : RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
166 : RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6
167 : } data_type;
168 : };
169 :
170 : static struct radius_attr_type radius_attrs[] =
171 : {
172 : { RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT },
173 : { RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST },
174 : { RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP },
175 : { RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 },
176 : { RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 },
177 : { RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT },
178 : { RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST },
179 : { RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST },
180 : { RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST },
181 : { RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 },
182 : { RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 },
183 : { RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action",
184 : RADIUS_ATTR_INT32 },
185 : { RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id",
186 : RADIUS_ATTR_TEXT },
187 : { RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id",
188 : RADIUS_ATTR_TEXT },
189 : { RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT },
190 : { RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST },
191 : { RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type",
192 : RADIUS_ATTR_INT32 },
193 : { RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 },
194 : { RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets",
195 : RADIUS_ATTR_INT32 },
196 : { RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets",
197 : RADIUS_ATTR_INT32 },
198 : { RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT },
199 : { RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 },
200 : { RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time",
201 : RADIUS_ATTR_INT32 },
202 : { RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets",
203 : RADIUS_ATTR_INT32 },
204 : { RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets",
205 : RADIUS_ATTR_INT32 },
206 : { RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause",
207 : RADIUS_ATTR_INT32 },
208 : { RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id",
209 : RADIUS_ATTR_TEXT },
210 : { RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 },
211 : { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords",
212 : RADIUS_ATTR_INT32 },
213 : { RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords",
214 : RADIUS_ATTR_INT32 },
215 : { RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",
216 : RADIUS_ATTR_INT32 },
217 : { RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 },
218 : { RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
219 : { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
220 : RADIUS_ATTR_HEXDUMP },
221 : { RADIUS_ATTR_TUNNEL_PASSWORD, "Tunnel-Password",
222 : RADIUS_ATTR_UNDIST },
223 : { RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
224 : { RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
225 : { RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
226 : RADIUS_ATTR_UNDIST },
227 : { RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id",
228 : RADIUS_ATTR_HEXDUMP },
229 : { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
230 : RADIUS_ATTR_INT32 },
231 : { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity",
232 : RADIUS_ATTR_TEXT },
233 : { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
234 : { RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 },
235 : { RADIUS_ATTR_EAP_KEY_NAME, "EAP-Key-Name", RADIUS_ATTR_HEXDUMP },
236 : };
237 : #define RADIUS_ATTRS ARRAY_SIZE(radius_attrs)
238 :
239 :
240 51846 : static struct radius_attr_type *radius_get_attr_type(u8 type)
241 : {
242 : size_t i;
243 :
244 1077645 : for (i = 0; i < RADIUS_ATTRS; i++) {
245 1077611 : if (type == radius_attrs[i].type)
246 51812 : return &radius_attrs[i];
247 : }
248 :
249 34 : return NULL;
250 : }
251 :
252 :
253 51846 : static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
254 : {
255 : struct radius_attr_type *attr;
256 : int len;
257 : unsigned char *pos;
258 : char buf[1000];
259 :
260 51846 : attr = radius_get_attr_type(hdr->type);
261 :
262 103692 : wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d",
263 103692 : hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
264 :
265 51846 : if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr))
266 51880 : return;
267 :
268 51812 : len = hdr->length - sizeof(struct radius_attr_hdr);
269 51812 : pos = (unsigned char *) (hdr + 1);
270 :
271 51812 : switch (attr->data_type) {
272 : case RADIUS_ATTR_TEXT:
273 18607 : printf_encode(buf, sizeof(buf), pos, len);
274 18607 : wpa_printf(MSG_INFO, " Value: '%s'", buf);
275 18607 : break;
276 :
277 : case RADIUS_ATTR_IP:
278 45 : if (len == 4) {
279 : struct in_addr addr;
280 45 : os_memcpy(&addr, pos, 4);
281 45 : wpa_printf(MSG_INFO, " Value: %s",
282 : inet_ntoa(addr));
283 : } else {
284 0 : wpa_printf(MSG_INFO, " Invalid IP address length %d",
285 : len);
286 : }
287 45 : break;
288 :
289 : #ifdef CONFIG_IPV6
290 : case RADIUS_ATTR_IPV6:
291 14 : if (len == 16) {
292 : const char *atxt;
293 14 : struct in6_addr *addr = (struct in6_addr *) pos;
294 14 : atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf));
295 14 : wpa_printf(MSG_INFO, " Value: %s",
296 : atxt ? atxt : "?");
297 : } else {
298 0 : wpa_printf(MSG_INFO, " Invalid IPv6 address length %d",
299 : len);
300 : }
301 14 : break;
302 : #endif /* CONFIG_IPV6 */
303 :
304 : case RADIUS_ATTR_HEXDUMP:
305 : case RADIUS_ATTR_UNDIST:
306 23124 : wpa_snprintf_hex(buf, sizeof(buf), pos, len);
307 23124 : wpa_printf(MSG_INFO, " Value: %s", buf);
308 23124 : break;
309 :
310 : case RADIUS_ATTR_INT32:
311 10022 : if (len == 4)
312 10022 : wpa_printf(MSG_INFO, " Value: %u",
313 : WPA_GET_BE32(pos));
314 : else
315 0 : wpa_printf(MSG_INFO, " Invalid INT32 length %d",
316 : len);
317 10022 : break;
318 :
319 : default:
320 0 : break;
321 : }
322 : }
323 :
324 :
325 6545 : void radius_msg_dump(struct radius_msg *msg)
326 : {
327 : size_t i;
328 :
329 26180 : wpa_printf(MSG_INFO, "RADIUS message: code=%d (%s) identifier=%d length=%d",
330 13090 : msg->hdr->code, radius_code_string(msg->hdr->code),
331 13090 : msg->hdr->identifier, be_to_host16(msg->hdr->length));
332 :
333 58391 : for (i = 0; i < msg->attr_used; i++) {
334 51846 : struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
335 51846 : radius_msg_dump_attr(attr);
336 : }
337 6545 : }
338 :
339 :
340 1605 : int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
341 : size_t secret_len)
342 : {
343 1605 : if (secret) {
344 : u8 auth[MD5_MAC_LEN];
345 : struct radius_attr_hdr *attr;
346 :
347 1605 : os_memset(auth, 0, MD5_MAC_LEN);
348 1605 : attr = radius_msg_add_attr(msg,
349 : RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
350 : auth, MD5_MAC_LEN);
351 1605 : if (attr == NULL) {
352 0 : wpa_printf(MSG_WARNING, "RADIUS: Could not add "
353 : "Message-Authenticator");
354 0 : return -1;
355 : }
356 1605 : msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
357 3210 : hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
358 1605 : wpabuf_len(msg->buf), (u8 *) (attr + 1));
359 : } else
360 0 : msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
361 :
362 1605 : if (wpabuf_len(msg->buf) > 0xffff) {
363 0 : wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
364 0 : (unsigned long) wpabuf_len(msg->buf));
365 0 : return -1;
366 : }
367 1605 : return 0;
368 : }
369 :
370 :
371 1603 : int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
372 : size_t secret_len, const u8 *req_authenticator)
373 : {
374 : u8 auth[MD5_MAC_LEN];
375 : struct radius_attr_hdr *attr;
376 : const u8 *addr[4];
377 : size_t len[4];
378 :
379 1603 : os_memset(auth, 0, MD5_MAC_LEN);
380 1603 : attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
381 : auth, MD5_MAC_LEN);
382 1603 : if (attr == NULL) {
383 0 : wpa_printf(MSG_ERROR, "WARNING: Could not add Message-Authenticator");
384 0 : return -1;
385 : }
386 1603 : msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
387 1603 : os_memcpy(msg->hdr->authenticator, req_authenticator,
388 : sizeof(msg->hdr->authenticator));
389 3206 : hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
390 1603 : wpabuf_len(msg->buf), (u8 *) (attr + 1));
391 :
392 : /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
393 1603 : addr[0] = (u8 *) msg->hdr;
394 1603 : len[0] = 1 + 1 + 2;
395 1603 : addr[1] = req_authenticator;
396 1603 : len[1] = MD5_MAC_LEN;
397 1603 : addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
398 1603 : len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
399 1603 : addr[3] = secret;
400 1603 : len[3] = secret_len;
401 1603 : md5_vector(4, addr, len, msg->hdr->authenticator);
402 :
403 1603 : if (wpabuf_len(msg->buf) > 0xffff) {
404 0 : wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
405 0 : (unsigned long) wpabuf_len(msg->buf));
406 0 : return -1;
407 : }
408 1603 : return 0;
409 : }
410 :
411 :
412 13 : int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret,
413 : size_t secret_len,
414 : const struct radius_hdr *req_hdr)
415 : {
416 : const u8 *addr[2];
417 : size_t len[2];
418 : u8 auth[MD5_MAC_LEN];
419 : struct radius_attr_hdr *attr;
420 :
421 13 : os_memset(auth, 0, MD5_MAC_LEN);
422 13 : attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
423 : auth, MD5_MAC_LEN);
424 13 : if (attr == NULL) {
425 0 : wpa_printf(MSG_WARNING, "Could not add Message-Authenticator");
426 0 : return -1;
427 : }
428 :
429 13 : msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
430 13 : os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16);
431 26 : hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
432 13 : wpabuf_len(msg->buf), (u8 *) (attr + 1));
433 :
434 : /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
435 13 : addr[0] = wpabuf_head_u8(msg->buf);
436 13 : len[0] = wpabuf_len(msg->buf);
437 13 : addr[1] = secret;
438 13 : len[1] = secret_len;
439 13 : if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0)
440 0 : return -1;
441 :
442 13 : if (wpabuf_len(msg->buf) > 0xffff) {
443 0 : wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
444 0 : (unsigned long) wpabuf_len(msg->buf));
445 0 : return -1;
446 : }
447 13 : return 0;
448 : }
449 :
450 :
451 30 : void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
452 : size_t secret_len)
453 : {
454 : const u8 *addr[2];
455 : size_t len[2];
456 :
457 30 : msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
458 30 : os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
459 30 : addr[0] = wpabuf_head(msg->buf);
460 30 : len[0] = wpabuf_len(msg->buf);
461 30 : addr[1] = secret;
462 30 : len[1] = secret_len;
463 30 : md5_vector(2, addr, len, msg->hdr->authenticator);
464 :
465 30 : if (wpabuf_len(msg->buf) > 0xffff) {
466 0 : wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
467 0 : (unsigned long) wpabuf_len(msg->buf));
468 : }
469 30 : }
470 :
471 :
472 25 : void radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
473 : size_t secret_len, const u8 *req_authenticator)
474 : {
475 : const u8 *addr[2];
476 : size_t len[2];
477 :
478 25 : msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
479 25 : os_memcpy(msg->hdr->authenticator, req_authenticator, MD5_MAC_LEN);
480 25 : addr[0] = wpabuf_head(msg->buf);
481 25 : len[0] = wpabuf_len(msg->buf);
482 25 : addr[1] = secret;
483 25 : len[1] = secret_len;
484 25 : md5_vector(2, addr, len, msg->hdr->authenticator);
485 :
486 25 : if (wpabuf_len(msg->buf) > 0xffff) {
487 0 : wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
488 0 : (unsigned long) wpabuf_len(msg->buf));
489 : }
490 25 : }
491 :
492 :
493 25 : int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
494 : size_t secret_len)
495 : {
496 : const u8 *addr[4];
497 : size_t len[4];
498 : u8 zero[MD5_MAC_LEN];
499 : u8 hash[MD5_MAC_LEN];
500 :
501 25 : os_memset(zero, 0, sizeof(zero));
502 25 : addr[0] = (u8 *) msg->hdr;
503 25 : len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN;
504 25 : addr[1] = zero;
505 25 : len[1] = MD5_MAC_LEN;
506 25 : addr[2] = (u8 *) (msg->hdr + 1);
507 25 : len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
508 25 : addr[3] = secret;
509 25 : len[3] = secret_len;
510 25 : md5_vector(4, addr, len, hash);
511 25 : return os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0;
512 : }
513 :
514 :
515 16 : int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
516 : size_t secret_len)
517 : {
518 : const u8 *addr[4];
519 : size_t len[4];
520 : u8 zero[MD5_MAC_LEN];
521 : u8 hash[MD5_MAC_LEN];
522 : u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
523 : u8 orig_authenticator[16];
524 :
525 16 : struct radius_attr_hdr *attr = NULL, *tmp;
526 : size_t i;
527 :
528 16 : os_memset(zero, 0, sizeof(zero));
529 16 : addr[0] = (u8 *) msg->hdr;
530 16 : len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN;
531 16 : addr[1] = zero;
532 16 : len[1] = MD5_MAC_LEN;
533 16 : addr[2] = (u8 *) (msg->hdr + 1);
534 16 : len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
535 16 : addr[3] = secret;
536 16 : len[3] = secret_len;
537 16 : md5_vector(4, addr, len, hash);
538 16 : if (os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0)
539 1 : return 1;
540 :
541 53 : for (i = 0; i < msg->attr_used; i++) {
542 38 : tmp = radius_get_attr_hdr(msg, i);
543 38 : if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
544 0 : if (attr != NULL) {
545 0 : wpa_printf(MSG_WARNING, "Multiple "
546 : "Message-Authenticator attributes "
547 : "in RADIUS message");
548 0 : return 1;
549 : }
550 0 : attr = tmp;
551 : }
552 : }
553 :
554 15 : if (attr == NULL) {
555 : /* Message-Authenticator is MAY; not required */
556 15 : return 0;
557 : }
558 :
559 0 : os_memcpy(orig, attr + 1, MD5_MAC_LEN);
560 0 : os_memset(attr + 1, 0, MD5_MAC_LEN);
561 0 : os_memcpy(orig_authenticator, msg->hdr->authenticator,
562 : sizeof(orig_authenticator));
563 0 : os_memset(msg->hdr->authenticator, 0,
564 : sizeof(msg->hdr->authenticator));
565 0 : hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
566 0 : wpabuf_len(msg->buf), auth);
567 0 : os_memcpy(attr + 1, orig, MD5_MAC_LEN);
568 0 : os_memcpy(msg->hdr->authenticator, orig_authenticator,
569 : sizeof(orig_authenticator));
570 :
571 0 : return os_memcmp(orig, auth, MD5_MAC_LEN) != 0;
572 : }
573 :
574 :
575 51846 : static int radius_msg_add_attr_to_array(struct radius_msg *msg,
576 : struct radius_attr_hdr *attr)
577 : {
578 51846 : if (msg->attr_used >= msg->attr_size) {
579 : size_t *nattr_pos;
580 41 : int nlen = msg->attr_size * 2;
581 :
582 41 : nattr_pos = os_realloc_array(msg->attr_pos, nlen,
583 : sizeof(*msg->attr_pos));
584 41 : if (nattr_pos == NULL)
585 0 : return -1;
586 :
587 41 : msg->attr_pos = nattr_pos;
588 41 : msg->attr_size = nlen;
589 : }
590 :
591 103692 : msg->attr_pos[msg->attr_used++] =
592 51846 : (unsigned char *) attr - wpabuf_head_u8(msg->buf);
593 :
594 51846 : return 0;
595 : }
596 :
597 :
598 25948 : struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
599 : const u8 *data, size_t data_len)
600 : {
601 : size_t buf_needed;
602 : struct radius_attr_hdr *attr;
603 :
604 25948 : if (data_len > RADIUS_MAX_ATTR_LEN) {
605 0 : wpa_printf(MSG_ERROR, "radius_msg_add_attr: too long attribute (%lu bytes)",
606 : (unsigned long) data_len);
607 0 : return NULL;
608 : }
609 :
610 25948 : buf_needed = sizeof(*attr) + data_len;
611 :
612 25948 : if (wpabuf_tailroom(msg->buf) < buf_needed) {
613 : /* allocate more space for message buffer */
614 660 : if (wpabuf_resize(&msg->buf, buf_needed) < 0)
615 0 : return NULL;
616 660 : msg->hdr = wpabuf_mhead(msg->buf);
617 : }
618 :
619 25948 : attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr));
620 25948 : attr->type = type;
621 25948 : attr->length = sizeof(*attr) + data_len;
622 25948 : wpabuf_put_data(msg->buf, data, data_len);
623 :
624 25948 : if (radius_msg_add_attr_to_array(msg, attr))
625 0 : return NULL;
626 :
627 25948 : return attr;
628 : }
629 :
630 :
631 : /**
632 : * radius_msg_parse - Parse a RADIUS message
633 : * @data: RADIUS message to be parsed
634 : * @len: Length of data buffer in octets
635 : * Returns: Parsed RADIUS message or %NULL on failure
636 : *
637 : * This parses a RADIUS message and makes a copy of its data. The caller is
638 : * responsible for freeing the returned data with radius_msg_free().
639 : */
640 3269 : struct radius_msg * radius_msg_parse(const u8 *data, size_t len)
641 : {
642 : struct radius_msg *msg;
643 : struct radius_hdr *hdr;
644 : struct radius_attr_hdr *attr;
645 : size_t msg_len;
646 : unsigned char *pos, *end;
647 :
648 3269 : if (data == NULL || len < sizeof(*hdr))
649 0 : return NULL;
650 :
651 3269 : hdr = (struct radius_hdr *) data;
652 :
653 3269 : msg_len = be_to_host16(hdr->length);
654 3269 : if (msg_len < sizeof(*hdr) || msg_len > len) {
655 0 : wpa_printf(MSG_INFO, "RADIUS: Invalid message length");
656 0 : return NULL;
657 : }
658 :
659 3269 : if (msg_len < len) {
660 0 : wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after "
661 : "RADIUS message", (unsigned long) len - msg_len);
662 : }
663 :
664 3269 : msg = os_zalloc(sizeof(*msg));
665 3269 : if (msg == NULL)
666 0 : return NULL;
667 :
668 3269 : msg->buf = wpabuf_alloc_copy(data, msg_len);
669 3269 : if (msg->buf == NULL || radius_msg_initialize(msg)) {
670 0 : radius_msg_free(msg);
671 0 : return NULL;
672 : }
673 3269 : msg->hdr = wpabuf_mhead(msg->buf);
674 :
675 : /* parse attributes */
676 3269 : pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr);
677 3269 : end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf);
678 32436 : while (pos < end) {
679 25898 : if ((size_t) (end - pos) < sizeof(*attr))
680 0 : goto fail;
681 :
682 25898 : attr = (struct radius_attr_hdr *) pos;
683 :
684 25898 : if (pos + attr->length > end || attr->length < sizeof(*attr))
685 : goto fail;
686 :
687 : /* TODO: check that attr->length is suitable for attr->type */
688 :
689 25898 : if (radius_msg_add_attr_to_array(msg, attr))
690 0 : goto fail;
691 :
692 25898 : pos += attr->length;
693 : }
694 :
695 3269 : return msg;
696 :
697 : fail:
698 0 : radius_msg_free(msg);
699 0 : return NULL;
700 : }
701 :
702 :
703 3206 : int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len)
704 : {
705 3206 : const u8 *pos = data;
706 3206 : size_t left = data_len;
707 :
708 10653 : while (left > 0) {
709 : int len;
710 4241 : if (left > RADIUS_MAX_ATTR_LEN)
711 1035 : len = RADIUS_MAX_ATTR_LEN;
712 : else
713 3206 : len = left;
714 :
715 4241 : if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE,
716 : pos, len))
717 0 : return 0;
718 :
719 4241 : pos += len;
720 4241 : left -= len;
721 : }
722 :
723 3206 : return 1;
724 : }
725 :
726 :
727 3248 : struct wpabuf * radius_msg_get_eap(struct radius_msg *msg)
728 : {
729 : struct wpabuf *eap;
730 : size_t len, i;
731 : struct radius_attr_hdr *attr;
732 :
733 3248 : if (msg == NULL)
734 0 : return NULL;
735 :
736 3248 : len = 0;
737 29308 : for (i = 0; i < msg->attr_used; i++) {
738 26060 : attr = radius_get_attr_hdr(msg, i);
739 30342 : if (attr->type == RADIUS_ATTR_EAP_MESSAGE &&
740 4282 : attr->length > sizeof(struct radius_attr_hdr))
741 4282 : len += attr->length - sizeof(struct radius_attr_hdr);
742 : }
743 :
744 3248 : if (len == 0)
745 1 : return NULL;
746 :
747 3247 : eap = wpabuf_alloc(len);
748 3247 : if (eap == NULL)
749 0 : return NULL;
750 :
751 29299 : for (i = 0; i < msg->attr_used; i++) {
752 26052 : attr = radius_get_attr_hdr(msg, i);
753 30334 : if (attr->type == RADIUS_ATTR_EAP_MESSAGE &&
754 4282 : attr->length > sizeof(struct radius_attr_hdr)) {
755 4282 : int flen = attr->length - sizeof(*attr);
756 4282 : wpabuf_put_data(eap, attr + 1, flen);
757 : }
758 : }
759 :
760 3247 : return eap;
761 : }
762 :
763 :
764 3204 : int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
765 : size_t secret_len, const u8 *req_auth)
766 : {
767 : u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
768 : u8 orig_authenticator[16];
769 3204 : struct radius_attr_hdr *attr = NULL, *tmp;
770 : size_t i;
771 :
772 28726 : for (i = 0; i < msg->attr_used; i++) {
773 25522 : tmp = radius_get_attr_hdr(msg, i);
774 25522 : if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
775 3204 : if (attr != NULL) {
776 0 : wpa_printf(MSG_INFO, "Multiple Message-Authenticator attributes in RADIUS message");
777 0 : return 1;
778 : }
779 3204 : attr = tmp;
780 : }
781 : }
782 :
783 3204 : if (attr == NULL) {
784 0 : wpa_printf(MSG_INFO, "No Message-Authenticator attribute found");
785 0 : return 1;
786 : }
787 :
788 3204 : os_memcpy(orig, attr + 1, MD5_MAC_LEN);
789 3204 : os_memset(attr + 1, 0, MD5_MAC_LEN);
790 3204 : if (req_auth) {
791 1600 : os_memcpy(orig_authenticator, msg->hdr->authenticator,
792 : sizeof(orig_authenticator));
793 1600 : os_memcpy(msg->hdr->authenticator, req_auth,
794 : sizeof(msg->hdr->authenticator));
795 : }
796 3204 : hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
797 3204 : wpabuf_len(msg->buf), auth);
798 3204 : os_memcpy(attr + 1, orig, MD5_MAC_LEN);
799 3204 : if (req_auth) {
800 1600 : os_memcpy(msg->hdr->authenticator, orig_authenticator,
801 : sizeof(orig_authenticator));
802 : }
803 :
804 3204 : if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) {
805 1 : wpa_printf(MSG_INFO, "Invalid Message-Authenticator!");
806 1 : return 1;
807 : }
808 :
809 3203 : return 0;
810 : }
811 :
812 :
813 1622 : int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
814 : size_t secret_len, struct radius_msg *sent_msg, int auth)
815 : {
816 : const u8 *addr[4];
817 : size_t len[4];
818 : u8 hash[MD5_MAC_LEN];
819 :
820 1622 : if (sent_msg == NULL) {
821 0 : wpa_printf(MSG_INFO, "No matching Access-Request message found");
822 0 : return 1;
823 : }
824 :
825 3222 : if (auth &&
826 1600 : radius_msg_verify_msg_auth(msg, secret, secret_len,
827 1600 : sent_msg->hdr->authenticator)) {
828 0 : return 1;
829 : }
830 :
831 : /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
832 1622 : addr[0] = (u8 *) msg->hdr;
833 1622 : len[0] = 1 + 1 + 2;
834 1622 : addr[1] = sent_msg->hdr->authenticator;
835 1622 : len[1] = MD5_MAC_LEN;
836 1622 : addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
837 1622 : len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
838 1622 : addr[3] = secret;
839 1622 : len[3] = secret_len;
840 1622 : md5_vector(4, addr, len, hash);
841 1622 : if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
842 0 : wpa_printf(MSG_INFO, "Response Authenticator invalid!");
843 0 : return 1;
844 : }
845 :
846 1622 : return 0;
847 : }
848 :
849 :
850 2901 : int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
851 : u8 type)
852 : {
853 : struct radius_attr_hdr *attr;
854 : size_t i;
855 2901 : int count = 0;
856 :
857 27274 : for (i = 0; i < src->attr_used; i++) {
858 24373 : attr = radius_get_attr_hdr(src, i);
859 24373 : if (attr->type == type && attr->length >= sizeof(*attr)) {
860 1298 : if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1),
861 1298 : attr->length - sizeof(*attr)))
862 0 : return -1;
863 1298 : count++;
864 : }
865 : }
866 :
867 2901 : return count;
868 : }
869 :
870 :
871 : /* Create Request Authenticator. The value should be unique over the lifetime
872 : * of the shared secret between authenticator and authentication server.
873 : * Use one-way MD5 hash calculated from current timestamp and some data given
874 : * by the caller. */
875 1635 : void radius_msg_make_authenticator(struct radius_msg *msg,
876 : const u8 *data, size_t len)
877 : {
878 : struct os_time tv;
879 : long int l;
880 : const u8 *addr[3];
881 : size_t elen[3];
882 :
883 1635 : os_get_time(&tv);
884 1635 : l = os_random();
885 1635 : addr[0] = (u8 *) &tv;
886 1635 : elen[0] = sizeof(tv);
887 1635 : addr[1] = data;
888 1635 : elen[1] = len;
889 1635 : addr[2] = (u8 *) &l;
890 1635 : elen[2] = sizeof(l);
891 1635 : md5_vector(3, addr, elen, msg->hdr->authenticator);
892 1635 : }
893 :
894 :
895 : /* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message.
896 : * Returns the Attribute payload and sets alen to indicate the length of the
897 : * payload if a vendor attribute with subtype is found, otherwise returns NULL.
898 : * The returned payload is allocated with os_malloc() and caller must free it
899 : * by calling os_free().
900 : */
901 504 : static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
902 : u8 subtype, size_t *alen)
903 : {
904 : u8 *data, *pos;
905 : size_t i, len;
906 :
907 504 : if (msg == NULL)
908 0 : return NULL;
909 :
910 1260 : for (i = 0; i < msg->attr_used; i++) {
911 1260 : struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
912 : size_t left;
913 : u32 vendor_id;
914 : struct radius_attr_vendor *vhdr;
915 :
916 2016 : if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC ||
917 756 : attr->length < sizeof(*attr))
918 1008 : continue;
919 :
920 756 : left = attr->length - sizeof(*attr);
921 756 : if (left < 4)
922 0 : continue;
923 :
924 756 : pos = (u8 *) (attr + 1);
925 :
926 756 : os_memcpy(&vendor_id, pos, 4);
927 756 : pos += 4;
928 756 : left -= 4;
929 :
930 756 : if (ntohl(vendor_id) != vendor)
931 0 : continue;
932 :
933 1764 : while (left >= sizeof(*vhdr)) {
934 756 : vhdr = (struct radius_attr_vendor *) pos;
935 1512 : if (vhdr->vendor_length > left ||
936 756 : vhdr->vendor_length < sizeof(*vhdr)) {
937 0 : left = 0;
938 0 : break;
939 : }
940 756 : if (vhdr->vendor_type != subtype) {
941 252 : pos += vhdr->vendor_length;
942 252 : left -= vhdr->vendor_length;
943 252 : continue;
944 : }
945 :
946 504 : len = vhdr->vendor_length - sizeof(*vhdr);
947 504 : data = os_malloc(len);
948 504 : if (data == NULL)
949 504 : return NULL;
950 504 : os_memcpy(data, pos + sizeof(*vhdr), len);
951 504 : if (alen)
952 504 : *alen = len;
953 504 : return data;
954 : }
955 : }
956 :
957 0 : return NULL;
958 : }
959 :
960 :
961 504 : static u8 * decrypt_ms_key(const u8 *key, size_t len,
962 : const u8 *req_authenticator,
963 : const u8 *secret, size_t secret_len, size_t *reslen)
964 : {
965 : u8 *plain, *ppos, *res;
966 : const u8 *pos;
967 : size_t left, plen;
968 : u8 hash[MD5_MAC_LEN];
969 504 : int i, first = 1;
970 : const u8 *addr[3];
971 : size_t elen[3];
972 :
973 : /* key: 16-bit salt followed by encrypted key info */
974 :
975 504 : if (len < 2 + 16)
976 0 : return NULL;
977 :
978 504 : pos = key + 2;
979 504 : left = len - 2;
980 504 : if (left % 16) {
981 0 : wpa_printf(MSG_INFO, "Invalid ms key len %lu",
982 : (unsigned long) left);
983 0 : return NULL;
984 : }
985 :
986 504 : plen = left;
987 504 : ppos = plain = os_malloc(plen);
988 504 : if (plain == NULL)
989 0 : return NULL;
990 504 : plain[0] = 0;
991 :
992 2520 : while (left > 0) {
993 : /* b(1) = MD5(Secret + Request-Authenticator + Salt)
994 : * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
995 :
996 1512 : addr[0] = secret;
997 1512 : elen[0] = secret_len;
998 1512 : if (first) {
999 504 : addr[1] = req_authenticator;
1000 504 : elen[1] = MD5_MAC_LEN;
1001 504 : addr[2] = key;
1002 504 : elen[2] = 2; /* Salt */
1003 : } else {
1004 1008 : addr[1] = pos - MD5_MAC_LEN;
1005 1008 : elen[1] = MD5_MAC_LEN;
1006 : }
1007 1512 : md5_vector(first ? 3 : 2, addr, elen, hash);
1008 1512 : first = 0;
1009 :
1010 25704 : for (i = 0; i < MD5_MAC_LEN; i++)
1011 24192 : *ppos++ = *pos++ ^ hash[i];
1012 1512 : left -= MD5_MAC_LEN;
1013 : }
1014 :
1015 504 : if (plain[0] == 0 || plain[0] > plen - 1) {
1016 0 : wpa_printf(MSG_INFO, "Failed to decrypt MPPE key");
1017 0 : os_free(plain);
1018 0 : return NULL;
1019 : }
1020 :
1021 504 : res = os_malloc(plain[0]);
1022 504 : if (res == NULL) {
1023 0 : os_free(plain);
1024 0 : return NULL;
1025 : }
1026 504 : os_memcpy(res, plain + 1, plain[0]);
1027 504 : if (reslen)
1028 504 : *reslen = plain[0];
1029 504 : os_free(plain);
1030 504 : return res;
1031 : }
1032 :
1033 :
1034 506 : static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt,
1035 : const u8 *req_authenticator,
1036 : const u8 *secret, size_t secret_len,
1037 : u8 *ebuf, size_t *elen)
1038 : {
1039 506 : int i, len, first = 1;
1040 : u8 hash[MD5_MAC_LEN], saltbuf[2], *pos;
1041 : const u8 *addr[3];
1042 : size_t _len[3];
1043 :
1044 506 : WPA_PUT_BE16(saltbuf, salt);
1045 :
1046 506 : len = 1 + key_len;
1047 506 : if (len & 0x0f) {
1048 506 : len = (len & 0xf0) + 16;
1049 : }
1050 506 : os_memset(ebuf, 0, len);
1051 506 : ebuf[0] = key_len;
1052 506 : os_memcpy(ebuf + 1, key, key_len);
1053 :
1054 506 : *elen = len;
1055 :
1056 506 : pos = ebuf;
1057 2530 : while (len > 0) {
1058 : /* b(1) = MD5(Secret + Request-Authenticator + Salt)
1059 : * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
1060 1518 : addr[0] = secret;
1061 1518 : _len[0] = secret_len;
1062 1518 : if (first) {
1063 506 : addr[1] = req_authenticator;
1064 506 : _len[1] = MD5_MAC_LEN;
1065 506 : addr[2] = saltbuf;
1066 506 : _len[2] = sizeof(saltbuf);
1067 : } else {
1068 1012 : addr[1] = pos - MD5_MAC_LEN;
1069 1012 : _len[1] = MD5_MAC_LEN;
1070 : }
1071 1518 : md5_vector(first ? 3 : 2, addr, _len, hash);
1072 1518 : first = 0;
1073 :
1074 25806 : for (i = 0; i < MD5_MAC_LEN; i++)
1075 24288 : *pos++ ^= hash[i];
1076 :
1077 1518 : len -= MD5_MAC_LEN;
1078 : }
1079 506 : }
1080 :
1081 :
1082 : struct radius_ms_mppe_keys *
1083 252 : radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
1084 : const u8 *secret, size_t secret_len)
1085 : {
1086 : u8 *key;
1087 : size_t keylen;
1088 : struct radius_ms_mppe_keys *keys;
1089 :
1090 252 : if (msg == NULL || sent_msg == NULL)
1091 0 : return NULL;
1092 :
1093 252 : keys = os_zalloc(sizeof(*keys));
1094 252 : if (keys == NULL)
1095 0 : return NULL;
1096 :
1097 252 : key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
1098 : RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY,
1099 : &keylen);
1100 252 : if (key) {
1101 504 : keys->send = decrypt_ms_key(key, keylen,
1102 252 : sent_msg->hdr->authenticator,
1103 : secret, secret_len,
1104 : &keys->send_len);
1105 252 : os_free(key);
1106 : }
1107 :
1108 252 : key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
1109 : RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY,
1110 : &keylen);
1111 252 : if (key) {
1112 504 : keys->recv = decrypt_ms_key(key, keylen,
1113 252 : sent_msg->hdr->authenticator,
1114 : secret, secret_len,
1115 : &keys->recv_len);
1116 252 : os_free(key);
1117 : }
1118 :
1119 252 : return keys;
1120 : }
1121 :
1122 :
1123 : struct radius_ms_mppe_keys *
1124 0 : radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
1125 : const u8 *secret, size_t secret_len)
1126 : {
1127 : u8 *key;
1128 : size_t keylen;
1129 : struct radius_ms_mppe_keys *keys;
1130 :
1131 0 : if (msg == NULL || sent_msg == NULL)
1132 0 : return NULL;
1133 :
1134 0 : keys = os_zalloc(sizeof(*keys));
1135 0 : if (keys == NULL)
1136 0 : return NULL;
1137 :
1138 0 : key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO,
1139 : RADIUS_CISCO_AV_PAIR, &keylen);
1140 0 : if (key && keylen == 51 &&
1141 0 : os_memcmp(key, "leap:session-key=", 17) == 0) {
1142 0 : keys->recv = decrypt_ms_key(key + 17, keylen - 17,
1143 0 : sent_msg->hdr->authenticator,
1144 : secret, secret_len,
1145 : &keys->recv_len);
1146 : }
1147 0 : os_free(key);
1148 :
1149 0 : return keys;
1150 : }
1151 :
1152 :
1153 253 : int radius_msg_add_mppe_keys(struct radius_msg *msg,
1154 : const u8 *req_authenticator,
1155 : const u8 *secret, size_t secret_len,
1156 : const u8 *send_key, size_t send_key_len,
1157 : const u8 *recv_key, size_t recv_key_len)
1158 : {
1159 : struct radius_attr_hdr *attr;
1160 253 : u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT);
1161 : u8 *buf;
1162 : struct radius_attr_vendor *vhdr;
1163 : u8 *pos;
1164 : size_t elen;
1165 : int hlen;
1166 : u16 salt;
1167 :
1168 253 : hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2;
1169 :
1170 : /* MS-MPPE-Send-Key */
1171 253 : buf = os_malloc(hlen + send_key_len + 16);
1172 253 : if (buf == NULL) {
1173 0 : return 0;
1174 : }
1175 253 : pos = buf;
1176 253 : os_memcpy(pos, &vendor_id, sizeof(vendor_id));
1177 253 : pos += sizeof(vendor_id);
1178 253 : vhdr = (struct radius_attr_vendor *) pos;
1179 253 : vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY;
1180 253 : pos = (u8 *) (vhdr + 1);
1181 253 : salt = os_random() | 0x8000;
1182 253 : WPA_PUT_BE16(pos, salt);
1183 253 : pos += 2;
1184 253 : encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret,
1185 : secret_len, pos, &elen);
1186 253 : vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
1187 :
1188 253 : attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
1189 : buf, hlen + elen);
1190 253 : os_free(buf);
1191 253 : if (attr == NULL) {
1192 0 : return 0;
1193 : }
1194 :
1195 : /* MS-MPPE-Recv-Key */
1196 253 : buf = os_malloc(hlen + send_key_len + 16);
1197 253 : if (buf == NULL) {
1198 0 : return 0;
1199 : }
1200 253 : pos = buf;
1201 253 : os_memcpy(pos, &vendor_id, sizeof(vendor_id));
1202 253 : pos += sizeof(vendor_id);
1203 253 : vhdr = (struct radius_attr_vendor *) pos;
1204 253 : vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY;
1205 253 : pos = (u8 *) (vhdr + 1);
1206 253 : salt ^= 1;
1207 253 : WPA_PUT_BE16(pos, salt);
1208 253 : pos += 2;
1209 253 : encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret,
1210 : secret_len, pos, &elen);
1211 253 : vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
1212 :
1213 253 : attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
1214 : buf, hlen + elen);
1215 253 : os_free(buf);
1216 253 : if (attr == NULL) {
1217 0 : return 0;
1218 : }
1219 :
1220 253 : return 1;
1221 : }
1222 :
1223 :
1224 975 : int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data,
1225 : size_t len)
1226 : {
1227 : struct radius_attr_hdr *attr;
1228 : u8 *buf, *pos;
1229 : size_t alen;
1230 :
1231 975 : alen = 4 + 2 + len;
1232 975 : buf = os_malloc(alen);
1233 975 : if (buf == NULL)
1234 0 : return 0;
1235 975 : pos = buf;
1236 975 : WPA_PUT_BE32(pos, RADIUS_VENDOR_ID_WFA);
1237 975 : pos += 4;
1238 975 : *pos++ = subtype;
1239 975 : *pos++ = 2 + len;
1240 975 : os_memcpy(pos, data, len);
1241 975 : attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
1242 : buf, alen);
1243 975 : os_free(buf);
1244 975 : if (attr == NULL)
1245 0 : return 0;
1246 :
1247 975 : return 1;
1248 : }
1249 :
1250 :
1251 2 : int radius_user_password_hide(struct radius_msg *msg,
1252 : const u8 *data, size_t data_len,
1253 : const u8 *secret, size_t secret_len,
1254 : u8 *buf, size_t buf_len)
1255 : {
1256 : size_t padlen, i, pos;
1257 : const u8 *addr[2];
1258 : size_t len[2];
1259 : u8 hash[16];
1260 :
1261 2 : if (data_len + 16 > buf_len)
1262 0 : return -1;
1263 :
1264 2 : os_memcpy(buf, data, data_len);
1265 :
1266 2 : padlen = data_len % 16;
1267 2 : if (padlen && data_len < buf_len) {
1268 2 : padlen = 16 - padlen;
1269 2 : os_memset(buf + data_len, 0, padlen);
1270 2 : buf_len = data_len + padlen;
1271 : } else {
1272 0 : buf_len = data_len;
1273 : }
1274 :
1275 2 : addr[0] = secret;
1276 2 : len[0] = secret_len;
1277 2 : addr[1] = msg->hdr->authenticator;
1278 2 : len[1] = 16;
1279 2 : md5_vector(2, addr, len, hash);
1280 :
1281 34 : for (i = 0; i < 16; i++)
1282 32 : buf[i] ^= hash[i];
1283 2 : pos = 16;
1284 :
1285 4 : while (pos < buf_len) {
1286 0 : addr[0] = secret;
1287 0 : len[0] = secret_len;
1288 0 : addr[1] = &buf[pos - 16];
1289 0 : len[1] = 16;
1290 0 : md5_vector(2, addr, len, hash);
1291 :
1292 0 : for (i = 0; i < 16; i++)
1293 0 : buf[pos + i] ^= hash[i];
1294 :
1295 0 : pos += 16;
1296 : }
1297 :
1298 2 : return buf_len;
1299 : }
1300 :
1301 :
1302 : /* Add User-Password attribute to a RADIUS message and encrypt it as specified
1303 : * in RFC 2865, Chap. 5.2 */
1304 : struct radius_attr_hdr *
1305 1 : radius_msg_add_attr_user_password(struct radius_msg *msg,
1306 : const u8 *data, size_t data_len,
1307 : const u8 *secret, size_t secret_len)
1308 : {
1309 : u8 buf[128];
1310 : int res;
1311 :
1312 1 : res = radius_user_password_hide(msg, data, data_len,
1313 : secret, secret_len, buf, sizeof(buf));
1314 1 : if (res < 0)
1315 0 : return NULL;
1316 :
1317 1 : return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD,
1318 : buf, res);
1319 : }
1320 :
1321 :
1322 5118 : int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
1323 : {
1324 5118 : struct radius_attr_hdr *attr = NULL, *tmp;
1325 : size_t i, dlen;
1326 :
1327 34282 : for (i = 0; i < msg->attr_used; i++) {
1328 30523 : tmp = radius_get_attr_hdr(msg, i);
1329 30523 : if (tmp->type == type) {
1330 1359 : attr = tmp;
1331 1359 : break;
1332 : }
1333 : }
1334 :
1335 5118 : if (!attr || attr->length < sizeof(*attr))
1336 3759 : return -1;
1337 :
1338 1359 : dlen = attr->length - sizeof(*attr);
1339 1359 : if (buf)
1340 1313 : os_memcpy(buf, (attr + 1), dlen > len ? len : dlen);
1341 1359 : return dlen;
1342 : }
1343 :
1344 :
1345 1650 : int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
1346 : size_t *len, const u8 *start)
1347 : {
1348 : size_t i;
1349 1650 : struct radius_attr_hdr *attr = NULL, *tmp;
1350 :
1351 5683 : for (i = 0; i < msg->attr_used; i++) {
1352 4874 : tmp = radius_get_attr_hdr(msg, i);
1353 4874 : if (tmp->type == type &&
1354 1024 : (start == NULL || (u8 *) tmp > start)) {
1355 841 : attr = tmp;
1356 841 : break;
1357 : }
1358 : }
1359 :
1360 1650 : if (!attr || attr->length < sizeof(*attr))
1361 809 : return -1;
1362 :
1363 841 : *buf = (u8 *) (attr + 1);
1364 841 : *len = attr->length - sizeof(*attr);
1365 841 : return 0;
1366 : }
1367 :
1368 :
1369 8 : int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len)
1370 : {
1371 : size_t i;
1372 : int count;
1373 :
1374 47 : for (count = 0, i = 0; i < msg->attr_used; i++) {
1375 39 : struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
1376 43 : if (attr->type == type &&
1377 4 : attr->length >= sizeof(struct radius_attr_hdr) + min_len)
1378 4 : count++;
1379 : }
1380 :
1381 8 : return count;
1382 : }
1383 :
1384 :
1385 : struct radius_tunnel_attrs {
1386 : int tag_used;
1387 : int type; /* Tunnel-Type */
1388 : int medium_type; /* Tunnel-Medium-Type */
1389 : int vlanid;
1390 : };
1391 :
1392 :
1393 : /**
1394 : * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
1395 : * @msg: RADIUS message
1396 : * Returns: VLAN ID for the first tunnel configuration of -1 if none is found
1397 : */
1398 6 : int radius_msg_get_vlanid(struct radius_msg *msg)
1399 : {
1400 : struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun;
1401 : size_t i;
1402 6 : struct radius_attr_hdr *attr = NULL;
1403 : const u8 *data;
1404 : char buf[10];
1405 : size_t dlen;
1406 :
1407 6 : os_memset(&tunnel, 0, sizeof(tunnel));
1408 :
1409 36 : for (i = 0; i < msg->attr_used; i++) {
1410 30 : attr = radius_get_attr_hdr(msg, i);
1411 30 : if (attr->length < sizeof(*attr))
1412 0 : return -1;
1413 30 : data = (const u8 *) (attr + 1);
1414 30 : dlen = attr->length - sizeof(*attr);
1415 30 : if (attr->length < 3)
1416 0 : continue;
1417 30 : if (data[0] >= RADIUS_TUNNEL_TAGS)
1418 8 : tun = &tunnel[0];
1419 : else
1420 22 : tun = &tunnel[data[0]];
1421 :
1422 30 : switch (attr->type) {
1423 : case RADIUS_ATTR_TUNNEL_TYPE:
1424 3 : if (attr->length != 6)
1425 0 : break;
1426 3 : tun->tag_used++;
1427 3 : tun->type = WPA_GET_BE24(data + 1);
1428 3 : break;
1429 : case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE:
1430 3 : if (attr->length != 6)
1431 0 : break;
1432 3 : tun->tag_used++;
1433 3 : tun->medium_type = WPA_GET_BE24(data + 1);
1434 3 : break;
1435 : case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID:
1436 3 : if (data[0] < RADIUS_TUNNEL_TAGS) {
1437 0 : data++;
1438 0 : dlen--;
1439 : }
1440 3 : if (dlen >= sizeof(buf))
1441 0 : break;
1442 3 : os_memcpy(buf, data, dlen);
1443 3 : buf[dlen] = '\0';
1444 3 : tun->tag_used++;
1445 3 : tun->vlanid = atoi(buf);
1446 3 : break;
1447 : }
1448 : }
1449 :
1450 102 : for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) {
1451 99 : tun = &tunnel[i];
1452 102 : if (tun->tag_used &&
1453 6 : tun->type == RADIUS_TUNNEL_TYPE_VLAN &&
1454 6 : tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 &&
1455 3 : tun->vlanid > 0)
1456 3 : return tun->vlanid;
1457 : }
1458 :
1459 3 : return -1;
1460 : }
1461 :
1462 :
1463 : /**
1464 : * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password
1465 : * @msg: Received RADIUS message
1466 : * @keylen: Length of returned password
1467 : * @secret: RADIUS shared secret
1468 : * @secret_len: Length of secret
1469 : * @sent_msg: Sent RADIUS message
1470 : * @n: Number of password attribute to return (starting with 0)
1471 : * Returns: Pointer to n-th password (free with os_free) or %NULL
1472 : */
1473 1 : char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
1474 : const u8 *secret, size_t secret_len,
1475 : struct radius_msg *sent_msg, size_t n)
1476 : {
1477 1 : u8 *buf = NULL;
1478 : size_t buflen;
1479 : const u8 *salt;
1480 : u8 *str;
1481 : const u8 *addr[3];
1482 : size_t len[3];
1483 : u8 hash[16];
1484 : u8 *pos;
1485 1 : size_t i, j = 0;
1486 : struct radius_attr_hdr *attr;
1487 : const u8 *data;
1488 : size_t dlen;
1489 1 : const u8 *fdata = NULL; /* points to found item */
1490 1 : size_t fdlen = -1;
1491 1 : char *ret = NULL;
1492 :
1493 : /* find n-th valid Tunnel-Password attribute */
1494 2 : for (i = 0; i < msg->attr_used; i++) {
1495 1 : attr = radius_get_attr_hdr(msg, i);
1496 2 : if (attr == NULL ||
1497 1 : attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) {
1498 1 : continue;
1499 : }
1500 0 : if (attr->length <= 5)
1501 0 : continue;
1502 0 : data = (const u8 *) (attr + 1);
1503 0 : dlen = attr->length - sizeof(*attr);
1504 0 : if (dlen <= 3 || dlen % 16 != 3)
1505 0 : continue;
1506 0 : j++;
1507 0 : if (j <= n)
1508 0 : continue;
1509 :
1510 0 : fdata = data;
1511 0 : fdlen = dlen;
1512 0 : break;
1513 : }
1514 1 : if (fdata == NULL)
1515 1 : goto out;
1516 :
1517 : /* alloc writable memory for decryption */
1518 0 : buf = os_malloc(fdlen);
1519 0 : if (buf == NULL)
1520 0 : goto out;
1521 0 : os_memcpy(buf, fdata, fdlen);
1522 0 : buflen = fdlen;
1523 :
1524 : /* init pointers */
1525 0 : salt = buf + 1;
1526 0 : str = buf + 3;
1527 :
1528 : /* decrypt blocks */
1529 0 : pos = buf + buflen - 16; /* last block */
1530 0 : while (pos >= str + 16) { /* all but the first block */
1531 0 : addr[0] = secret;
1532 0 : len[0] = secret_len;
1533 0 : addr[1] = pos - 16;
1534 0 : len[1] = 16;
1535 0 : md5_vector(2, addr, len, hash);
1536 :
1537 0 : for (i = 0; i < 16; i++)
1538 0 : pos[i] ^= hash[i];
1539 :
1540 0 : pos -= 16;
1541 : }
1542 :
1543 : /* decrypt first block */
1544 0 : if (str != pos)
1545 0 : goto out;
1546 0 : addr[0] = secret;
1547 0 : len[0] = secret_len;
1548 0 : addr[1] = sent_msg->hdr->authenticator;
1549 0 : len[1] = 16;
1550 0 : addr[2] = salt;
1551 0 : len[2] = 2;
1552 0 : md5_vector(3, addr, len, hash);
1553 :
1554 0 : for (i = 0; i < 16; i++)
1555 0 : pos[i] ^= hash[i];
1556 :
1557 : /* derive plaintext length from first subfield */
1558 0 : *keylen = (unsigned char) str[0];
1559 0 : if ((u8 *) (str + *keylen) >= (u8 *) (buf + buflen)) {
1560 : /* decryption error - invalid key length */
1561 0 : goto out;
1562 : }
1563 0 : if (*keylen == 0) {
1564 : /* empty password */
1565 0 : goto out;
1566 : }
1567 :
1568 : /* copy passphrase into new buffer */
1569 0 : ret = os_malloc(*keylen);
1570 0 : if (ret)
1571 0 : os_memcpy(ret, str + 1, *keylen);
1572 :
1573 : out:
1574 : /* return new buffer */
1575 1 : os_free(buf);
1576 1 : return ret;
1577 : }
1578 :
1579 :
1580 662 : void radius_free_class(struct radius_class_data *c)
1581 : {
1582 : size_t i;
1583 662 : if (c == NULL)
1584 662 : return;
1585 671 : for (i = 0; i < c->count; i++)
1586 9 : os_free(c->attr[i].data);
1587 662 : os_free(c->attr);
1588 662 : c->attr = NULL;
1589 662 : c->count = 0;
1590 : }
1591 :
1592 :
1593 282 : int radius_copy_class(struct radius_class_data *dst,
1594 : const struct radius_class_data *src)
1595 : {
1596 : size_t i;
1597 :
1598 282 : if (src->attr == NULL)
1599 277 : return 0;
1600 :
1601 5 : dst->attr = os_calloc(src->count, sizeof(struct radius_attr_data));
1602 5 : if (dst->attr == NULL)
1603 0 : return -1;
1604 :
1605 5 : dst->count = 0;
1606 :
1607 10 : for (i = 0; i < src->count; i++) {
1608 5 : dst->attr[i].data = os_malloc(src->attr[i].len);
1609 5 : if (dst->attr[i].data == NULL)
1610 0 : break;
1611 5 : dst->count++;
1612 5 : os_memcpy(dst->attr[i].data, src->attr[i].data,
1613 : src->attr[i].len);
1614 5 : dst->attr[i].len = src->attr[i].len;
1615 : }
1616 :
1617 5 : return 0;
1618 : }
1619 :
1620 :
1621 12 : u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs)
1622 : {
1623 : size_t i, j;
1624 : struct radius_attr_hdr *attr;
1625 :
1626 43 : for (i = 0; i < msg->attr_used; i++) {
1627 32 : attr = radius_get_attr_hdr(msg, i);
1628 :
1629 146 : for (j = 0; attrs[j]; j++) {
1630 145 : if (attr->type == attrs[j])
1631 31 : break;
1632 : }
1633 :
1634 32 : if (attrs[j] == 0)
1635 1 : return attr->type; /* unlisted attr */
1636 : }
1637 :
1638 11 : return 0;
1639 : }
|