Added IKEv1 support to 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;
215 }
216 return 12;
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->spis = chunk_cat("mc", this->spis, chunk_from_thing(spi));
259 break;
260 default:
261 break;
262 }
263 }
264
265 /**
266 * SPI enumerator implementation
267 */
268 typedef struct {
269 /** implements enumerator_t */
270 enumerator_t public;
271 /** remaining SPIs */
272 chunk_t spis;
273 } spi_enumerator_t;
274
275 METHOD(enumerator_t, spis_enumerate, bool,
276 spi_enumerator_t *this, u_int32_t *spi)
277 {
278 if (this->spis.len >= sizeof(*spi))
279 {
280 memcpy(spi, this->spis.ptr, sizeof(*spi));
281 this->spis = chunk_skip(this->spis, sizeof(*spi));
282 return TRUE;
283 }
284 return FALSE;
285 }
286
287 METHOD(delete_payload_t, create_spi_enumerator, enumerator_t*,
288 private_delete_payload_t *this)
289 {
290 spi_enumerator_t *e;
291
292 if (this->spi_size != sizeof(u_int32_t))
293 {
294 return enumerator_create_empty();
295 }
296 INIT(e,
297 .public = {
298 .enumerate = (void*)_spis_enumerate,
299 .destroy = (void*)free,
300 },
301 .spis = this->spis,
302 );
303 return &e->public;
304 }
305
306 METHOD2(payload_t, delete_payload_t, destroy, void,
307 private_delete_payload_t *this)
308 {
309 free(this->spis.ptr);
310 free(this);
311 }
312
313 /*
314 * Described in header
315 */
316 delete_payload_t *delete_payload_create(payload_type_t type,
317 protocol_id_t protocol_id)
318 {
319 private_delete_payload_t *this;
320
321 INIT(this,
322 .public = {
323 .payload_interface = {
324 .verify = _verify,
325 .get_encoding_rules = _get_encoding_rules,
326 .get_header_length = _get_header_length,
327 .get_length = _get_length,
328 .get_next_type = _get_next_type,
329 .set_next_type = _set_next_type,
330 .get_type = _get_payload_type,
331 .destroy = _destroy,
332 },
333 .get_protocol_id = _get_protocol_id,
334 .add_spi = _add_spi,
335 .create_spi_enumerator = _create_spi_enumerator,
336 .destroy = _destroy,
337 },
338 .next_payload = NO_PAYLOAD,
339 .payload_length = get_header_length(this),
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 return &this->public;
346 }