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