Annotation of embedaddon/strongswan/src/libimcv/pa_tnc/pa_tnc_msg.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2011-2015 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 "imcv.h"
17: #include "pa_tnc_msg.h"
18: #include "ietf/ietf_attr_pa_tnc_error.h"
19:
20: #include <bio/bio_writer.h>
21: #include <bio/bio_reader.h>
22: #include <collections/linked_list.h>
23: #include <pen/pen.h>
24: #include <utils/debug.h>
25:
26: typedef struct private_pa_tnc_msg_t private_pa_tnc_msg_t;
27:
28: /**
29: * PA-TNC message header
30: *
31: * 1 2 3
32: * 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
33: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34: * | Version | Reserved |
35: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36: * | Message Identifier |
37: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38: */
39:
40: #define PA_TNC_RESERVED 0x000000
41:
42: /**
43: * Private data of a pa_tnc_msg_t object.
44: *
45: */
46: struct private_pa_tnc_msg_t {
47:
48: /**
49: * Public pa_tnc_msg_t interface.
50: */
51: pa_tnc_msg_t public;
52:
53: /**
54: * List of PA-TNC attributes
55: */
56: linked_list_t *attributes;
57:
58: /**
59: * linked list of PA-TNC error messages
60: */
61: linked_list_t *errors;
62:
63: /**
64: * Message identifier
65: */
66: uint32_t identifier;
67:
68: /**
69: * Current PA-TNC Message size
70: */
71: size_t msg_len;
72:
73: /**
74: * Maximum PA-TNC Message size
75: */
76: size_t max_msg_len;
77:
78: /**
79: * TRUE if attribute was extracted from data
80: */
81: bool from_data;
82:
83: /**
84: * Encoded message
85: */
86: chunk_t encoding;
87: };
88:
89: METHOD(pa_tnc_msg_t, get_encoding, chunk_t,
90: private_pa_tnc_msg_t *this)
91: {
92: return this->encoding;
93: }
94:
95: METHOD(pa_tnc_msg_t, get_space, size_t,
96: private_pa_tnc_msg_t *this)
97: {
98: return this->max_msg_len ? this->max_msg_len - this->msg_len : 0;
99: }
100:
101: METHOD(pa_tnc_msg_t, add_attribute, bool,
102: private_pa_tnc_msg_t *this, pa_tnc_attr_t *attr)
103: {
104: chunk_t attr_value;
105: size_t attr_len;
106:
107: if (!this->from_data)
108: {
109: attr->build(attr);
110: attr_value = attr->get_value(attr);
111: attr_len = PA_TNC_ATTR_HEADER_SIZE + attr_value.len;
112:
113: if (this->max_msg_len && this->msg_len + attr_len > this->max_msg_len)
114: {
115: /* attribute just does not fit into this message */
116: return FALSE;
117: }
118: this->msg_len += attr_len;
119: }
120: this->attributes->insert_last(this->attributes, attr);
121: return TRUE;
122: }
123:
124: METHOD(pa_tnc_msg_t, build, bool,
125: private_pa_tnc_msg_t *this)
126: {
127: bio_writer_t *writer;
128: enumerator_t *enumerator;
129: pa_tnc_attr_t *attr;
130: enum_name_t *pa_attr_names;
131: pen_type_t type;
132: uint8_t flags;
133: chunk_t value;
134: nonce_gen_t *ng;
135:
136: /* generate a nonce as a message identifier */
137: ng = lib->crypto->create_nonce_gen(lib->crypto);
138: if (!ng || !ng->get_nonce(ng, 4, (uint8_t*)&this->identifier))
139: {
140: DBG1(DBG_TNC, "failed to generate random PA-TNC message identifier");
141: DESTROY_IF(ng);
142: return FALSE;
143: }
144: ng->destroy(ng);
145: DBG1(DBG_TNC, "creating PA-TNC message with ID 0x%08x", this->identifier);
146:
147: /* build message header */
148: writer = bio_writer_create(this->msg_len);
149: writer->write_uint8 (writer, PA_TNC_VERSION);
150: writer->write_uint24(writer, PA_TNC_RESERVED);
151: writer->write_uint32(writer, this->identifier);
152:
153: /* append encoded value of PA-TNC attributes */
154: enumerator = this->attributes->create_enumerator(this->attributes);
155: while (enumerator->enumerate(enumerator, &attr))
156: {
157: type = attr->get_type(attr);
158: value = attr->get_value(attr);
159: flags = attr->get_noskip_flag(attr) ? PA_TNC_ATTR_FLAG_NOSKIP :
160: PA_TNC_ATTR_FLAG_NONE;
161:
162: pa_attr_names = imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes,
163: type.vendor_id);
164: if (pa_attr_names)
165: {
166: DBG2(DBG_TNC, "creating PA-TNC attribute type '%N/%N' "
167: "0x%06x/0x%08x", pen_names, type.vendor_id,
168: pa_attr_names, type.type, type.vendor_id, type.type);
169: }
170: else
171: {
172: DBG2(DBG_TNC, "creating PA-TNC attribute type '%N' "
173: "0x%06x/0x%08x", pen_names, type.vendor_id,
174: type.vendor_id, type.type);
175: }
176: DBG3(DBG_TNC, "%B", &value);
177:
178: writer->write_uint8 (writer, flags);
179: writer->write_uint24(writer, type.vendor_id);
180: writer->write_uint32(writer, type.type);
181: writer->write_uint32(writer, PA_TNC_ATTR_HEADER_SIZE + value.len);
182: writer->write_data (writer, value);
183: }
184: enumerator->destroy(enumerator);
185:
186: free(this->encoding.ptr);
187: this->encoding = writer->extract_buf(writer);
188: writer->destroy(writer);
189:
190: return TRUE;
191: }
192:
193: METHOD(pa_tnc_msg_t, process, status_t,
194: private_pa_tnc_msg_t *this)
195: {
196: bio_reader_t *reader;
197: pa_tnc_attr_t *attr, *error;
198: pen_type_t attr_type;
199: chunk_t attr_value;
200: uint8_t version;
201: uint32_t reserved, offset, attr_offset;
202: pen_type_t error_code = { PEN_IETF, PA_ERROR_INVALID_PARAMETER };
203:
204: /* process message header */
205: if (this->encoding.len < PA_TNC_HEADER_SIZE)
206: {
207: DBG1(DBG_TNC, "%u bytes insufficient to parse PA-TNC message header",
208: this->encoding.len);
209: return FAILED;
210: }
211: reader = bio_reader_create(this->encoding);
212: reader->read_uint8 (reader, &version);
213: reader->read_uint24(reader, &reserved);
214: reader->read_uint32(reader, &this->identifier);
215: DBG1(DBG_TNC, "processing PA-TNC message with ID 0x%08x", this->identifier);
216:
217: if (version != PA_TNC_VERSION)
218: {
219: DBG1(DBG_TNC, "PA-TNC version %u not supported", version);
220: error_code = pen_type_create(PEN_IETF, PA_ERROR_VERSION_NOT_SUPPORTED);
221: error = ietf_attr_pa_tnc_error_create(error_code, this->encoding);
222: goto err;
223: }
224:
225: /* offset of the first PA-TNC attribute in the PA-TNC message */
226: offset = PA_TNC_HEADER_SIZE;
227:
228: /* pre-process PA-TNC attributes */
229: while (reader->remaining(reader) > 0)
230: {
231: attr = imcv_pa_tnc_attributes->create(imcv_pa_tnc_attributes,
232: reader, FALSE, &offset, this->encoding, &error);
233: if (!attr)
234: {
235: if (error)
236: {
237: goto err;
238: }
239: else
240: {
241: continue;
242: }
243: }
244: attr_value = attr->get_value(attr);
245: attr_type = attr->get_type(attr);
246:
247: if (attr->process(attr, &attr_offset) != SUCCESS)
248: {
249: attr->destroy(attr);
250:
251: if (attr_type.vendor_id == PEN_IETF &&
252: attr_type.type == IETF_ATTR_PA_TNC_ERROR)
253: {
254: /* suppress error while processing a PA-TNC error attribute */
255: offset += attr_value.len;
256: continue;
257: }
258: error_code = pen_type_create(PEN_IETF, PA_ERROR_INVALID_PARAMETER);
259: error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
260: this->encoding, offset + attr_offset);
261: goto err;
262: }
263: offset += attr_value.len;
264: this->attributes->insert_last(this->attributes, attr);
265: }
266: reader->destroy(reader);
267: return SUCCESS;
268:
269: err:
270: reader->destroy(reader);
271: this->errors->insert_last(this->errors, error);
272: return VERIFY_ERROR;
273: }
274:
275: METHOD(pa_tnc_msg_t, process_ietf_std_errors, bool,
276: private_pa_tnc_msg_t *this, linked_list_t *non_fatal_types)
277: {
278: enumerator_t *e1, *e2;
279: enum_name_t *pa_attr_names;
280: pa_tnc_attr_t *attr;
281: pen_type_t type, unsupported_type;
282: uint8_t flags;
283: bool fatal_error = FALSE;
284:
285: e1 = this->attributes->create_enumerator(this->attributes);
286: while (e1->enumerate(e1, &attr))
287: {
288: type = attr->get_type(attr);
289:
290: if (type.vendor_id == PEN_IETF && type.type == IETF_ATTR_PA_TNC_ERROR)
291: {
292: ietf_attr_pa_tnc_error_t *error_attr;
293: pen_type_t error_code, *non_fatal_type;
294: chunk_t msg_info;
295: uint32_t offset;
296: bool fatal_current_error = TRUE;
297:
298: error_attr = (ietf_attr_pa_tnc_error_t*)attr;
299: error_code = error_attr->get_error_code(error_attr);
300: msg_info = error_attr->get_msg_info(error_attr);
301:
302: /* skip errors from non-IETF namespaces and non PA-TNC msg errors */
303: if (error_code.vendor_id != PEN_IETF ||
304: error_code.type > PA_ERROR_PA_TNC_MSG_ROOF)
305: {
306: continue;
307: }
308: DBG1(DBG_TNC, "received PA-TNC error '%N' concerning message "
309: "0x%08x/0x%08x", pa_tnc_error_code_names, error_code.type,
310: untoh32(msg_info.ptr), untoh32(msg_info.ptr + 4));
311:
312: switch (error_code.type)
313: {
314: case PA_ERROR_INVALID_PARAMETER:
315: offset = error_attr->get_offset(error_attr);
316: DBG1(DBG_TNC, " occurred at offset of %u bytes", offset);
317: break;
318: case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
319: unsupported_type =
320: error_attr->get_unsupported_attr(error_attr, &flags);
321: pa_attr_names =
322: imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes,
323: unsupported_type.vendor_id);
324: if (pa_attr_names)
325: {
326: DBG1(DBG_TNC, " unsupported attribute type '%N/%N' "
327: "0x%06x/0x%08x, flags 0x%02x",
328: pen_names, unsupported_type.vendor_id,
329: pa_attr_names, unsupported_type.type,
330: unsupported_type.vendor_id, unsupported_type.type,
331: flags);
332: }
333: else
334: {
335: DBG1(DBG_TNC, " unsupported attribute type '%N' "
336: "0x%06x/0x%08x, flags 0x%02x",
337: pen_names, unsupported_type.vendor_id,
338: unsupported_type.vendor_id, unsupported_type.type,
339: flags);
340: }
341: e2 = non_fatal_types->create_enumerator(non_fatal_types);
342: while (e2->enumerate(e2, &non_fatal_type))
343: {
344: if (pen_type_equals(unsupported_type, *non_fatal_type))
345: {
346: fatal_current_error = FALSE;
347: break;
348: }
349: }
350: e2->destroy(e2);
351: break;
352: default:
353: break;
354: }
355: if (fatal_current_error)
356: {
357: fatal_error = TRUE;
358: }
359: }
360: }
361: e1->destroy(e1);
362:
363: return fatal_error;
364: }
365:
366: METHOD(pa_tnc_msg_t, create_attribute_enumerator, enumerator_t*,
367: private_pa_tnc_msg_t *this)
368: {
369: return this->attributes->create_enumerator(this->attributes);
370: }
371:
372: METHOD(pa_tnc_msg_t, create_error_enumerator, enumerator_t*,
373: private_pa_tnc_msg_t *this)
374: {
375: return this->errors->create_enumerator(this->errors);
376: }
377:
378: METHOD(pa_tnc_msg_t, destroy, void,
379: private_pa_tnc_msg_t *this)
380: {
381: this->attributes->destroy_offset(this->attributes,
382: offsetof(pa_tnc_attr_t, destroy));
383: this->errors->destroy_offset(this->errors,
384: offsetof(pa_tnc_attr_t, destroy));
385: free(this->encoding.ptr);
386: free(this);
387: }
388:
389: /**
390: * See header
391: */
392: pa_tnc_msg_t *pa_tnc_msg_create(size_t max_msg_len)
393: {
394: private_pa_tnc_msg_t *this;
395:
396: INIT(this,
397: .public = {
398: .get_encoding = _get_encoding,
399: .get_space = _get_space,
400: .add_attribute = _add_attribute,
401: .build = _build,
402: .process = _process,
403: .process_ietf_std_errors = _process_ietf_std_errors,
404: .create_attribute_enumerator = _create_attribute_enumerator,
405: .create_error_enumerator = _create_error_enumerator,
406: .destroy = _destroy,
407: },
408: .attributes = linked_list_create(),
409: .errors = linked_list_create(),
410: .msg_len = PA_TNC_HEADER_SIZE,
411: .max_msg_len = max_msg_len,
412: );
413:
414: return &this->public;
415: }
416:
417: /**
418: * See header
419: */
420: pa_tnc_msg_t *pa_tnc_msg_create_from_data(chunk_t data)
421: {
422: private_pa_tnc_msg_t *this;
423:
424: INIT(this,
425: .public = {
426: .get_encoding = _get_encoding,
427: .get_space = _get_space,
428: .add_attribute = _add_attribute,
429: .build = _build,
430: .process = _process,
431: .process_ietf_std_errors = _process_ietf_std_errors,
432: .create_attribute_enumerator = _create_attribute_enumerator,
433: .create_error_enumerator = _create_error_enumerator,
434: .destroy = _destroy,
435: },
436: .encoding = chunk_clone(data),
437: .attributes = linked_list_create(),
438: .errors = linked_list_create(),
439: .from_data = TRUE,
440: );
441:
442: return &this->public;
443: }
444:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>