2 * Copyright (C) 2016-2018 Tobias Brunner
3 * HSR Hochschule fuer Technik Rapperswil
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>.
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
16 #include "exchange_test_helper.h"
18 #include "mock_ipsec.h"
20 #include "mock_nonce_gen.h"
22 #include <collections/array.h>
23 #include <credentials/sets/mem_cred.h>
25 typedef struct private_exchange_test_helper_t private_exchange_test_helper_t
;
26 typedef struct private_backend_t private_backend_t
;
31 struct private_exchange_test_helper_t
{
36 exchange_test_helper_t
public;
49 * List of registered listeners
56 private_backend_t
*backend
;
60 * Custom backend_t implementation
62 struct private_backend_t
{
75 * Responder peer_cfg/child_cfg
80 CALLBACK(get_ike_spi
, uint64_t,
81 private_exchange_test_helper_t
*this)
83 return (uint64_t)ref_get(&this->ike_spi
);
89 exchange_test_helper_t
*exchange_test_helper
;
91 static ike_cfg_t
*create_ike_cfg(bool initiator
, exchange_test_sa_conf_t
*conf
)
93 ike_cfg_create_t ike
= {
96 .local_port
= IKEV2_UDP_PORT
,
97 .remote
= "127.0.0.1",
98 .remote_port
= IKEV2_UDP_PORT
,
101 char *proposal
= NULL
;
105 ike
.childless
= initiator ? conf
->initiator
.childless
106 : conf
->responder
.childless
;
107 proposal
= initiator ? conf
->initiator
.ike
: conf
->responder
.ike
;
110 ike_cfg
= ike_cfg_create(&ike
);
113 ike_cfg
->add_proposal(ike_cfg
,
114 proposal_create_from_string(PROTO_IKE
, proposal
));
118 ike_cfg
->add_proposal(ike_cfg
, proposal_create_default(PROTO_IKE
));
123 static child_cfg_t
*create_child_cfg(bool initiator
,
124 exchange_test_sa_conf_t
*conf
)
126 child_cfg_t
*child_cfg
;
127 child_cfg_create_t child
= {
130 char *proposal
= NULL
;
132 child_cfg
= child_cfg_create(initiator ?
"init" : "resp", &child
);
135 proposal
= initiator ? conf
->initiator
.esp
: conf
->responder
.esp
;
139 child_cfg
->add_proposal(child_cfg
,
140 proposal_create_from_string(PROTO_ESP
, proposal
));
144 child_cfg
->add_proposal(child_cfg
, proposal_create_default(PROTO_ESP
));
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));
153 static void add_auth_cfg(peer_cfg_t
*peer_cfg
, bool initiator
, bool local
)
158 auth
= auth_cfg_create();
159 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_PSK
);
160 if (initiator
^ local
)
164 auth
->add(auth
, AUTH_RULE_IDENTITY
, identification_create_from_string(id
));
165 peer_cfg
->add_auth_cfg(peer_cfg
, auth
, local
);
168 static peer_cfg_t
*create_peer_cfg(bool initiator
,
169 exchange_test_sa_conf_t
*conf
)
171 peer_cfg_t
*peer_cfg
;
172 peer_cfg_create_t peer
= {
173 .cert_policy
= CERT_SEND_IF_ASKED
,
174 .unique
= UNIQUE_REPLACE
,
178 peer_cfg
= peer_cfg_create(initiator ?
"init" : "resp",
179 create_ike_cfg(initiator
, conf
), &peer
);
180 add_auth_cfg(peer_cfg
, initiator
, TRUE
);
181 add_auth_cfg(peer_cfg
, initiator
, FALSE
);
185 METHOD(backend_t
, create_ike_cfg_enumerator
, enumerator_t
*,
186 private_backend_t
*this, host_t
*me
, host_t
*other
)
188 return enumerator_create_single(this->ike_cfg
, NULL
);
191 METHOD(backend_t
, create_peer_cfg_enumerator
, enumerator_t
*,
192 private_backend_t
*this, identification_t
*me
, identification_t
*other
)
194 return enumerator_create_single(this->peer_cfg
, NULL
);
198 * Sets the config objects provided by the backend
200 static void set_config(private_backend_t
*this, ike_cfg_t
*ike
,
203 DESTROY_IF(this->ike_cfg
);
205 DESTROY_IF(this->peer_cfg
);
206 this->peer_cfg
= peer
;
209 METHOD(exchange_test_helper_t
, process_message
, status_t
,
210 private_exchange_test_helper_t
*this, ike_sa_t
*ike_sa
, message_t
*message
)
212 status_t status
= FAILED
;
217 message
= this->public.sender
->dequeue(this->public.sender
);
219 id
= message
->get_ike_sa_id(message
);
221 id
->switch_initiator(id
);
222 if (!id
->get_responder_spi(id
) || id
->equals(id
, ike_sa
->get_id(ike_sa
)))
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
);
228 message
->destroy(message
);
233 METHOD(exchange_test_helper_t
, create_sa
, child_cfg_t
*,
234 private_exchange_test_helper_t
*this, ike_sa_t
**init
, ike_sa_t
**resp
,
235 exchange_test_sa_conf_t
*conf
)
237 peer_cfg_t
*peer_cfg
;
238 child_cfg_t
*child_cfg
;
240 *init
= charon
->ike_sa_manager
->checkout_new(charon
->ike_sa_manager
,
243 *resp
= charon
->ike_sa_manager
->checkout_new(charon
->ike_sa_manager
,
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
);
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
));
255 (*init
)->set_peer_cfg(*init
, peer_cfg
);
256 peer_cfg
->destroy(peer_cfg
);
260 METHOD(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
)
264 ike_sa_id_t
*id_i
, *id_r
;
265 ike_sa_t
*sa_i
, *sa_r
;
266 child_cfg_t
*child_i
;
268 child_i
= create_sa(this, init
, resp
, conf
);
273 id_i
= sa_i
->get_id(sa_i
);
274 id_r
= sa_r
->get_id(sa_r
);
276 call_ikesa(sa_i
, initiate
, child_i
, 0, NULL
, NULL
);
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
);
285 process_message(this, sa_r
, NULL
);
287 process_message(this, sa_i
, NULL
);
290 METHOD(exchange_test_helper_t
, add_listener
, void,
291 private_exchange_test_helper_t
*this, listener_t
*listener
)
293 array_insert_create(&this->listeners
, ARRAY_TAIL
, listener
);
294 charon
->bus
->add_listener(charon
->bus
, listener
);
298 * Enable logging in charon as requested
300 static void initialize_logging()
302 int level
= LEVEL_SILENT
;
305 verbosity
= getenv("TESTS_VERBOSITY");
308 level
= atoi(verbosity
);
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
,
315 charon
->load_loggers(charon
);
319 * Create a nonce generator with the first byte
321 static nonce_gen_t
*create_nonce_gen()
323 return mock_nonce_gen_create(exchange_test_helper
->nonce_first_byte
);
327 * Described in header
329 void exchange_test_helper_init(char *plugins
)
331 private_exchange_test_helper_t
*this;
332 private_backend_t
*backend
;
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
),
339 PLUGIN_REGISTER(NONCE_GEN
, create_nonce_gen
),
340 PLUGIN_PROVIDE(NONCE_GEN
),
341 PLUGIN_DEPENDS(RNG
, RNG_WEAK
),
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
,
354 .sender
= mock_sender_create(),
355 .establish_sa
= _establish_sa
,
356 .create_sa
= _create_sa
,
357 .process_message
= _process_message
,
358 .add_listener
= _add_listener
,
360 .creds
= mem_cred_create(),
364 initialize_logging();
365 lib
->plugins
->add_static_features(lib
->plugins
, "exchange-test-helper",
366 features
, countof(features
), TRUE
, NULL
, NULL
);
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
);
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
);
377 charon
->kernel
->add_net_interface(charon
->kernel
, mock_net_create
);
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
,
382 charon
->backends
->add_backend(charon
->backends
, &backend
->public);
384 lib
->credmgr
->add_set(lib
->credmgr
, &this->creds
->set
);
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
);
390 exchange_test_helper
= &this->public;
394 * Described in header
396 void exchange_test_helper_deinit()
398 private_exchange_test_helper_t
*this;
399 listener_t
*listener
;
401 this = (private_exchange_test_helper_t
*)exchange_test_helper
;
403 while (array_remove(this->listeners
, ARRAY_HEAD
, &listener
))
405 charon
->bus
->remove_listener(charon
->bus
, listener
);
407 charon
->backends
->remove_backend(charon
->backends
, &this->backend
->public);
408 set_config(this->backend
, NULL
, NULL
);
410 lib
->credmgr
->remove_set(lib
->credmgr
, &this->creds
->set
);
411 this->creds
->destroy(this->creds
);
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 */
415 charon
->sender
->destroy(charon
->sender
);
416 charon
->sender
= NULL
;
417 array_destroy(this->listeners
);