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