]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libcharon/tests/suites/test_child_delete.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / libcharon / tests / suites / test_child_delete.c
CommitLineData
33e2620b
TB
1/*
2 * Copyright (C) 2016 Tobias Brunner
19ef2aec
TB
3 *
4 * Copyright (C) secunet Security Networks AG
33e2620b
TB
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17#include "test_suite.h"
18
19#include <daemon.h>
20#include <tests/utils/exchange_test_helper.h>
21#include <tests/utils/exchange_test_asserts.h>
0a2cad40 22#include <tests/utils/job_asserts.h>
33e2620b
TB
23#include <tests/utils/sa_asserts.h>
24
25/**
26 * Regular CHILD_SA deletion either initiated by the original initiator or
27 * responder of the IKE_SA.
28 */
29START_TEST(test_regular)
30{
31 ike_sa_t *a, *b;
32
33 if (_i)
34 { /* responder deletes the CHILD_SA (SPI 2) */
35 exchange_test_helper->establish_sa(exchange_test_helper,
557e262f 36 &b, &a, NULL);
33e2620b
TB
37 }
38 else
39 { /* initiator deletes the CHILD_SA (SPI 1) */
40 exchange_test_helper->establish_sa(exchange_test_helper,
557e262f 41 &a, &b, NULL);
33e2620b
TB
42 }
43 assert_hook_not_called(child_updown);
5d97e5c3 44 call_ikesa(a, delete_child_sa, PROTO_ESP, _i+1, FALSE);
33e2620b
TB
45 assert_child_sa_state(a, _i+1, CHILD_DELETING);
46 assert_hook();
47
48 /* INFORMATIONAL { D } --> */
49 assert_hook_updown(child_updown, FALSE);
50 assert_single_payload(IN, PLV2_DELETE);
51 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
52 assert_child_sa_count(b, 0);
53 assert_hook();
54
55 /* <-- INFORMATIONAL { D } */
56 assert_hook_updown(child_updown, FALSE);
57 assert_single_payload(IN, PLV2_DELETE);
58 exchange_test_helper->process_message(exchange_test_helper, a, NULL);
59 assert_child_sa_count(a, 0);
60 assert_hook();
61
5d97e5c3
TB
62 call_ikesa(a, destroy);
63 call_ikesa(b, destroy);
33e2620b
TB
64}
65END_TEST
66
67/**
68 * Both peers initiate the CHILD_SA deletion concurrently and should handle
69 * the collision properly.
70 */
71START_TEST(test_collision)
72{
73 ike_sa_t *a, *b;
74
75 exchange_test_helper->establish_sa(exchange_test_helper,
557e262f 76 &a, &b, NULL);
33e2620b
TB
77 /* both peers delete the CHILD_SA concurrently */
78 assert_hook_not_called(child_updown);
5d97e5c3 79 call_ikesa(a, delete_child_sa, PROTO_ESP, 1, FALSE);
33e2620b 80 assert_child_sa_state(a, 1, CHILD_DELETING);
5d97e5c3 81 call_ikesa(b, delete_child_sa, PROTO_ESP, 2, FALSE);
33e2620b
TB
82 assert_child_sa_state(b, 2, CHILD_DELETING);
83 assert_hook();
84
85 /* RFC 7296 says:
86 *
87 * Normally, the response in the INFORMATIONAL exchange will contain
88 * Delete payloads for the paired SAs going in the other direction.
89 * There is one exception. If, by chance, both ends of a set of SAs
90 * independently decide to close them, each may send a Delete payload
91 * and the two requests may cross in the network. If a node receives a
92 * delete request for SAs for which it has already issued a delete
93 * request, it MUST delete the outgoing SAs while processing the request
94 * and the incoming SAs while processing the response. In that case,
95 * the responses MUST NOT include Delete payloads for the deleted SAs,
96 * since that would result in duplicate deletion and could in theory
97 * delete the wrong SA.
98 *
99 * We don't handle SAs separately so we expect both are still installed,
100 * but the INFORMATIONAL response should not contain a DELETE payload.
101 */
102
103 /* INFORMATIONAL { D } --> */
104 assert_hook_not_called(child_updown);
105 assert_single_payload(IN, PLV2_DELETE);
106 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
107 assert_child_sa_state(b, 2, CHILD_DELETING);
108 /* <-- INFORMATIONAL { D } */
109 assert_single_payload(IN, PLV2_DELETE);
110 exchange_test_helper->process_message(exchange_test_helper, a, NULL);
111 assert_child_sa_state(a, 1, CHILD_DELETING);
112 assert_hook();
113
114 /* <-- INFORMATIONAL { } */
115 assert_hook_updown(child_updown, FALSE);
116 assert_message_empty(IN);
117 exchange_test_helper->process_message(exchange_test_helper, a, NULL);
118 assert_child_sa_count(a, 0);
119 assert_hook();
120 /* INFORMATIONAL { } --> */
121 assert_hook_updown(child_updown, FALSE);
122 assert_message_empty(IN);
123 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
124 assert_child_sa_count(b, 0);
125 assert_hook();
126
5d97e5c3
TB
127 call_ikesa(a, destroy);
128 call_ikesa(b, destroy);
33e2620b
TB
129}
130END_TEST
131
32cfe1e0
TB
132/**
133 * This is like the collision above but one of the DELETEs is dropped or delayed
134 * so the other peer is not aware that there is a collision.
135 */
136START_TEST(test_collision_drop)
137{
138 ike_sa_t *a, *b;
139 message_t *msg;
140
141 exchange_test_helper->establish_sa(exchange_test_helper,
557e262f 142 &a, &b, NULL);
32cfe1e0
TB
143 /* both peers delete the CHILD_SA concurrently */
144 assert_hook_not_called(child_updown);
145 call_ikesa(a, delete_child_sa, PROTO_ESP, 1, FALSE);
146 assert_child_sa_state(a, 1, CHILD_DELETING);
147 call_ikesa(b, delete_child_sa, PROTO_ESP, 2, FALSE);
148 assert_child_sa_state(b, 2, CHILD_DELETING);
149 assert_hook();
150
151 /* INFORMATIONAL { D } --> */
152 assert_hook_not_called(child_updown);
153 assert_single_payload(IN, PLV2_DELETE);
154 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
155 assert_child_sa_state(b, 2, CHILD_DELETING);
156 assert_hook();
157
158 /* drop/delay the responder's message */
159 msg = exchange_test_helper->sender->dequeue(exchange_test_helper->sender);
160
161 /* <-- INFORMATIONAL { } */
162 assert_hook_updown(child_updown, FALSE);
163 assert_message_empty(IN);
164 exchange_test_helper->process_message(exchange_test_helper, a, NULL);
165 assert_child_sa_count(a, 0);
166 assert_hook();
167
168 /* <-- INFORMATIONAL { D } (delayed/retransmitted) */
169 assert_hook_not_called(child_updown);
170 assert_single_payload(IN, PLV2_DELETE);
171 exchange_test_helper->process_message(exchange_test_helper, a, msg);
172 assert_hook();
173
174 /* INFORMATIONAL { } --> */
175 assert_hook_updown(child_updown, FALSE);
176 assert_message_empty(IN);
177 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
178 assert_child_sa_count(b, 0);
179 assert_hook();
180
181 call_ikesa(a, destroy);
182 call_ikesa(b, destroy);
183}
184END_TEST
185
0a2cad40
TB
186/**
187 * One of the hosts initiates a rekey of the IKE_SA of the CHILD_SA the other
188 * peer is concurrently trying to delete.
189 *
190 * delete ----\ /---- rekey IKE
191 * \-----/----> detect collision
192 * detect collision <---------/ /---- delete
193 * TEMP_FAIL ----\ /
194 * \----/----->
195 * <--------/
196 */
197START_TEST(test_collision_ike_rekey)
198{
199 ike_sa_t *a, *b;
200 uint32_t spi_a = _i+1;
201
202 if (_i)
203 { /* responder deletes the CHILD_SA (SPI 2) */
204 exchange_test_helper->establish_sa(exchange_test_helper,
205 &b, &a, NULL);
206 }
207 else
208 { /* initiator deletes the CHILD_SA (SPI 1) */
209 exchange_test_helper->establish_sa(exchange_test_helper,
210 &a, &b, NULL);
211 }
212 call_ikesa(a, delete_child_sa, PROTO_ESP, spi_a, FALSE);
213 assert_child_sa_state(a, spi_a, CHILD_DELETING);
214 call_ikesa(b, rekey);
215 assert_ike_sa_state(b, IKE_REKEYING);
216
217 /* this should never get called as there is no successful rekeying */
218 assert_hook_not_called(ike_rekey);
219
220 /* RFC 7296, 2.25.2: If a peer receives a request to delete a Child SA when
221 * it is currently rekeying the IKE SA, it SHOULD reply as usual, with a
222 * Delete payload.
223 */
224
225 /* INFORMATIONAL { D } --> */
226 assert_hook_updown(child_updown, FALSE);
227 assert_single_payload(OUT, PLV2_DELETE);
228 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
229 assert_ike_sa_state(b, IKE_REKEYING);
230 assert_child_sa_count(b, 0);
231 assert_hook();
232
233 /* RFC 7296, 2.25.1: If a peer receives a request to rekey the IKE SA, and
234 * it is currently, rekeying, or closing a Child SA of that IKE SA, it
235 * SHOULD reply with TEMPORARY_FAILURE.
236 */
237
238 /* <-- CREATE_CHILD_SA { SA, Ni, KEi } */
239 assert_single_notify(OUT, TEMPORARY_FAILURE);
240 exchange_test_helper->process_message(exchange_test_helper, a, NULL);
241 assert_child_sa_state(a, spi_a, CHILD_DELETING);
242
243 /* <-- INFORMATIONAL { D } */
244 assert_hook_updown(child_updown, FALSE);
245 exchange_test_helper->process_message(exchange_test_helper, a, NULL);
246 assert_child_sa_count(a, 0);
247 assert_hook();
248
249 /* CREATE_CHILD_SA { N(TEMP_FAIL) } --> */
250 /* we expect a job to retry the rekeying is scheduled */
251 assert_jobs_scheduled(1);
252 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
253 assert_ike_sa_state(b, IKE_ESTABLISHED);
254 assert_scheduler();
255
256 /* ike_rekey */
257 assert_hook();
258
259 call_ikesa(a, destroy);
260 call_ikesa(b, destroy);
261}
262END_TEST
263
264/**
265 * One of the hosts initiates a delete of the IKE_SA of the CHILD_SA the other
266 * peer is concurrently trying to delete.
267 *
268 * delete ----\ /---- delete IKE
269 * \-----/----> detect collision
270 * <---------/ /---- delete
271 * delete ----\ /
272 * \----/----->
273 * sa already gone <--------/
274 */
275START_TEST(test_collision_ike_delete)
276{
277 ike_sa_t *a, *b;
278 uint32_t spi_a = _i+1;
279 message_t *msg;
280 status_t s;
281
282 if (_i)
283 { /* responder rekeys the CHILD_SA (SPI 2) */
284 exchange_test_helper->establish_sa(exchange_test_helper,
285 &b, &a, NULL);
286 }
287 else
288 { /* initiator rekeys the CHILD_SA (SPI 1) */
289 exchange_test_helper->establish_sa(exchange_test_helper,
290 &a, &b, NULL);
291 }
292 call_ikesa(a, delete_child_sa, PROTO_ESP, spi_a, FALSE);
293 assert_child_sa_state(a, spi_a, CHILD_DELETING);
a79d5103 294 call_ikesa(b, delete, FALSE);
0a2cad40
TB
295 assert_ike_sa_state(b, IKE_DELETING);
296
297 /* RFC 7296, 2.25.2 does not explicitly state what the behavior SHOULD be if
298 * a peer receives a request to delete a CHILD_SA when it is currently
299 * closing the IKE SA. We expect a regular response.
300 */
301
302 /* INFORMATIONAL { D } --> */
303 assert_hook_updown(child_updown, FALSE);
304 assert_single_payload(OUT, PLV2_DELETE);
305 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
306 assert_ike_sa_state(b, IKE_DELETING);
307 assert_child_sa_count(b, 0);
308 assert_hook();
309
310 /* RFC 7296, 2.25.1 does not explicitly state what the behavior SHOULD be if
311 * a peer receives a request to close the IKE SA if it is currently deleting
312 * a Child SA of that IKE SA. Let's just close the IKE_SA and forget the
313 * delete.
314 */
315
316 /* <-- INFORMATIONAL { D } */
317 assert_hook_updown(ike_updown, FALSE);
318 assert_hook_updown(child_updown, FALSE);
319 assert_message_empty(OUT);
320 s = exchange_test_helper->process_message(exchange_test_helper, a, NULL);
321 ck_assert_int_eq(DESTROY_ME, s);
322 call_ikesa(a, destroy);
323 assert_hook();
324 assert_hook();
325
326 /* <-- INFORMATIONAL { D } */
327 /* the SA is already gone */
328 msg = exchange_test_helper->sender->dequeue(exchange_test_helper->sender);
329 msg->destroy(msg);
330
331 /* INFORMATIONAL { } --> */
332 assert_hook_updown(ike_updown, FALSE);
333 assert_hook_not_called(child_updown);
334 s = exchange_test_helper->process_message(exchange_test_helper, b, NULL);
335 ck_assert_int_eq(DESTROY_ME, s);
336 call_ikesa(b, destroy);
337 assert_hook();
338 assert_hook();
339}
340END_TEST
341
33e2620b
TB
342Suite *child_delete_suite_create()
343{
344 Suite *s;
345 TCase *tc;
346
347 s = suite_create("child delete");
348
349 tc = tcase_create("regular");
350 tcase_add_loop_test(tc, test_regular, 0, 2);
351 suite_add_tcase(s, tc);
352
32cfe1e0 353 tc = tcase_create("collisions");
33e2620b 354 tcase_add_test(tc, test_collision);
32cfe1e0 355 tcase_add_test(tc, test_collision_drop);
33e2620b
TB
356 suite_add_tcase(s, tc);
357
0a2cad40
TB
358 tc = tcase_create("collisions ike rekey");
359 tcase_add_loop_test(tc, test_collision_ike_rekey, 0, 2);
360 suite_add_tcase(s, tc);
361
362 tc = tcase_create("collisions ike delete");
363 tcase_add_loop_test(tc, test_collision_ike_delete, 0, 2);
364 suite_add_tcase(s, tc);
365
33e2620b
TB
366 return s;
367}