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