support of error_offset in PA-TNC INVALID PARAMETER error messages
[strongswan.git] / src / libimcv / ietf / ietf_attr_pa_tnc_error.c
1 /*
2 * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 */
14
15 #include "ietf_attr_pa_tnc_error.h"
16
17 #include <pa_tnc/pa_tnc_msg.h>
18 #include <bio/bio_writer.h>
19 #include <bio/bio_reader.h>
20 #include <debug.h>
21
22 ENUM(pa_tnc_error_code_names, PA_ERROR_RESERVED,
23 PA_ERROR_ATTR_TYPE_NOT_SUPPORTED,
24 "Reserved",
25 "Invalid Parameter",
26 "Version Not Supported",
27 "Attribute Type Not Supported"
28 );
29
30 typedef struct private_ietf_attr_pa_tnc_error_t private_ietf_attr_pa_tnc_error_t;
31
32 /**
33 * PA-TNC Error Attribute Type (see section 4.2.8 of RFC 5792)
34 *
35 * 1 2 3
36 * 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
37 *
38 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39 * | Reserved | PA-TNC Error Code Vendor ID |
40 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41 * | PA-TNC Error Code |
42 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43 * | Error Information (Variable Length) |
44 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45 */
46
47 #define PA_ERROR_HEADER_SIZE 8
48 #define PA_ERROR_RESERVED 0x00
49
50 /**
51 * All Error Types return the first 8 bytes of the erroneous PA-TNC message
52 *
53 * 1 2 3
54 * 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
55 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56 * | Version | Copy of Reserved |
57 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58 * | Message Identifier |
59 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60 */
61
62 #define PA_ERROR_MSG_INFO_SIZE 8
63
64 /**
65 * "Invalid Parameter" Error Code
66 * 1 2 3
67 * 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
68 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69 * | Offset |
70 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
71 */
72
73 /**
74 * "Version Not Supported" Error Code
75 *
76 * 1 2 3
77 * 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
78 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
79 * | Max Version | Min Version | Reserved |
80 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
81 */
82
83 #define PA_ERROR_VERSION_RESERVED 0x0000
84
85 /**
86 * "Attribute Type Not Supported" Error Code
87 *
88 * 1 2 3
89 * 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
90 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
91 * | Flags | PA-TNC Attribute Vendor ID |
92 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
93 * | PA-TNC Attribute Type |
94 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
95 */
96
97 #define PA_ERROR_ATTR_INFO_SIZE 8
98
99 /**
100 * Private data of an ietf_attr_pa_tnc_error_t object.
101 */
102 struct private_ietf_attr_pa_tnc_error_t {
103
104 /**
105 * Public members of ietf_attr_pa_tnc_error_t
106 */
107 ietf_attr_pa_tnc_error_t public;
108
109 /**
110 * Attribute vendor ID
111 */
112 pen_t vendor_id;
113
114 /**
115 * Attribute type
116 */
117 u_int32_t type;
118
119 /**
120 * Attribute value
121 */
122 chunk_t value;
123
124 /**
125 * Noskip flag
126 */
127 bool noskip_flag;
128
129 /**
130 * Error code vendor ID
131 */
132 pen_t error_vendor_id;
133
134 /**
135 * Error code
136 */
137 u_int32_t error_code;
138
139 /**
140 * First 8 bytes of erroneous PA-TNC message
141 */
142 chunk_t msg_info;
143
144 /**
145 * First 8 bytes of unsupported PA-TNC attribute
146 */
147 chunk_t attr_info;
148
149 /**
150 * PA-TNC error offset
151 */
152 u_int32_t error_offset;
153
154 /**
155 * Reference count
156 */
157 refcount_t ref;
158 };
159
160 METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
161 private_ietf_attr_pa_tnc_error_t *this)
162 {
163 return this->vendor_id;
164 }
165
166 METHOD(pa_tnc_attr_t, get_type, u_int32_t,
167 private_ietf_attr_pa_tnc_error_t *this)
168 {
169 return this->type;
170 }
171
172 METHOD(pa_tnc_attr_t, get_value, chunk_t,
173 private_ietf_attr_pa_tnc_error_t *this)
174 {
175 return this->value;
176 }
177
178 METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
179 private_ietf_attr_pa_tnc_error_t *this)
180 {
181 return this->noskip_flag;
182 }
183
184 METHOD(pa_tnc_attr_t, set_noskip_flag,void,
185 private_ietf_attr_pa_tnc_error_t *this, bool noskip)
186 {
187 this->noskip_flag = noskip;
188 }
189
190 METHOD(pa_tnc_attr_t, build, void,
191 private_ietf_attr_pa_tnc_error_t *this)
192 {
193 bio_writer_t *writer;
194
195 writer = bio_writer_create(PA_ERROR_HEADER_SIZE + PA_ERROR_MSG_INFO_SIZE);
196 writer->write_uint8 (writer, PA_ERROR_RESERVED);
197 writer->write_uint24(writer, this->error_vendor_id);
198 writer->write_uint32(writer, this->error_code);
199 writer->write_data (writer, this->msg_info);
200
201 switch (this->error_code)
202 {
203 case PA_ERROR_INVALID_PARAMETER:
204 writer->write_uint32(writer, this->error_offset);
205 break;
206 case PA_ERROR_VERSION_NOT_SUPPORTED:
207 writer->write_uint8 (writer, PA_TNC_VERSION);
208 writer->write_uint8 (writer, PA_TNC_VERSION);
209 writer->write_uint16(writer, PA_ERROR_VERSION_RESERVED);
210 break;
211 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
212 writer->write_data(writer, this->attr_info);
213 break;
214 default:
215 break;
216 }
217
218 this->value = chunk_clone(writer->get_buf(writer));
219 writer->destroy(writer);
220 }
221
222 METHOD(pa_tnc_attr_t, process, status_t,
223 private_ietf_attr_pa_tnc_error_t *this, u_int32_t *offset)
224 {
225 bio_reader_t *reader;
226 u_int8_t reserved;
227
228 if (this->value.len < PA_ERROR_HEADER_SIZE + PA_ERROR_MSG_INFO_SIZE)
229 {
230 DBG1(DBG_TNC, "insufficient data for PA-TNC error header and "
231 "error information");
232 *offset = 0;
233 return FAILED;
234 }
235 reader = bio_reader_create(this->value);
236 reader->read_uint8 (reader, &reserved);
237 reader->read_uint24(reader, &this->error_vendor_id);
238 reader->read_uint32(reader, &this->error_code);
239 reader->read_data (reader, PA_ERROR_MSG_INFO_SIZE, &this->msg_info);
240 this->msg_info = chunk_clone(this->msg_info);
241
242 switch (this->error_code)
243 {
244 case PA_ERROR_INVALID_PARAMETER:
245 if (!reader->read_uint32(reader, &this->error_offset))
246 {
247 reader->destroy(reader);
248 DBG1(DBG_TNC, "insufficient data for error offset field");
249 *offset = PA_ERROR_HEADER_SIZE + PA_ERROR_MSG_INFO_SIZE;
250 return FAILED;
251 }
252 break;
253 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
254 if (!reader->read_data(reader, PA_ERROR_ATTR_INFO_SIZE,
255 &this->attr_info))
256 {
257 reader->destroy(reader);
258 DBG1(DBG_TNC, "insufficient data for unsupported attribute "
259 "information");
260 *offset = PA_ERROR_HEADER_SIZE + PA_ERROR_MSG_INFO_SIZE;
261 return FAILED;
262 }
263 this->attr_info = chunk_clone(this->attr_info);
264 break;
265 default:
266 break;
267 }
268 reader->destroy(reader);
269
270 return SUCCESS;
271 }
272
273 METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
274 private_ietf_attr_pa_tnc_error_t *this)
275 {
276 ref_get(&this->ref);
277 return &this->public.pa_tnc_attribute;
278 }
279
280 METHOD(pa_tnc_attr_t, destroy, void,
281 private_ietf_attr_pa_tnc_error_t *this)
282 {
283 if (ref_put(&this->ref))
284 {
285 free(this->value.ptr);
286 free(this->msg_info.ptr);
287 free(this->attr_info.ptr);
288 free(this);
289 }
290 }
291
292 METHOD(ietf_attr_pa_tnc_error_t, get_error_vendor_id, pen_t,
293 private_ietf_attr_pa_tnc_error_t *this)
294 {
295 return this->error_vendor_id;
296 }
297
298 METHOD(ietf_attr_pa_tnc_error_t, get_error_code, u_int32_t,
299 private_ietf_attr_pa_tnc_error_t *this)
300 {
301 return this->error_code;
302 }
303
304 METHOD(ietf_attr_pa_tnc_error_t, get_msg_info, chunk_t,
305 private_ietf_attr_pa_tnc_error_t *this)
306 {
307 return this->msg_info;
308 }
309
310 METHOD(ietf_attr_pa_tnc_error_t, get_attr_info, chunk_t,
311 private_ietf_attr_pa_tnc_error_t *this)
312 {
313 return this->attr_info;
314 }
315
316 METHOD(ietf_attr_pa_tnc_error_t, set_attr_info, void,
317 private_ietf_attr_pa_tnc_error_t *this, chunk_t attr_info)
318 {
319 this->attr_info = chunk_clone(attr_info);
320 }
321
322 METHOD(ietf_attr_pa_tnc_error_t, get_offset, u_int32_t,
323 private_ietf_attr_pa_tnc_error_t *this)
324 {
325 return this->error_offset;
326 }
327
328 /**
329 * Described in header.
330 */
331 pa_tnc_attr_t *ietf_attr_pa_tnc_error_create(pen_t vendor_id,
332 u_int32_t error_code,
333 chunk_t msg_info)
334 {
335 private_ietf_attr_pa_tnc_error_t *this;
336
337 /* the first 8 bytes of the erroneous PA-TNC message are sent back */
338 msg_info.len = PA_ERROR_MSG_INFO_SIZE;
339
340 INIT(this,
341 .public = {
342 .pa_tnc_attribute = {
343 .get_vendor_id = _get_vendor_id,
344 .get_type = _get_type,
345 .get_value = _get_value,
346 .get_noskip_flag = _get_noskip_flag,
347 .set_noskip_flag = _set_noskip_flag,
348 .build = _build,
349 .process = _process,
350 .get_ref = _get_ref,
351 .destroy = _destroy,
352 },
353 .get_vendor_id = _get_error_vendor_id,
354 .get_error_code = _get_error_code,
355 .get_msg_info = _get_msg_info,
356 .get_attr_info = _get_attr_info,
357 .set_attr_info = _set_attr_info,
358 .get_offset = _get_offset,
359 },
360 .vendor_id = PEN_IETF,
361 .type = IETF_ATTR_PA_TNC_ERROR,
362 .error_vendor_id = vendor_id,
363 .error_code = error_code,
364 .msg_info = chunk_clone(msg_info),
365 .ref = 1,
366 );
367
368 return &this->public.pa_tnc_attribute;
369 }
370
371 /**
372 * Described in header.
373 */
374 pa_tnc_attr_t *ietf_attr_pa_tnc_error_create_with_offset(pen_t vendor_id,
375 u_int32_t error_code,
376 chunk_t msg_info,
377 u_int32_t error_offset)
378 {
379 private_ietf_attr_pa_tnc_error_t *this;
380
381 /* the first 8 bytes of the erroneous PA-TNC message are sent back */
382 msg_info.len = PA_ERROR_MSG_INFO_SIZE;
383
384 INIT(this,
385 .public = {
386 .pa_tnc_attribute = {
387 .get_vendor_id = _get_vendor_id,
388 .get_type = _get_type,
389 .get_value = _get_value,
390 .get_noskip_flag = _get_noskip_flag,
391 .set_noskip_flag = _set_noskip_flag,
392 .build = _build,
393 .process = _process,
394 .get_ref = _get_ref,
395 .destroy = _destroy,
396 },
397 .get_vendor_id = _get_error_vendor_id,
398 .get_error_code = _get_error_code,
399 .get_msg_info = _get_msg_info,
400 .get_attr_info = _get_attr_info,
401 .set_attr_info = _set_attr_info,
402 .get_offset = _get_offset,
403 },
404 .vendor_id = PEN_IETF,
405 .type = IETF_ATTR_PA_TNC_ERROR,
406 .error_vendor_id = vendor_id,
407 .error_code = error_code,
408 .msg_info = chunk_clone(msg_info),
409 .error_offset = error_offset,
410 .ref = 1,
411 );
412
413 return &this->public.pa_tnc_attribute;
414 }
415
416 /**
417 * Described in header.
418 */
419 pa_tnc_attr_t *ietf_attr_pa_tnc_error_create_from_data(chunk_t data)
420 {
421 private_ietf_attr_pa_tnc_error_t *this;
422
423 INIT(this,
424 .public = {
425 .pa_tnc_attribute = {
426 .get_vendor_id = _get_vendor_id,
427 .get_type = _get_type,
428 .get_value = _get_value,
429 .build = _build,
430 .process = _process,
431 .get_ref = _get_ref,
432 .destroy = _destroy,
433 },
434 .get_vendor_id = _get_error_vendor_id,
435 .get_error_code = _get_error_code,
436 .get_msg_info = _get_msg_info,
437 .get_attr_info = _get_attr_info,
438 .set_attr_info = _set_attr_info,
439 .get_offset = _get_offset,
440 },
441 .vendor_id = PEN_IETF,
442 .type = IETF_ATTR_PA_TNC_ERROR,
443 .value = chunk_clone(data),
444 .ref = 1,
445 );
446
447 return &this->public.pa_tnc_attribute;
448 }
449
450