]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libcharon/tests/utils/exchange_test_helper.c
unit-tests: Make childless initiation configurable
[thirdparty/strongswan.git] / src / libcharon / tests / utils / exchange_test_helper.c
CommitLineData
c7f5259c 1/*
35e49ffd 2 * Copyright (C) 2016-2018 Tobias Brunner
c7f5259c
TB
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 "exchange_test_helper.h"
7e542486 17#include "mock_dh.h"
dda5aab0 18#include "mock_ipsec.h"
35e49ffd 19#include "mock_net.h"
dda5aab0 20#include "mock_nonce_gen.h"
c7f5259c 21
5d10ef31 22#include <collections/array.h>
c7f5259c
TB
23#include <credentials/sets/mem_cred.h>
24
25typedef struct private_exchange_test_helper_t private_exchange_test_helper_t;
557e262f 26typedef struct private_backend_t private_backend_t;
c7f5259c
TB
27
28/**
29 * Private data
30 */
31struct private_exchange_test_helper_t {
32
33 /**
34 * Public interface
35 */
36 exchange_test_helper_t public;
37
c7f5259c
TB
38 /**
39 * Credentials
40 */
41 mem_cred_t *creds;
29f1637b
TB
42
43 /**
44 * IKE_SA SPI counter
45 */
46 refcount_t ike_spi;
5d10ef31
TB
47
48 /**
49 * List of registered listeners
50 */
51 array_t *listeners;
e0678a8c
TB
52
53 /**
54 * Config backend
55 */
56 private_backend_t *backend;
c7f5259c
TB
57};
58
557e262f
TB
59/**
60 * Custom backend_t implementation
61 */
62struct private_backend_t {
63
64 /**
65 * Public interface
66 */
67 backend_t public;
68
69 /**
70 * Responder ike_cfg
71 */
72 ike_cfg_t *ike_cfg;
73
74 /**
75 * Responder peer_cfg/child_cfg
76 */
77 peer_cfg_t *peer_cfg;
78};
79
29f1637b
TB
80CALLBACK(get_ike_spi, uint64_t,
81 private_exchange_test_helper_t *this)
82{
83 return (uint64_t)ref_get(&this->ike_spi);
84}
85
c7f5259c
TB
86/*
87 * Described in header
88 */
89exchange_test_helper_t *exchange_test_helper;
90
557e262f 91static ike_cfg_t *create_ike_cfg(bool initiator, exchange_test_sa_conf_t *conf)
c7f5259c 92{
9486a2e5
TB
93 ike_cfg_create_t ike = {
94 .version = IKEV2,
95 .local = "127.0.0.1",
96 .local_port = IKEV2_UDP_PORT,
97 .remote = "127.0.0.1",
98 .remote_port = IKEV2_UDP_PORT,
99 };
c7f5259c 100 ike_cfg_t *ike_cfg;
557e262f 101 char *proposal = NULL;
c7f5259c 102
557e262f
TB
103 if (conf)
104 {
1b19469c
TB
105 ike.childless = initiator ? conf->initiator.childless
106 : conf->responder.childless;
557e262f
TB
107 proposal = initiator ? conf->initiator.ike : conf->responder.ike;
108 }
1b19469c
TB
109
110 ike_cfg = ike_cfg_create(&ike);
557e262f
TB
111 if (proposal)
112 {
113 ike_cfg->add_proposal(ike_cfg,
114 proposal_create_from_string(PROTO_IKE, proposal));
115 }
116 else
117 {
118 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
119 }
c7f5259c
TB
120 return ike_cfg;
121}
122
557e262f
TB
123static child_cfg_t *create_child_cfg(bool initiator,
124 exchange_test_sa_conf_t *conf)
c7f5259c
TB
125{
126 child_cfg_t *child_cfg;
127 child_cfg_create_t child = {
128 .mode = MODE_TUNNEL,
129 };
557e262f 130 char *proposal = NULL;
c7f5259c
TB
131
132 child_cfg = child_cfg_create(initiator ? "init" : "resp", &child);
557e262f
TB
133 if (conf)
134 {
135 proposal = initiator ? conf->initiator.esp : conf->responder.esp;
136 }
137 if (proposal)
138 {
139 child_cfg->add_proposal(child_cfg,
140 proposal_create_from_string(PROTO_ESP, proposal));
141 }
142 else
143 {
144 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
145 }
c7f5259c
TB
146 child_cfg->add_traffic_selector(child_cfg, TRUE,
147 traffic_selector_create_dynamic(0, 0, 65535));
148 child_cfg->add_traffic_selector(child_cfg, FALSE,
149 traffic_selector_create_dynamic(0, 0, 65535));
150 return child_cfg;
151}
152
153static void add_auth_cfg(peer_cfg_t *peer_cfg, bool initiator, bool local)
154{
155 auth_cfg_t *auth;
156 char *id = "init";
157
158 auth = auth_cfg_create();
159 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
160 if (initiator ^ local)
161 {
162 id = "resp";
163 }
164 auth->add(auth, AUTH_RULE_IDENTITY, identification_create_from_string(id));
165 peer_cfg->add_auth_cfg(peer_cfg, auth, local);
166}
167
557e262f
TB
168static peer_cfg_t *create_peer_cfg(bool initiator,
169 exchange_test_sa_conf_t *conf)
c7f5259c
TB
170{
171 peer_cfg_t *peer_cfg;
172 peer_cfg_create_t peer = {
173 .cert_policy = CERT_SEND_IF_ASKED,
174 .unique = UNIQUE_REPLACE,
175 .keyingtries = 1,
176 };
177
557e262f
TB
178 peer_cfg = peer_cfg_create(initiator ? "init" : "resp",
179 create_ike_cfg(initiator, conf), &peer);
c7f5259c
TB
180 add_auth_cfg(peer_cfg, initiator, TRUE);
181 add_auth_cfg(peer_cfg, initiator, FALSE);
c7f5259c
TB
182 return peer_cfg;
183}
184
185METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
557e262f 186 private_backend_t *this, host_t *me, host_t *other)
c7f5259c 187{
557e262f 188 return enumerator_create_single(this->ike_cfg, NULL);
c7f5259c
TB
189}
190
191METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
557e262f 192 private_backend_t *this, identification_t *me, identification_t *other)
c7f5259c 193{
557e262f 194 return enumerator_create_single(this->peer_cfg, NULL);
c7f5259c
TB
195}
196
e0678a8c
TB
197/**
198 * Sets the config objects provided by the backend
199 */
200static void set_config(private_backend_t *this, ike_cfg_t *ike,
201 peer_cfg_t *peer)
202{
203 DESTROY_IF(this->ike_cfg);
204 this->ike_cfg = ike;
205 DESTROY_IF(this->peer_cfg);
206 this->peer_cfg = peer;
207}
208
b76c1dec 209METHOD(exchange_test_helper_t, process_message, status_t,
c7f5259c
TB
210 private_exchange_test_helper_t *this, ike_sa_t *ike_sa, message_t *message)
211{
40d9a4c8
TB
212 status_t status = FAILED;
213 ike_sa_id_t *id;
b76c1dec 214
c7f5259c
TB
215 if (!message)
216 {
217 message = this->public.sender->dequeue(this->public.sender);
218 }
40d9a4c8
TB
219 id = message->get_ike_sa_id(message);
220 id = id->clone(id);
221 id->switch_initiator(id);
222 if (!id->get_responder_spi(id) || id->equals(id, ike_sa->get_id(ike_sa)))
223 {
224 charon->bus->set_sa(charon->bus, ike_sa);
225 status = ike_sa->process_message(ike_sa, message);
226 charon->bus->set_sa(charon->bus, NULL);
227 }
c7f5259c 228 message->destroy(message);
40d9a4c8 229 id->destroy(id);
b76c1dec 230 return status;
c7f5259c
TB
231}
232
e0678a8c 233METHOD(exchange_test_helper_t, create_sa, child_cfg_t*,
557e262f
TB
234 private_exchange_test_helper_t *this, ike_sa_t **init, ike_sa_t **resp,
235 exchange_test_sa_conf_t *conf)
c7f5259c 236{
c7f5259c 237 peer_cfg_t *peer_cfg;
557e262f 238 child_cfg_t *child_cfg;
c7f5259c 239
e0678a8c
TB
240 *init = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
241 IKEV2, TRUE);
c7f5259c 242
e0678a8c
TB
243 *resp = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
244 IKEV2, FALSE);
245
246 peer_cfg = create_peer_cfg(FALSE, conf);
247 child_cfg = create_child_cfg(FALSE, conf);
248 peer_cfg->add_child_cfg(peer_cfg, child_cfg->get_ref(child_cfg));
249 child_cfg->destroy(child_cfg);
250 set_config(this->backend, create_ike_cfg(FALSE, conf), peer_cfg);
c7f5259c 251
557e262f
TB
252 peer_cfg = create_peer_cfg(TRUE, conf);
253 child_cfg = create_child_cfg(TRUE, conf);
254 peer_cfg->add_child_cfg(peer_cfg, child_cfg->get_ref(child_cfg));
e0678a8c 255 (*init)->set_peer_cfg(*init, peer_cfg);
c7f5259c 256 peer_cfg->destroy(peer_cfg);
e0678a8c
TB
257 return child_cfg;
258}
557e262f 259
e0678a8c
TB
260METHOD(exchange_test_helper_t, establish_sa, void,
261 private_exchange_test_helper_t *this, ike_sa_t **init, ike_sa_t **resp,
262 exchange_test_sa_conf_t *conf)
263{
264 ike_sa_id_t *id_i, *id_r;
265 ike_sa_t *sa_i, *sa_r;
266 child_cfg_t *child_i;
267
268 child_i = create_sa(this, init, resp, conf);
269
270 sa_i = *init;
271 sa_r = *resp;
272
273 id_i = sa_i->get_id(sa_i);
274 id_r = sa_r->get_id(sa_r);
275
276 call_ikesa(sa_i, initiate, child_i, 0, NULL, NULL);
557e262f 277
c7f5259c
TB
278 /* IKE_SA_INIT --> */
279 id_r->set_initiator_spi(id_r, id_i->get_initiator_spi(id_i));
280 process_message(this, sa_r, NULL);
281 /* <-- IKE_SA_INIT */
282 id_i->set_responder_spi(id_i, id_r->get_responder_spi(id_r));
283 process_message(this, sa_i, NULL);
284 /* IKE_AUTH --> */
285 process_message(this, sa_r, NULL);
286 /* <-- IKE_AUTH */
287 process_message(this, sa_i, NULL);
288}
289
5d10ef31
TB
290METHOD(exchange_test_helper_t, add_listener, void,
291 private_exchange_test_helper_t *this, listener_t *listener)
292{
293 array_insert_create(&this->listeners, ARRAY_TAIL, listener);
294 charon->bus->add_listener(charon->bus, listener);
295}
296
c7f5259c
TB
297/**
298 * Enable logging in charon as requested
299 */
300static void initialize_logging()
301{
302 int level = LEVEL_SILENT;
303 char *verbosity;
304
305 verbosity = getenv("TESTS_VERBOSITY");
306 if (verbosity)
307 {
308 level = atoi(verbosity);
309 }
310 lib->settings->set_int(lib->settings, "%s.filelog.stderr.default",
311 lib->settings->get_int(lib->settings, "%s.filelog.stderr.default",
312 level, lib->ns), lib->ns);
313 lib->settings->set_bool(lib->settings, "%s.filelog.stderr.ike_name", TRUE,
314 lib->ns);
9665686b 315 charon->load_loggers(charon);
c7f5259c
TB
316}
317
dda5aab0
TB
318/**
319 * Create a nonce generator with the first byte
320 */
321static nonce_gen_t *create_nonce_gen()
322{
323 return mock_nonce_gen_create(exchange_test_helper->nonce_first_byte);
324}
325
c7f5259c
TB
326/*
327 * Described in header
328 */
329void exchange_test_helper_init(char *plugins)
330{
331 private_exchange_test_helper_t *this;
e0678a8c 332 private_backend_t *backend;
7e542486
TB
333 plugin_feature_t features[] = {
334 PLUGIN_REGISTER(DH, mock_dh_create),
335 /* we only need to support a limited number of DH groups */
336 PLUGIN_PROVIDE(DH, MODP_2048_BIT),
337 PLUGIN_PROVIDE(DH, MODP_3072_BIT),
338 PLUGIN_PROVIDE(DH, ECP_256_BIT),
dda5aab0
TB
339 PLUGIN_REGISTER(NONCE_GEN, create_nonce_gen),
340 PLUGIN_PROVIDE(NONCE_GEN),
341 PLUGIN_DEPENDS(RNG, RNG_WEAK),
7e542486 342 };
c7f5259c 343
e0678a8c
TB
344 INIT(backend,
345 .public = {
346 .create_ike_cfg_enumerator = _create_ike_cfg_enumerator,
347 .create_peer_cfg_enumerator = _create_peer_cfg_enumerator,
348 .get_peer_cfg_by_name = (void*)return_null,
349 },
350 );
351
c7f5259c
TB
352 INIT(this,
353 .public = {
354 .sender = mock_sender_create(),
355 .establish_sa = _establish_sa,
e0678a8c 356 .create_sa = _create_sa,
c7f5259c 357 .process_message = _process_message,
5d10ef31 358 .add_listener = _add_listener,
c7f5259c 359 },
c7f5259c 360 .creds = mem_cred_create(),
e0678a8c 361 .backend = backend,
c7f5259c
TB
362 );
363
364 initialize_logging();
7e542486
TB
365 lib->plugins->add_static_features(lib->plugins, "exchange-test-helper",
366 features, countof(features), TRUE, NULL, NULL);
c7f5259c
TB
367 /* the libcharon unit tests only load the libstrongswan plugins, unless
368 * TESTS_PLUGINS is defined */
369 charon->initialize(charon, plugins);
370 lib->plugins->status(lib->plugins, LEVEL_CTRL);
7e542486 371
c7f5259c
TB
372 /* the original sender is not initialized because there is no socket */
373 charon->sender = (sender_t*)this->public.sender;
374 /* and there is no kernel plugin loaded
375 * TODO: we'd have more control if we'd implement kernel_interface_t */
376 charon->kernel->add_ipsec_interface(charon->kernel, mock_ipsec_create);
35e49ffd 377 charon->kernel->add_net_interface(charon->kernel, mock_net_create);
29f1637b
TB
378 /* like SPIs for IPsec SAs, make IKE SPIs predictable */
379 charon->ike_sa_manager->set_spi_cb(charon->ike_sa_manager, get_ike_spi,
380 this);
c7f5259c 381
e0678a8c
TB
382 charon->backends->add_backend(charon->backends, &backend->public);
383
c7f5259c
TB
384 lib->credmgr->add_set(lib->credmgr, &this->creds->set);
385
386 this->creds->add_shared(this->creds,
387 shared_key_create(SHARED_IKE, chunk_clone(chunk_from_str("test"))),
388 identification_create_from_string("%any"), NULL);
389
390 exchange_test_helper = &this->public;
391}
392
393/*
394 * Described in header
395 */
396void exchange_test_helper_deinit()
397{
398 private_exchange_test_helper_t *this;
5d10ef31 399 listener_t *listener;
c7f5259c
TB
400
401 this = (private_exchange_test_helper_t*)exchange_test_helper;
402
5d10ef31
TB
403 while (array_remove(this->listeners, ARRAY_HEAD, &listener))
404 {
405 charon->bus->remove_listener(charon->bus, listener);
406 }
e0678a8c
TB
407 charon->backends->remove_backend(charon->backends, &this->backend->public);
408 set_config(this->backend, NULL, NULL);
409 free(this->backend);
c7f5259c
TB
410 lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
411 this->creds->destroy(this->creds);
735bd4ca
TB
412 /* flush SAs before destroying the sender (in case of test failures) */
413 charon->ike_sa_manager->flush(charon->ike_sa_manager);
414 /* charon won't destroy this as it didn't initialize the original sender */
c7f5259c
TB
415 charon->sender->destroy(charon->sender);
416 charon->sender = NULL;
5d10ef31 417 array_destroy(this->listeners);
c7f5259c
TB
418 free(this);
419}