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