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