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