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