1b9a5c8028c00083192cf37e34d12ff847452987
[strongswan.git] / src / libcharon / encoding / payloads / eap_payload.c
1 /*
2 * Copyright (C) 2005-2010 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include <stddef.h>
18
19 #include "eap_payload.h"
20
21 #include <daemon.h>
22 #include <eap/eap.h>
23
24 typedef struct private_eap_payload_t private_eap_payload_t;
25
26 /**
27 * Private data of an eap_payload_t object.
28 *
29 */
30 struct private_eap_payload_t {
31 /**
32 * Public eap_payload_t interface.
33 */
34 eap_payload_t public;
35
36 /**
37 * Next payload type.
38 */
39 u_int8_t next_payload;
40
41 /**
42 * Critical flag.
43 */
44 bool critical;
45
46 /**
47 * Reserved bits
48 */
49 bool reserved[7];
50
51 /**
52 * Length of this payload.
53 */
54 u_int16_t payload_length;
55
56 /**
57 * EAP message data, if available
58 */
59 chunk_t data;
60 };
61
62 /**
63 * Encoding rules to parse or generate a EAP payload.
64 *
65 * The defined offsets are the positions in a object of type
66 * private_eap_payload_t.
67 *
68 */
69 static encoding_rule_t encodings[] = {
70 /* 1 Byte next payload type, stored in the field next_payload */
71 { U_INT_8, offsetof(private_eap_payload_t, next_payload) },
72 /* the critical bit */
73 { FLAG, offsetof(private_eap_payload_t, critical) },
74 /* 7 Bit reserved bits, nowhere stored */
75 { RESERVED_BIT, offsetof(private_eap_payload_t, reserved[0]) },
76 { RESERVED_BIT, offsetof(private_eap_payload_t, reserved[1]) },
77 { RESERVED_BIT, offsetof(private_eap_payload_t, reserved[2]) },
78 { RESERVED_BIT, offsetof(private_eap_payload_t, reserved[3]) },
79 { RESERVED_BIT, offsetof(private_eap_payload_t, reserved[4]) },
80 { RESERVED_BIT, offsetof(private_eap_payload_t, reserved[5]) },
81 { RESERVED_BIT, offsetof(private_eap_payload_t, reserved[6]) },
82 /* Length of the whole payload*/
83 { PAYLOAD_LENGTH, offsetof(private_eap_payload_t, payload_length) },
84 /* chunt to data, starting at "code" */
85 { CHUNK_DATA, offsetof(private_eap_payload_t, data) },
86 };
87
88 /*
89 1 2 3
90 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
91 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
92 ! Next Payload !C! RESERVED ! Payload Length !
93 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
94 ! Code ! Identifier ! Length !
95 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
96 ! Type ! Type_Data...
97 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
98 */
99
100 METHOD(payload_t, verify, status_t,
101 private_eap_payload_t *this)
102 {
103 u_int16_t length;
104 u_int8_t code;
105
106 if (this->data.len < 4)
107 {
108 DBG1(DBG_ENC, "EAP payloads EAP message too short (%d)", this->data.len);
109 return FAILED;
110 }
111 length = untoh16(this->data.ptr + 2);
112 if (this->data.len != length)
113 {
114 DBG1(DBG_ENC, "EAP payload length (%d) does not match contained "
115 "message length (%d)", this->data.len, length);
116 return FAILED;
117 }
118 code = this->data.ptr[0];
119 switch (code)
120 {
121 case EAP_REQUEST:
122 case EAP_RESPONSE:
123 {
124 if (this->data.len < 4)
125 {
126 DBG1(DBG_ENC, "EAP Request/Response does not have any data");
127 return FAILED;
128 }
129 break;
130 }
131 case EAP_SUCCESS:
132 case EAP_FAILURE:
133 {
134 if (this->data.len != 4)
135 {
136 DBG1(DBG_ENC, "EAP Success/Failure has data");
137 return FAILED;
138 }
139 break;
140 }
141 default:
142 return FAILED;
143 }
144 return SUCCESS;
145 }
146
147 METHOD(payload_t, get_encoding_rules, int,
148 private_eap_payload_t *this, encoding_rule_t **rules)
149 {
150 *rules = encodings;
151 return countof(encodings);
152 }
153
154 METHOD(payload_t, get_header_length, int,
155 private_eap_payload_t *this)
156 {
157 return 4;
158 }
159
160 METHOD(payload_t, get_payload_type, payload_type_t,
161 private_eap_payload_t *this)
162 {
163 return EXTENSIBLE_AUTHENTICATION;
164 }
165
166 METHOD(payload_t, get_next_type, payload_type_t,
167 private_eap_payload_t *this)
168 {
169 return (this->next_payload);
170 }
171
172 METHOD(payload_t, set_next_type, void,
173 private_eap_payload_t *this, payload_type_t type)
174 {
175 this->next_payload = type;
176 }
177
178 METHOD(payload_t, get_length, size_t,
179 private_eap_payload_t *this)
180 {
181 return this->payload_length;
182 }
183
184 METHOD(eap_payload_t, get_data, chunk_t,
185 private_eap_payload_t *this)
186 {
187 return this->data;
188 }
189
190 METHOD(eap_payload_t, set_data, void,
191 private_eap_payload_t *this, chunk_t data)
192 {
193 free(this->data.ptr);
194 this->data = chunk_clone(data);
195 this->payload_length = this->data.len + 4;
196 }
197
198 METHOD(eap_payload_t, get_code, eap_code_t,
199 private_eap_payload_t *this)
200 {
201 if (this->data.len > 0)
202 {
203 return this->data.ptr[0];
204 }
205 /* should not happen, as it is verified */
206 return 0;
207 }
208
209 METHOD(eap_payload_t, get_identifier, u_int8_t,
210 private_eap_payload_t *this)
211 {
212 if (this->data.len > 1)
213 {
214 return this->data.ptr[1];
215 }
216 /* should not happen, as it is verified */
217 return 0;
218 }
219
220 METHOD(eap_payload_t, get_type, eap_type_t,
221 private_eap_payload_t *this, u_int32_t *vendor)
222 {
223 eap_type_t type;
224
225 *vendor = 0;
226 if (this->data.len > 4)
227 {
228 type = this->data.ptr[4];
229 if (type != EAP_EXPANDED)
230 {
231 return type;
232 }
233 if (this->data.len >= 12)
234 {
235 *vendor = untoh32(this->data.ptr + 4) & 0x00FFFFFF;
236 return untoh32(this->data.ptr + 8);
237 }
238 }
239 return 0;
240 }
241
242 METHOD2(payload_t, eap_payload_t, destroy, void,
243 private_eap_payload_t *this)
244 {
245 chunk_free(&this->data);
246 free(this);
247 }
248
249 /*
250 * Described in header
251 */
252 eap_payload_t *eap_payload_create()
253 {
254 private_eap_payload_t *this;
255
256 INIT(this,
257 .public = {
258 .payload_interface = {
259 .verify = _verify,
260 .get_encoding_rules = _get_encoding_rules,
261 .get_header_length = _get_header_length,
262 .get_length = _get_length,
263 .get_next_type = _get_next_type,
264 .set_next_type = _set_next_type,
265 .get_type = _get_payload_type,
266 .destroy = _destroy,
267 },
268 .get_data = _get_data,
269 .set_data = _set_data,
270 .get_code = _get_code,
271 .get_identifier = _get_identifier,
272 .get_type = _get_type,
273 .destroy = _destroy,
274 },
275 .next_payload = NO_PAYLOAD,
276 .payload_length = get_header_length(this),
277 );
278 return &this->public;
279 }
280
281 /*
282 * Described in header
283 */
284 eap_payload_t *eap_payload_create_data(chunk_t data)
285 {
286 eap_payload_t *this = eap_payload_create();
287
288 this->set_data(this, data);
289 return this;
290 }
291
292 /*
293 * Described in header
294 */
295 eap_payload_t *eap_payload_create_data_own(chunk_t data)
296 {
297 eap_payload_t *this = eap_payload_create();
298
299 this->set_data(this, data);
300 free(data.ptr);
301 return this;
302 }
303
304 /*
305 * Described in header
306 */
307 eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier)
308 {
309 chunk_t data;
310
311 data = chunk_from_chars(code, identifier, 0, 0);
312 htoun16(data.ptr + 2, data.len);
313 return eap_payload_create_data(data);
314 }
315
316 /*
317 * Described in header
318 */
319 eap_payload_t *eap_payload_create_nak(u_int8_t identifier)
320 {
321 chunk_t data;
322
323 data = chunk_from_chars(EAP_RESPONSE, identifier, 0, 0, EAP_NAK);
324 htoun16(data.ptr + 2, data.len);
325 return eap_payload_create_data(data);
326 }
327