4fd48075665cba15f64d579aab586c54b2919220
[strongswan.git] / src / libcharon / tests / suites / test_child_rekey.c
1 /*
2 * Copyright (C) 2016 Tobias Brunner
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 "test_suite.h"
17
18 #include <daemon.h>
19 #include <tests/utils/exchange_test_helper.h>
20 #include <tests/utils/exchange_test_asserts.h>
21 #include <tests/utils/job_asserts.h>
22 #include <tests/utils/sa_asserts.h>
23
24 /**
25 * Initiate rekeying the CHILD_SA with the given SPI on the given IKE_SA.
26 */
27 #define initiate_rekey(sa, spi) ({ \
28 assert_hook_not_called(child_updown); \
29 assert_hook_not_called(child_rekey); \
30 call_ikesa(sa, rekey_child_sa, PROTO_ESP, spi); \
31 assert_child_sa_state(sa, spi, CHILD_REKEYING); \
32 assert_hook(); \
33 assert_hook(); \
34 })
35
36 /**
37 * Regular CHILD_SA rekey either initiated by the original initiator or
38 * responder of the IKE_SA.
39 */
40 START_TEST(test_regular)
41 {
42 ike_sa_t *a, *b;
43 uint32_t spi_a = _i+1, spi_b = 2-_i;
44
45 if (_i)
46 { /* responder rekeys the CHILD_SA (SPI 2) */
47 exchange_test_helper->establish_sa(exchange_test_helper,
48 &b, &a);
49 }
50 else
51 { /* initiator rekeys the CHILD_SA (SPI 1) */
52 exchange_test_helper->establish_sa(exchange_test_helper,
53 &a, &b);
54 }
55 initiate_rekey(a, spi_a);
56
57 /* this should never get called as this results in a successful rekeying */
58 assert_hook_not_called(child_updown);
59
60 /* CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } --> */
61 assert_hook_called(child_rekey);
62 assert_notify(IN, REKEY_SA);
63 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
64 assert_child_sa_state(b, spi_b, CHILD_REKEYED);
65 assert_child_sa_state(b, 4, CHILD_INSTALLED);
66 assert_hook();
67
68 /* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */
69 assert_hook_called(child_rekey);
70 assert_no_notify(IN, REKEY_SA);
71 exchange_test_helper->process_message(exchange_test_helper, a, NULL);
72 assert_child_sa_state(a, spi_a, CHILD_DELETING);
73 assert_child_sa_state(a, 3, CHILD_INSTALLED);
74 assert_hook();
75
76 /* INFORMATIONAL { D } --> */
77 assert_hook_not_called(child_rekey);
78 assert_single_payload(IN, PLV2_DELETE);
79 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
80 assert_child_sa_state(b, 4, CHILD_INSTALLED);
81 assert_child_sa_count(b, 1);
82 assert_hook();
83 /* <-- INFORMATIONAL { D } */
84 assert_hook_not_called(child_rekey);
85 assert_single_payload(IN, PLV2_DELETE);
86 exchange_test_helper->process_message(exchange_test_helper, a, NULL);
87 assert_child_sa_state(a, 3, CHILD_INSTALLED);
88 assert_child_sa_count(a, 1);
89 assert_hook();
90
91 /* child_updown */
92 assert_hook();
93
94 call_ikesa(a, destroy);
95 call_ikesa(b, destroy);
96 }
97 END_TEST
98
99 /**
100 * Both peers initiate the CHILD_SA reekying concurrently and should handle
101 * the collision properly depending on the nonces.
102 */
103 START_TEST(test_collision)
104 {
105 ike_sa_t *a, *b;
106
107 exchange_test_helper->establish_sa(exchange_test_helper,
108 &a, &b);
109
110 /* When rekeyings collide we get two CHILD_SAs with a total of four nonces.
111 * The CHILD_SA with the lowest nonce SHOULD be deleted by the peer that
112 * created that CHILD_SA. The replaced CHILD_SA is deleted by the peer that
113 * initiated the surviving SA.
114 * Four nonces and SPIs are needed (SPI 1 and 2 are used for the initial
115 * CHILD_SA):
116 * N1/3 -----\ /----- N2/4
117 * \--/-----> N3/5
118 * N4/6 <-------/ /----- ...
119 * ... -----\
120 * We test this four times, each time a different nonce is the lowest.
121 */
122 struct {
123 /* Nonces used at each point */
124 u_char nonces[4];
125 /* SPIs of the deleted CHILD_SA (either redundant or replaced) */
126 uint32_t spi_del_a, spi_del_b;
127 /* SPIs of the kept CHILD_SA */
128 uint32_t spi_a, spi_b;
129 } data[] = {
130 { { 0x00, 0xFF, 0xFF, 0xFF }, 3, 2, 6, 4 },
131 { { 0xFF, 0x00, 0xFF, 0xFF }, 1, 4, 3, 5 },
132 { { 0xFF, 0xFF, 0x00, 0xFF }, 3, 2, 6, 4 },
133 { { 0xFF, 0xFF, 0xFF, 0x00 }, 1, 4, 3, 5 },
134 };
135
136 exchange_test_helper->nonce_first_byte = data[_i].nonces[0];
137 initiate_rekey(a, 1);
138 exchange_test_helper->nonce_first_byte = data[_i].nonces[1];
139 initiate_rekey(b, 2);
140
141 /* this should never get called as this results in a successful rekeying */
142 assert_hook_not_called(child_updown);
143
144 /* CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } --> */
145 exchange_test_helper->nonce_first_byte = data[_i].nonces[2];
146 assert_hook_rekey(child_rekey, 2, 5);
147 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
148 assert_child_sa_state(b, 2, CHILD_REKEYED);
149 assert_child_sa_state(b, 5, CHILD_INSTALLED);
150 assert_hook();
151 /* <-- CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } */
152 exchange_test_helper->nonce_first_byte = data[_i].nonces[3];
153 assert_hook_rekey(child_rekey, 1, 6);
154 exchange_test_helper->process_message(exchange_test_helper, a, NULL);
155 assert_child_sa_state(a, 1, CHILD_REKEYED);
156 assert_child_sa_state(a, 6, CHILD_INSTALLED);
157 assert_hook();
158
159 /* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */
160 if (data[_i].spi_del_a == 1)
161 { /* currently we call this again if we keep our own replacement as we
162 * already called it above */
163 assert_hook_rekey(child_rekey, 1, data[_i].spi_a);
164 exchange_test_helper->process_message(exchange_test_helper, a, NULL);
165 assert_hook();
166 }
167 else
168 {
169 exchange_test_helper->process_message(exchange_test_helper, a, NULL);
170 }
171 assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING);
172 assert_child_sa_state(a, data[_i].spi_del_b, CHILD_REKEYED);
173 assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED);
174 /* CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } --> */
175 if (data[_i].spi_del_b == 2)
176 {
177 assert_hook_rekey(child_rekey, 2, data[_i].spi_b);
178 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
179 assert_hook();
180 }
181 else
182 {
183 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
184 }
185 assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING);
186 assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED);
187 assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED);
188
189 /* we don't expect this hook to get called anymore */
190 assert_hook_not_called(child_rekey);
191 /* INFORMATIONAL { D } --> */
192 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
193 assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING);
194 assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED);
195 assert_child_sa_count(b, 2);
196 /* <-- INFORMATIONAL { D } */
197 exchange_test_helper->process_message(exchange_test_helper, a, NULL);
198 assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING);
199 assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED);
200 assert_child_sa_count(a, 2);
201 /* <-- INFORMATIONAL { D } */
202 exchange_test_helper->process_message(exchange_test_helper, a, NULL);
203 assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED);
204 assert_child_sa_count(a, 1);
205 /* INFORMATIONAL { D } --> */
206 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
207 assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED);
208 assert_child_sa_count(b, 1);
209
210 /* child_rekey/child_updown */
211 assert_hook();
212 assert_hook();
213
214 call_ikesa(a, destroy);
215 call_ikesa(b, destroy);
216 }
217 END_TEST
218
219 /**
220 * One of the hosts initiates a DELETE of the CHILD_SA the other peer is
221 * concurrently trying to rekey.
222 *
223 * rekey ----\ /---- delete
224 * \-----/----> detect collision
225 * detect collision <---------/ /---- TEMP_FAIL
226 * delete ----\ /
227 * \----/----->
228 * aborts rekeying <--------/
229 */
230 START_TEST(test_collision_delete)
231 {
232 ike_sa_t *a, *b;
233 uint32_t spi_a = _i+1, spi_b = 2-_i;
234
235 if (_i)
236 { /* responder rekeys the CHILD_SA (SPI 2) */
237 exchange_test_helper->establish_sa(exchange_test_helper,
238 &b, &a);
239 }
240 else
241 { /* initiator rekeys the CHILD_SA (SPI 1) */
242 exchange_test_helper->establish_sa(exchange_test_helper,
243 &a, &b);
244 }
245 initiate_rekey(a, spi_a);
246 call_ikesa(b, delete_child_sa, PROTO_ESP, spi_b, FALSE);
247 assert_child_sa_state(b, spi_b, CHILD_DELETING);
248
249 /* this should never get called as there is no successful rekeying on
250 * either side */
251 assert_hook_not_called(child_rekey);
252
253 /* RFC 7296, 2.25.1: If a peer receives a request to rekey a CHILD_SA that
254 * it is currently trying to close, it SHOULD reply with TEMPORARY_FAILURE.
255 */
256
257 /* CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } --> */
258 assert_hook_not_called(child_updown);
259 assert_notify(IN, REKEY_SA);
260 assert_single_notify(OUT, TEMPORARY_FAILURE);
261 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
262 assert_child_sa_state(b, spi_b, CHILD_DELETING);
263 assert_hook();
264
265 /* RFC 7296, 2.25.1: If a peer receives a request to delete a CHILD_SA that
266 * it is currently trying to rekey, it SHOULD reply as usual, with a DELETE
267 * payload.
268 */
269
270 /* <-- INFORMATIONAL { D } */
271 assert_hook_updown(child_updown, FALSE);
272 assert_single_payload(IN, PLV2_DELETE);
273 assert_single_payload(OUT, PLV2_DELETE);
274 exchange_test_helper->process_message(exchange_test_helper, a, NULL);
275 assert_child_sa_count(a, 0);
276 assert_hook();
277
278 /* <-- CREATE_CHILD_SA { N(TEMP_FAIL) } */
279 assert_hook_not_called(child_updown);
280 /* we don't expect a job to retry the rekeying */
281 assert_no_jobs_scheduled();
282 exchange_test_helper->process_message(exchange_test_helper, a, NULL);
283 assert_scheduler();
284 assert_hook();
285
286 /* INFORMATIONAL { D } --> */
287 assert_hook_updown(child_updown, FALSE);
288 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
289 assert_child_sa_count(b, 0);
290 assert_hook();
291
292 /* child_rekey */
293 assert_hook();
294
295 assert_sa_idle(a);
296 assert_sa_idle(b);
297
298 call_ikesa(a, destroy);
299 call_ikesa(b, destroy);
300 }
301 END_TEST
302
303 /**
304 * One of the hosts initiates a DELETE of the CHILD_SA the other peer is
305 * concurrently trying to rekey. However, the delete request is delayed or
306 * dropped, so the peer doing the rekeying is unaware of the collision.
307 *
308 * rekey ----\ /---- delete
309 * \-----/----> detect collision
310 * reschedule <---------/------ TEMP_FAIL
311 * <--------/
312 * delete ---------------->
313 *
314 * The job will not find the SA to retry rekeying.
315 */
316 START_TEST(test_collision_delete_drop_delete)
317 {
318 ike_sa_t *a, *b;
319 message_t *msg;
320 uint32_t spi_a = _i+1, spi_b = 2-_i;
321
322 if (_i)
323 { /* responder rekeys the CHILD_SA (SPI 2) */
324 exchange_test_helper->establish_sa(exchange_test_helper,
325 &b, &a);
326 }
327 else
328 { /* initiator rekeys the CHILD_SA (SPI 1) */
329 exchange_test_helper->establish_sa(exchange_test_helper,
330 &a, &b);
331 }
332 initiate_rekey(a, spi_a);
333 call_ikesa(b, delete_child_sa, PROTO_ESP, spi_b, FALSE);
334 assert_child_sa_state(b, spi_b, CHILD_DELETING);
335
336 /* this should never get called as there is no successful rekeying on
337 * either side */
338 assert_hook_not_called(child_rekey);
339
340 /* RFC 7296, 2.25.1: If a peer receives a request to rekey a CHILD_SA that
341 * it is currently trying to close, it SHOULD reply with TEMPORARY_FAILURE.
342 */
343
344 /* CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } --> */
345 assert_hook_not_called(child_updown);
346 assert_notify(IN, REKEY_SA);
347 assert_single_notify(OUT, TEMPORARY_FAILURE);
348 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
349 assert_child_sa_state(b, spi_b, CHILD_DELETING);
350 assert_hook();
351
352 /* delay the DELETE request */
353 msg = exchange_test_helper->sender->dequeue(exchange_test_helper->sender);
354
355 /* <-- CREATE_CHILD_SA { N(TEMP_FAIL) } */
356 assert_hook_not_called(child_updown);
357 /* we expect a job to retry the rekeying is scheduled */
358 assert_jobs_scheduled(1);
359 exchange_test_helper->process_message(exchange_test_helper, a, NULL);
360 assert_child_sa_state(a, spi_a, CHILD_INSTALLED);
361 assert_scheduler();
362 assert_hook();
363
364 /* <-- INFORMATIONAL { D } (delayed) */
365 assert_hook_updown(child_updown, FALSE);
366 assert_single_payload(IN, PLV2_DELETE);
367 assert_single_payload(OUT, PLV2_DELETE);
368 exchange_test_helper->process_message(exchange_test_helper, a, msg);
369 assert_child_sa_count(a, 0);
370 assert_hook();
371
372 /* INFORMATIONAL { D } --> */
373 assert_hook_updown(child_updown, FALSE);
374 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
375 assert_child_sa_count(b, 0);
376 assert_hook();
377
378 /* child_rekey */
379 assert_hook();
380
381 assert_sa_idle(a);
382 assert_sa_idle(b);
383
384 call_ikesa(a, destroy);
385 call_ikesa(b, destroy);
386 }
387 END_TEST
388
389 /**
390 * One of the hosts initiates a DELETE of the CHILD_SA the other peer is
391 * concurrently trying to rekey. However, the rekey request is delayed or
392 * dropped, so the peer doing the deleting is unaware of the collision.
393 *
394 * rekey ----\ /---- delete
395 * detect collision <----\-----/
396 * delete ------\--------->
397 * \-------->
398 * /---- CHILD_SA_NOT_FOUND
399 * aborts rekeying <----------/
400 */
401 START_TEST(test_collision_delete_drop_rekey)
402 {
403 ike_sa_t *a, *b;
404 message_t *msg;
405 uint32_t spi_a = _i+1, spi_b = 2-_i;
406
407 if (_i)
408 { /* responder rekeys the CHILD_SA (SPI 2) */
409 exchange_test_helper->establish_sa(exchange_test_helper,
410 &b, &a);
411 }
412 else
413 { /* initiator rekeys the CHILD_SA (SPI 1) */
414 exchange_test_helper->establish_sa(exchange_test_helper,
415 &a, &b);
416 }
417 initiate_rekey(a, spi_a);
418 call_ikesa(b, delete_child_sa, PROTO_ESP, spi_b, FALSE);
419 assert_child_sa_state(b, spi_b, CHILD_DELETING);
420
421 /* this should never get called as there is no successful rekeying on
422 * either side */
423 assert_hook_not_called(child_rekey);
424
425 /* delay the CREAE_CHILD_SA request */
426 msg = exchange_test_helper->sender->dequeue(exchange_test_helper->sender);
427
428 /* RFC 7296, 2.25.1: If a peer receives a request to delete a CHILD_SA that
429 * it is currently trying to rekey, it SHOULD reply as usual, with a DELETE
430 * payload.
431 */
432
433 /* <-- INFORMATIONAL { D } */
434 assert_hook_updown(child_updown, FALSE);
435 assert_single_payload(IN, PLV2_DELETE);
436 assert_single_payload(OUT, PLV2_DELETE);
437 exchange_test_helper->process_message(exchange_test_helper, a, NULL);
438 assert_child_sa_count(a, 0);
439 assert_hook();
440
441 /* INFORMATIONAL { D } --> */
442 assert_hook_updown(child_updown, FALSE);
443 exchange_test_helper->process_message(exchange_test_helper, b, NULL);
444 assert_child_sa_count(b, 0);
445 assert_hook();
446
447 /* RFC 7296, 2.25.1: If a peer receives a to rekey a Child SA that does not
448 * exist, it SHOULD reply with CHILD_SA_NOT_FOUND.
449 */
450
451 /* CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } --> (delayed) */
452 assert_hook_not_called(child_updown);
453 assert_notify(IN, REKEY_SA);
454 assert_single_notify(OUT, CHILD_SA_NOT_FOUND);
455 exchange_test_helper->process_message(exchange_test_helper, b, msg);
456 assert_hook();
457
458 /* <-- CREATE_CHILD_SA { N(NO_CHILD_SA) } */
459 assert_hook_not_called(child_updown);
460 /* no jobs or tasks should get scheduled/queued */
461 assert_no_jobs_scheduled();
462 exchange_test_helper->process_message(exchange_test_helper, a, NULL);
463 assert_scheduler();
464 assert_hook();
465
466 /* child_rekey */
467 assert_hook();
468
469 assert_sa_idle(a);
470 assert_sa_idle(b);
471
472 call_ikesa(a, destroy);
473 call_ikesa(b, destroy);
474 }
475 END_TEST
476
477 /**
478 * FIXME: Not sure what we can do about the following:
479 *
480 * One of the hosts initiates a rekeying of a CHILD_SA and after responding to
481 * it the other peer deletes the new SA. However, the rekey response is
482 * delayed or dropped, so the peer doing the rekeying receives a delete for an
483 * unknown CHILD_SA and then has a rekeyed CHILD_SA that should not exist.
484 *
485 * rekey ---------------->
486 * /---- rekey
487 * unknown SA <----------/----- delete new SA
488 * ----------/----->
489 * <--------/
490 *
491 * The peers' states are now out of sync.
492 *
493 * Perhaps the rekey initiator could keep track of deletes for non-existing SAs
494 * while rekeying and then check against the SPIs when handling the
495 * CREATE_CHILD_SA response.
496 */
497
498
499 Suite *child_rekey_suite_create()
500 {
501 Suite *s;
502 TCase *tc;
503
504 s = suite_create("child rekey");
505
506 tc = tcase_create("regular");
507 tcase_add_loop_test(tc, test_regular, 0, 2);
508 suite_add_tcase(s, tc);
509
510 tc = tcase_create("collisions rekey");
511 tcase_add_loop_test(tc, test_collision, 0, 4);
512 suite_add_tcase(s, tc);
513
514 tc = tcase_create("collisions delete");
515 tcase_add_loop_test(tc, test_collision_delete, 0, 2);
516 tcase_add_loop_test(tc, test_collision_delete_drop_delete, 0, 2);
517 tcase_add_loop_test(tc, test_collision_delete_drop_rekey, 0, 2);
518 suite_add_tcase(s, tc);
519
520 return s;
521 }