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