7cfe6ef7f2f4aef03a4d28209bee09ceaa1bbd79
[strongswan.git] / src / libimcv / ietf / ietf_attr_pa_tnc_error.c
1 /*
2 * Copyright (C) 2011-2018 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_SWIMA_SUBSCRIPTION_ID_REUSE,
25 "Reserved",
26 "Invalid Parameter",
27 "Version Not Supported",
28 "Attribute Type Not Supported"
29 "SWIMA Error",
30 "SWIMA Subscription Denied",
31 "SWIMA Response Too Large",
32 "SWIMA Subscription Fulfillment Error",
33 "SWIMA Subscription ID Reuse"
34 );
35
36 typedef struct private_ietf_attr_pa_tnc_error_t private_ietf_attr_pa_tnc_error_t;
37
38 /**
39 * PA-TNC Error Attribute Type (see section 4.2.8 of RFC 5792)
40 *
41 * 1 2 3
42 * 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
43 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 * | Reserved | PA-TNC Error Code Vendor ID |
45 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46 * | PA-TNC Error Code |
47 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48 * | Error Information (Variable Length) |
49 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50 */
51
52 #define PA_ERROR_HEADER_SIZE 8
53 #define PA_ERROR_RESERVED 0x00
54
55 /**
56 * All IETF Error Types return the first 8 bytes of the erroneous PA-TNC message
57 *
58 * 1 2 3
59 * 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
60 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
61 * | Version | Copy of Reserved |
62 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
63 * | Message Identifier |
64 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65 */
66
67 #define PA_ERROR_MSG_INFO_SIZE 8
68 #define PA_ERROR_MSG_INFO_MAX_SIZE 1024
69
70 /**
71 * "Invalid Parameter" Error Code
72 * 1 2 3
73 * 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
74 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
75 * | Offset |
76 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
77 */
78
79 /**
80 * "Version Not Supported" Error Code
81 *
82 * 1 2 3
83 * 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
84 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
85 * | Max Version | Min Version | Reserved |
86 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
87 */
88
89 #define PA_ERROR_VERSION_RESERVED 0x0000
90
91 /**
92 * "Attribute Type Not Supported" Error Code
93 *
94 * 1 2 3
95 * 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
96 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
97 * | Flags | PA-TNC Attribute Vendor ID |
98 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
99 * | PA-TNC Attribute Type |
100 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
101 */
102
103 #define PA_ERROR_ATTR_INFO_SIZE 8
104
105 /**
106 * Private data of an ietf_attr_pa_tnc_error_t object.
107 */
108 struct private_ietf_attr_pa_tnc_error_t {
109
110 /**
111 * Public members of ietf_attr_pa_tnc_error_t
112 */
113 ietf_attr_pa_tnc_error_t public;
114
115 /**
116 * Vendor-specific attribute type
117 */
118 pen_type_t type;
119
120 /**
121 * Length of attribute value
122 */
123 size_t length;
124
125 /**
126 * Attribute value or segment
127 */
128 chunk_t value;
129
130 /**
131 * Noskip flag
132 */
133 bool noskip_flag;
134
135 /**
136 * Vendor-specific error code
137 */
138 pen_type_t error_code;
139
140 /**
141 * First 8 bytes of erroneous PA-TNC message
142 */
143 chunk_t msg_info;
144
145 /**
146 * Flags of unsupported PA-TNC attribute
147 */
148 uint8_t flags;
149
150 /**
151 * Vendor ID and type of unsupported PA-TNC attribute
152 */
153 pen_type_t unsupported_type;
154
155 /**
156 * PA-TNC error offset
157 */
158 uint32_t error_offset;
159
160 /**
161 * Reference count
162 */
163 refcount_t ref;
164 };
165
166 METHOD(pa_tnc_attr_t, get_type, pen_type_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 if (this->value.ptr)
196 {
197 return;
198 }
199 writer = bio_writer_create(PA_ERROR_HEADER_SIZE + PA_ERROR_MSG_INFO_SIZE);
200 writer->write_uint8 (writer, PA_ERROR_RESERVED);
201 writer->write_uint24(writer, this->error_code.vendor_id);
202 writer->write_uint32(writer, this->error_code.type);
203 writer->write_data (writer, this->msg_info);
204
205 if (this->error_code.vendor_id == PEN_IETF)
206 {
207 switch (this->error_code.type)
208 {
209 case PA_ERROR_INVALID_PARAMETER:
210 writer->write_uint32(writer, this->error_offset);
211 break;
212 case PA_ERROR_VERSION_NOT_SUPPORTED:
213 writer->write_uint8 (writer, PA_TNC_VERSION);
214 writer->write_uint8 (writer, PA_TNC_VERSION);
215 writer->write_uint16(writer, PA_ERROR_VERSION_RESERVED);
216 break;
217 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
218 writer->write_uint8 (writer, this->flags);
219 writer->write_uint24(writer, this->unsupported_type.vendor_id);
220 writer->write_uint32(writer, this->unsupported_type.type);
221 break;
222 default:
223 break;
224 }
225 }
226 this->value = writer->extract_buf(writer);
227 this->length = this->value.len;
228 writer->destroy(writer);
229 }
230
231 METHOD(pa_tnc_attr_t, process, status_t,
232 private_ietf_attr_pa_tnc_error_t *this, uint32_t *offset)
233 {
234 bio_reader_t *reader;
235 uint8_t reserved;
236 uint32_t vendor_id, type;
237
238 *offset = 0;
239
240 if (this->value.len < this->length)
241 {
242 return NEED_MORE;
243 }
244 if (this->value.len < PA_ERROR_HEADER_SIZE)
245 {
246 DBG1(DBG_TNC, "insufficient data for PA-TNC error header");
247 return FAILED;
248 }
249 reader = bio_reader_create(this->value);
250 reader->read_uint8 (reader, &reserved);
251 reader->read_uint24(reader, &this->error_code.vendor_id);
252 reader->read_uint32(reader, &this->error_code.type);
253
254 if (this->error_code.vendor_id == PEN_IETF &&
255 this->error_code.type <= PA_ERROR_PA_TNC_MSG_ROOF)
256 {
257 if (!reader->read_data(reader, PA_ERROR_MSG_INFO_SIZE, &this->msg_info))
258 {
259 reader->destroy(reader);
260 DBG1(DBG_TNC, "insufficient data for IETF error information");
261 *offset = PA_ERROR_HEADER_SIZE;
262 return FAILED;
263 }
264 this->msg_info = chunk_clone(this->msg_info);
265
266 switch (this->error_code.type)
267 {
268 case PA_ERROR_INVALID_PARAMETER:
269 if (!reader->read_uint32(reader, &this->error_offset))
270 {
271 reader->destroy(reader);
272 DBG1(DBG_TNC, "insufficient data for error offset field");
273 *offset = PA_ERROR_HEADER_SIZE + PA_ERROR_MSG_INFO_SIZE;
274 return FAILED;
275 }
276 break;
277 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
278 if (reader->remaining(reader) < PA_ERROR_ATTR_INFO_SIZE)
279 {
280 reader->destroy(reader);
281 DBG1(DBG_TNC, "insufficient data for unsupported attribute "
282 "information");
283 *offset = PA_ERROR_HEADER_SIZE + PA_ERROR_MSG_INFO_SIZE;
284 return FAILED;
285 }
286 reader->read_uint8 (reader, &this->flags);
287 reader->read_uint24(reader, &vendor_id);
288 reader->read_uint32(reader, &type);
289 this->unsupported_type = pen_type_create(vendor_id, type);
290 break;
291 default:
292 break;
293 }
294 }
295 else
296 {
297 reader->read_data(reader, reader->remaining(reader), &this->msg_info);
298 this->msg_info = chunk_clone(this->msg_info);
299 }
300 reader->destroy(reader);
301
302 return SUCCESS;
303 }
304
305 METHOD(pa_tnc_attr_t, add_segment, void,
306 private_ietf_attr_pa_tnc_error_t *this, chunk_t segment)
307 {
308 this->value = chunk_cat("mc", this->value, segment);
309 }
310
311 METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
312 private_ietf_attr_pa_tnc_error_t *this)
313 {
314 ref_get(&this->ref);
315 return &this->public.pa_tnc_attribute;
316 }
317
318 METHOD(pa_tnc_attr_t, destroy, void,
319 private_ietf_attr_pa_tnc_error_t *this)
320 {
321 if (ref_put(&this->ref))
322 {
323 free(this->value.ptr);
324 free(this->msg_info.ptr);
325 free(this);
326 }
327 }
328
329 METHOD(ietf_attr_pa_tnc_error_t, get_error_code, pen_type_t,
330 private_ietf_attr_pa_tnc_error_t *this)
331 {
332 return this->error_code;
333 }
334
335 METHOD(ietf_attr_pa_tnc_error_t, get_msg_info, chunk_t,
336 private_ietf_attr_pa_tnc_error_t *this)
337 {
338 return this->msg_info;
339 }
340
341 METHOD(ietf_attr_pa_tnc_error_t, get_unsupported_attr, pen_type_t,
342 private_ietf_attr_pa_tnc_error_t *this, uint8_t *flags)
343 {
344 if (flags)
345 {
346 *flags = this->flags;
347 }
348 return this->unsupported_type;
349 }
350
351 METHOD(ietf_attr_pa_tnc_error_t, set_unsupported_attr, void,
352 private_ietf_attr_pa_tnc_error_t *this, uint8_t flags, pen_type_t type)
353 {
354 this->flags = flags;
355 this->unsupported_type = type;
356 }
357
358 METHOD(ietf_attr_pa_tnc_error_t, get_offset, uint32_t,
359 private_ietf_attr_pa_tnc_error_t *this)
360 {
361 return this->error_offset;
362 }
363
364 /**
365 * Generic constructor
366 */
367 static private_ietf_attr_pa_tnc_error_t* create_generic()
368 {
369 private_ietf_attr_pa_tnc_error_t *this;
370
371 INIT(this,
372 .public = {
373 .pa_tnc_attribute = {
374 .get_type = _get_type,
375 .get_value = _get_value,
376 .get_noskip_flag = _get_noskip_flag,
377 .set_noskip_flag = _set_noskip_flag,
378 .build = _build,
379 .process = _process,
380 .add_segment = _add_segment,
381 .get_ref = _get_ref,
382 .destroy = _destroy,
383 },
384 .get_error_code = _get_error_code,
385 .get_msg_info = _get_msg_info,
386 .get_unsupported_attr = _get_unsupported_attr,
387 .set_unsupported_attr = _set_unsupported_attr,
388 .get_offset = _get_offset,
389 },
390 .type = { PEN_IETF, IETF_ATTR_PA_TNC_ERROR },
391 .ref = 1,
392 );
393
394 return this;
395 }
396
397 /**
398 * Described in header.
399 */
400 pa_tnc_attr_t *ietf_attr_pa_tnc_error_create(pen_type_t error_code,
401 chunk_t msg_info)
402 {
403 private_ietf_attr_pa_tnc_error_t *this;
404
405 if (error_code.vendor_id == PEN_IETF &&
406 error_code.type <= PA_ERROR_PA_TNC_MSG_ROOF)
407 {
408 msg_info.len = PA_ERROR_MSG_INFO_SIZE;
409 }
410 else if (msg_info.len > PA_ERROR_MSG_INFO_MAX_SIZE)
411 {
412 msg_info.len = PA_ERROR_MSG_INFO_MAX_SIZE;
413 }
414
415 this = create_generic();
416 this->error_code = error_code;
417 this->msg_info = chunk_clone(msg_info);
418
419 return &this->public.pa_tnc_attribute;
420 }
421
422 /**
423 * Described in header.
424 */
425 pa_tnc_attr_t *ietf_attr_pa_tnc_error_create_with_offset(pen_type_t error_code,
426 chunk_t msg_info,
427 uint32_t error_offset)
428 {
429 private_ietf_attr_pa_tnc_error_t *this;
430
431 /* the first 8 bytes of the erroneous PA-TNC message are sent back */
432 msg_info.len = PA_ERROR_MSG_INFO_SIZE;
433
434 this = create_generic();
435 this->error_code = error_code;
436 this->msg_info = chunk_clone(msg_info);
437 this->error_offset = error_offset;
438
439 return &this->public.pa_tnc_attribute;
440 }
441
442 /**
443 * Described in header.
444 */
445 pa_tnc_attr_t *ietf_attr_pa_tnc_error_create_from_data(size_t length,
446 chunk_t data)
447 {
448 private_ietf_attr_pa_tnc_error_t *this;
449
450 this = create_generic();
451 this->length = length;
452 this->value = chunk_clone(data);
453
454 return &this->public.pa_tnc_attribute;
455 }