Implemented limited payload parsing for IKEv1 SA payloads
[strongswan.git] / src / libcharon / encoding / payloads / transform_substructure.c
1 /*
2 * Copyright (C) 2005-2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include <stddef.h>
19
20 #include "transform_substructure.h"
21
22 #include <encoding/payloads/transform_attribute.h>
23 #include <encoding/payloads/encodings.h>
24 #include <library.h>
25 #include <utils/linked_list.h>
26 #include <daemon.h>
27
28 typedef struct private_transform_substructure_t private_transform_substructure_t;
29
30 /**
31 * Private data of an transform_substructure_t object.
32 */
33 struct private_transform_substructure_t {
34
35 /**
36 * Public transform_substructure_t interface.
37 */
38 transform_substructure_t public;
39
40 /**
41 * Next payload type.
42 */
43 u_int8_t next_payload;
44
45 /**
46 * Reserved byte
47 */
48 u_int8_t reserved[3];
49
50 /**
51 * Length of this payload.
52 */
53 u_int16_t transform_length;
54
55 /**
56 * Type or number, Type of the transform in IKEv2, number in IKEv2.
57 */
58 u_int8_t transform_ton;
59
60 /**
61 * Transform ID, as encoded in IKEv1.
62 */
63 u_int8_t transform_id_v1;
64
65 /**
66 * Transform ID, as encoded in IKEv2.
67 */
68 u_int16_t transform_id_v2;
69
70 /**
71 * Transforms Attributes are stored in a linked_list_t.
72 */
73 linked_list_t *attributes;
74
75 /**
76 * Payload type, TRANSFORM_SUBSTRUCTURE or TRANSFORM_SUBSTRUCTURE_V1
77 */
78 payload_type_t type;
79 };
80
81 /**
82 * Encoding rules for TRANSFORM_SUBSTRUCTURE
83 */
84 static encoding_rule_t encodings_v2[] = {
85 /* 1 Byte next payload type, stored in the field next_payload */
86 { U_INT_8, offsetof(private_transform_substructure_t, next_payload) },
87 /* 1 Reserved Byte */
88 { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[0]) },
89 /* Length of the whole transform substructure*/
90 { PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length)},
91 /* transform type */
92 { U_INT_8, offsetof(private_transform_substructure_t, transform_ton) },
93 /* transform identifier, as used by IKEv1 */
94 { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[1]) },
95 /* transform identifier, as used by IKEv2 */
96 { U_INT_16, offsetof(private_transform_substructure_t, transform_id_v2) },
97 /* Attributes in a transform attribute list */
98 { TRANSFORM_ATTRIBUTES, offsetof(private_transform_substructure_t, attributes) }
99 };
100
101 /**
102 * Encoding rules for TRANSFORM_SUBSTRUCTURE_V1
103 */
104 static encoding_rule_t encodings_v1[] = {
105 /* 1 Byte next payload type, stored in the field next_payload */
106 { U_INT_8, offsetof(private_transform_substructure_t, next_payload) },
107 /* 1 Reserved Byte */
108 { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[0]) },
109 /* Length of the whole transform substructure*/
110 { PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length)},
111 /* transform number */
112 { U_INT_8, offsetof(private_transform_substructure_t, transform_ton)},
113 /* transform identifier, as used by IKEv1 */
114 { U_INT_8, offsetof(private_transform_substructure_t, transform_id_v1) },
115 /* transform identifier, as used by IKEv2 */
116 { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[1]) },
117 { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[2]) },
118 /* Attributes in a transform attribute list */
119 { TRANSFORM_ATTRIBUTES_V1, offsetof(private_transform_substructure_t, attributes) }
120 };
121
122 /*
123 1 2 3
124 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
125 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
126 ! 0 (last) or 3 ! RESERVED ! Transform Length !
127 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
128 ! Tfrm Typ or # ! Tfrm ID IKEv1 ! Transform ID IKEv2 !
129 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
130 ! !
131 ~ Transform Attributes ~
132 ! !
133 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
134 */
135
136 METHOD(payload_t, verify, status_t,
137 private_transform_substructure_t *this)
138 {
139 status_t status = SUCCESS;
140 enumerator_t *enumerator;
141 payload_t *attribute;
142
143 if (this->next_payload != NO_PAYLOAD && this->next_payload != 3)
144 {
145 DBG1(DBG_ENC, "inconsistent next payload");
146 return FAILED;
147 }
148
149 enumerator = this->attributes->create_enumerator(this->attributes);
150 while (enumerator->enumerate(enumerator, &attribute))
151 {
152 status = attribute->verify(attribute);
153 if (status != SUCCESS)
154 {
155 DBG1(DBG_ENC, "TRANSFORM_ATTRIBUTE verification failed");
156 break;
157 }
158 }
159 enumerator->destroy(enumerator);
160
161 /* proposal number is checked in SA payload */
162 return status;
163 }
164
165 METHOD(payload_t, get_encoding_rules, void,
166 private_transform_substructure_t *this, encoding_rule_t **rules,
167 size_t *rule_count)
168 {
169 if (this->type == TRANSFORM_ATTRIBUTE)
170 {
171 *rules = encodings_v2;
172 *rule_count = countof(encodings_v2);
173 }
174 else
175 {
176 *rules = encodings_v1;
177 *rule_count = countof(encodings_v1);
178 }
179 }
180
181 METHOD(payload_t, get_type, payload_type_t,
182 private_transform_substructure_t *this)
183 {
184 return this->type;
185 }
186
187 METHOD(payload_t, get_next_type, payload_type_t,
188 private_transform_substructure_t *this)
189 {
190 return this->next_payload;
191 }
192
193 /**
194 * recompute the length of the payload.
195 */
196 static void compute_length(private_transform_substructure_t *this)
197 {
198 enumerator_t *enumerator;
199 payload_t *attribute;
200
201 this->transform_length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH;
202 enumerator = this->attributes->create_enumerator(this->attributes);
203 while (enumerator->enumerate(enumerator, &attribute))
204 {
205 this->transform_length += attribute->get_length(attribute);
206 }
207 enumerator->destroy(enumerator);
208 }
209
210 METHOD(payload_t, get_length, size_t,
211 private_transform_substructure_t *this)
212 {
213 return this->transform_length;
214 }
215
216 METHOD(transform_substructure_t, set_is_last_transform, void,
217 private_transform_substructure_t *this, bool is_last)
218 {
219 this->next_payload = is_last ? 0: TRANSFORM_TYPE_VALUE;
220 }
221
222 METHOD(payload_t, set_next_type, void,
223 private_transform_substructure_t *this,payload_type_t type)
224 {
225 }
226
227 METHOD(transform_substructure_t, get_transform_type_or_number, u_int8_t,
228 private_transform_substructure_t *this)
229 {
230 return this->transform_ton;
231 }
232
233 METHOD(transform_substructure_t, get_transform_id, u_int16_t,
234 private_transform_substructure_t *this)
235 {
236 if (this->type == TRANSFORM_SUBSTRUCTURE)
237 {
238 return this->transform_id_v2;
239 }
240 return this->transform_id_v1;
241 }
242
243 METHOD(transform_substructure_t, create_attribute_enumerator, enumerator_t*,
244 private_transform_substructure_t *this)
245 {
246 return this->attributes->create_enumerator(this->attributes);
247 }
248
249 METHOD2(payload_t, transform_substructure_t, destroy, void,
250 private_transform_substructure_t *this)
251 {
252 this->attributes->destroy_offset(this->attributes,
253 offsetof(payload_t, destroy));
254 free(this);
255 }
256
257 /*
258 * Described in header.
259 */
260 transform_substructure_t *transform_substructure_create(payload_type_t type)
261 {
262 private_transform_substructure_t *this;
263
264 INIT(this,
265 .public = {
266 .payload_interface = {
267 .verify = _verify,
268 .get_encoding_rules = _get_encoding_rules,
269 .get_length = _get_length,
270 .get_next_type = _get_next_type,
271 .set_next_type = _set_next_type,
272 .get_type = _get_type,
273 .destroy = _destroy,
274 },
275 .set_is_last_transform = _set_is_last_transform,
276 .get_transform_type_or_number = _get_transform_type_or_number,
277 .get_transform_id = _get_transform_id,
278 .create_attribute_enumerator = _create_attribute_enumerator,
279 .destroy = _destroy,
280 },
281 .next_payload = NO_PAYLOAD,
282 .transform_length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH,
283 .attributes = linked_list_create(),
284 .type = type,
285 );
286 return &this->public;
287 }
288
289 /*
290 * Described in header
291 */
292 transform_substructure_t *transform_substructure_create_type(payload_type_t type,
293 u_int8_t type_or_number, u_int16_t id, u_int16_t key_length)
294 {
295 private_transform_substructure_t *this;
296
297 this = (private_transform_substructure_t*)transform_substructure_create(type);
298
299 this->transform_ton = type_or_number;
300 if (type == TRANSFORM_SUBSTRUCTURE)
301 {
302 this->transform_id_v2 = id;
303 }
304 else
305 {
306 this->transform_id_v1 = id;
307 }
308 if (key_length)
309 {
310 this->attributes->insert_last(this->attributes,
311 (void*)transform_attribute_create_key_length(key_length));
312 compute_length(this);
313 }
314 return &this->public;
315 }
316