Fixed length calculation of delete payload
[strongswan.git] / src / libcharon / encoding / payloads / delete_payload.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 "delete_payload.h"
21
22
23 typedef struct private_delete_payload_t private_delete_payload_t;
24
25 /**
26 * Private data of an delete_payload_t object.
27 */
28 struct private_delete_payload_t {
29
30 /**
31 * Public delete_payload_t interface.
32 */
33 delete_payload_t public;
34
35 /**
36 * Next payload type.
37 */
38 u_int8_t next_payload;
39
40 /**
41 * Critical flag.
42 */
43 bool critical;
44
45 /**
46 * reserved bits
47 */
48 bool reserved[8];
49
50 /**
51 * Length of this payload.
52 */
53 u_int16_t payload_length;
54
55 /**
56 * IKEv1 Domain of Interpretation
57 */
58 u_int32_t doi;
59
60 /**
61 * Protocol ID.
62 */
63 u_int8_t protocol_id;
64
65 /**
66 * SPI Size.
67 */
68 u_int8_t spi_size;
69
70 /**
71 * Number of SPI's.
72 */
73 u_int16_t spi_count;
74
75 /**
76 * The contained SPI's.
77 */
78 chunk_t spis;
79
80 /**
81 * Payload type, DELETE or DELETE_V1
82 */
83 payload_type_t type;
84 };
85
86 /**
87 * Encoding rules for an IKEv2 delete payload.
88 */
89 static encoding_rule_t encodings_v2[] = {
90 /* 1 Byte next payload type, stored in the field next_payload */
91 { U_INT_8, offsetof(private_delete_payload_t, next_payload) },
92 /* the critical bit */
93 { FLAG, offsetof(private_delete_payload_t, critical) },
94 /* 7 Bit reserved bits */
95 { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[0]) },
96 { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[1]) },
97 { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[2]) },
98 { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[3]) },
99 { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[4]) },
100 { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[5]) },
101 { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[6]) },
102 /* Length of the whole payload*/
103 { PAYLOAD_LENGTH, offsetof(private_delete_payload_t, payload_length) },
104 { U_INT_8, offsetof(private_delete_payload_t, protocol_id) },
105 { U_INT_8, offsetof(private_delete_payload_t, spi_size) },
106 { U_INT_16, offsetof(private_delete_payload_t, spi_count) },
107 /* some delete data bytes, length is defined in PAYLOAD_LENGTH */
108 { CHUNK_DATA, offsetof(private_delete_payload_t, spis) },
109 };
110
111 /*
112 1 2 3
113 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
114 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
115 ! Next Payload !C! RESERVED ! Payload Length !
116 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
117 ! Protocol ID ! SPI Size ! # of SPIs !
118 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
119 ! !
120 ~ Security Parameter Index(es) (SPI) ~
121 ! !
122 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
123 */
124
125 /**
126 * Encoding rules for an IKEv1 delete payload.
127 */
128 static encoding_rule_t encodings_v1[] = {
129 /* 1 Byte next payload type, stored in the field next_payload */
130 { U_INT_8, offsetof(private_delete_payload_t, next_payload) },
131 /* 8 Bit reserved bits */
132 { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[0]) },
133 { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[1]) },
134 { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[2]) },
135 { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[3]) },
136 { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[4]) },
137 { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[5]) },
138 { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[6]) },
139 { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[7]) },
140 /* Length of the whole payload*/
141 { PAYLOAD_LENGTH, offsetof(private_delete_payload_t, payload_length) },
142 /* Domain of interpretation */
143 { U_INT_32, offsetof(private_delete_payload_t, doi) },
144 { U_INT_8, offsetof(private_delete_payload_t, protocol_id) },
145 { U_INT_8, offsetof(private_delete_payload_t, spi_size) },
146 { U_INT_16, offsetof(private_delete_payload_t, spi_count) },
147 /* some delete data bytes, length is defined in PAYLOAD_LENGTH */
148 { CHUNK_DATA, offsetof(private_delete_payload_t, spis) },
149 };
150
151 /*
152 1 2 3
153 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
154 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
155 ! Next Payload !C! RESERVED ! Payload Length !
156 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
157 ! DOI !
158 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
159 ! Protocol ID ! SPI Size ! # of SPIs !
160 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
161 ! !
162 ~ Security Parameter Index(es) (SPI) ~
163 ! !
164 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
165 */
166
167 METHOD(payload_t, verify, status_t,
168 private_delete_payload_t *this)
169 {
170 switch (this->protocol_id)
171 {
172 case PROTO_AH:
173 case PROTO_ESP:
174 if (this->spi_size != 4)
175 {
176 return FAILED;
177 }
178 break;
179 case PROTO_IKE:
180 case 0:
181 /* IKE deletion has no spi assigned! */
182 if (this->spi_size != 0)
183 {
184 return FAILED;
185 }
186 break;
187 default:
188 return FAILED;
189 }
190 if (this->spis.len != (this->spi_count * this->spi_size))
191 {
192 return FAILED;
193 }
194 return SUCCESS;
195 }
196
197 METHOD(payload_t, get_encoding_rules, int,
198 private_delete_payload_t *this, encoding_rule_t **rules)
199 {
200 if (this->type == DELETE)
201 {
202 *rules = encodings_v2;
203 return countof(encodings_v2);
204 }
205 *rules = encodings_v1;
206 return countof(encodings_v1);
207 }
208
209 METHOD(payload_t, get_header_length, int,
210 private_delete_payload_t *this)
211 {
212 if (this->type == DELETE)
213 {
214 return 8 + this->spi_size;
215 }
216 return 12 + this->spi_size;
217 }
218
219 METHOD(payload_t, get_payload_type, payload_type_t,
220 private_delete_payload_t *this)
221 {
222 return this->type;
223 }
224
225 METHOD(payload_t, get_next_type, payload_type_t,
226 private_delete_payload_t *this)
227 {
228 return this->next_payload;
229 }
230
231 METHOD(payload_t, set_next_type, void,
232 private_delete_payload_t *this,payload_type_t type)
233 {
234 this->next_payload = type;
235 }
236
237 METHOD(payload_t, get_length, size_t,
238 private_delete_payload_t *this)
239 {
240 return this->payload_length;
241 }
242
243 METHOD(delete_payload_t, get_protocol_id, protocol_id_t,
244 private_delete_payload_t *this)
245 {
246 return this->protocol_id;
247 }
248
249 METHOD(delete_payload_t, add_spi, void,
250 private_delete_payload_t *this, u_int32_t spi)
251 {
252 switch (this->protocol_id)
253 {
254 case PROTO_AH:
255 case PROTO_ESP:
256 this->spi_count++;
257 this->payload_length += sizeof(spi);
258 this->spi_size += sizeof(spi);
259 this->spis = chunk_cat("mc", this->spis, chunk_from_thing(spi));
260 break;
261 default:
262 break;
263 }
264 }
265
266 /**
267 * SPI enumerator implementation
268 */
269 typedef struct {
270 /** implements enumerator_t */
271 enumerator_t public;
272 /** remaining SPIs */
273 chunk_t spis;
274 } spi_enumerator_t;
275
276 METHOD(enumerator_t, spis_enumerate, bool,
277 spi_enumerator_t *this, u_int32_t *spi)
278 {
279 if (this->spis.len >= sizeof(*spi))
280 {
281 memcpy(spi, this->spis.ptr, sizeof(*spi));
282 this->spis = chunk_skip(this->spis, sizeof(*spi));
283 return TRUE;
284 }
285 return FALSE;
286 }
287
288 METHOD(delete_payload_t, create_spi_enumerator, enumerator_t*,
289 private_delete_payload_t *this)
290 {
291 spi_enumerator_t *e;
292
293 if (this->spi_size != sizeof(u_int32_t))
294 {
295 return enumerator_create_empty();
296 }
297 INIT(e,
298 .public = {
299 .enumerate = (void*)_spis_enumerate,
300 .destroy = (void*)free,
301 },
302 .spis = this->spis,
303 );
304 return &e->public;
305 }
306
307 METHOD2(payload_t, delete_payload_t, destroy, void,
308 private_delete_payload_t *this)
309 {
310 free(this->spis.ptr);
311 free(this);
312 }
313
314 /*
315 * Described in header
316 */
317 delete_payload_t *delete_payload_create(payload_type_t type,
318 protocol_id_t protocol_id)
319 {
320 private_delete_payload_t *this;
321
322 INIT(this,
323 .public = {
324 .payload_interface = {
325 .verify = _verify,
326 .get_encoding_rules = _get_encoding_rules,
327 .get_header_length = _get_header_length,
328 .get_length = _get_length,
329 .get_next_type = _get_next_type,
330 .set_next_type = _set_next_type,
331 .get_type = _get_payload_type,
332 .destroy = _destroy,
333 },
334 .get_protocol_id = _get_protocol_id,
335 .add_spi = _add_spi,
336 .create_spi_enumerator = _create_spi_enumerator,
337 .destroy = _destroy,
338 },
339 .next_payload = NO_PAYLOAD,
340 .doi = IKEV1_DOI_IPSEC,
341 .protocol_id = protocol_id,
342 .spi_size = protocol_id == PROTO_AH || protocol_id == PROTO_ESP ? 4 : 0,
343 .type = type,
344 );
345 this->payload_length = get_header_length(this);
346
347 return &this->public;
348 }