EAP Channel binding support
[mech_eap.git] / libeap / src / utils / radius_utils.c
1 /*
2  * RADIUS tlv construction and parsing utilites
3  * Copyright (c) 2012, Painless Security, LLC
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include "includes.h"
16
17 #include "common.h"
18
19 #include "radius/radius.h"
20 #include "radius_utils.h"
21 #include "wpabuf.h"
22
23 int radius_add_tlv(struct wpabuf **buf, u32 type, u32 vendor, u8 *data,
24                    size_t len)
25 {
26         u8 base_type;
27         u8 total;
28         if (vendor) {
29                 if (len + 6 > RADIUS_MAX_ATTR_LEN)
30                         return -1;
31                 total = len + 2 + 6;
32                 base_type = RADIUS_ATTR_VENDOR_SPECIFIC;
33         } else {
34                 if (len > RADIUS_MAX_ATTR_LEN)
35                         return -1;
36                 total = len + 2;
37                 base_type = type;
38         }
39
40         /* ensure buffer has enough space */
41         if (wpabuf_resize(buf, total))
42                 return -1;
43
44         /* write into buffer */
45         wpabuf_put_u8(*buf, base_type);
46         wpabuf_put_u8(*buf, total);
47         if (vendor) {
48                 wpabuf_put_be32(*buf, vendor);
49                 wpabuf_put_u8(*buf, (u8 )type);
50                 wpabuf_put_u8(*buf, (u8 )len+2);
51         }
52         wpabuf_put_data(*buf, data, len);
53         return 0;
54 }
55
56 struct radius_parser_struct
57 {
58         u8 *data;
59         size_t len;
60         size_t pos;
61 };
62
63 radius_parser radius_parser_start(void *tlvdata, size_t len)
64 {
65         radius_parser parser = malloc(sizeof(struct radius_parser_struct));
66         if (parser) {
67                 parser->data = (u8 *)tlvdata;
68                 parser->len = len;
69                 parser->pos = 0;
70         }
71         return parser;
72 }
73
74 void radius_parser_finish(radius_parser parser)
75 {
76         free(parser);
77 }
78
79 int radius_parser_parse_tlv(radius_parser parser, u8 *type, u32 *vendor_id,
80                             void **value, size_t *len)
81 {
82         u8 rawtype, rawlen;
83         if (!parser)
84                 return -1;
85         if (parser->len < parser->pos + 3)
86                 return -1;
87         rawtype = parser->data[parser->pos];
88         rawlen = parser->data[parser->pos+1];
89         if (parser->len < parser->pos + rawlen)
90                 return -1;
91
92         if (rawtype == RADIUS_ATTR_VENDOR_SPECIFIC) {
93                 if (rawlen < 7)
94                         return -1;
95                 *vendor_id = WPA_GET_BE24(&parser->data[parser->pos + 3]);
96                 *value = &parser->data[parser->pos + 6];
97                 *len = rawlen - 6;
98         } else {
99                 if (rawlen < 3)
100                         return -1;
101
102                 *value = &parser->data[parser->pos + 2];
103                 *len = rawlen - 2;
104         }
105         *type = rawtype;
106
107         parser->pos += rawlen;
108         return 0;
109 }
110
111 int radius_parser_parse_vendor_specific(radius_parser parser, u8 *vendor_type,
112                                         void **value, size_t *len)
113 {
114         u8 rawtype, rawlen;
115         if (!parser)
116                 return -1;
117         if (parser->len < parser->pos + 3)
118                 return -1;
119         rawtype = parser->data[parser->pos];
120         rawlen = parser->data[parser->pos+1];
121         if (parser->len < parser->pos + rawlen)
122                 return -1;
123
124         if (rawlen < 3)
125                 return -1;
126
127         *value = &parser->data[parser->pos + 2];
128         *len = rawlen - 2;
129         *vendor_type = rawtype;
130
131         parser->pos += rawlen;
132         return 0;
133 }