unit-tests: Make IKE SPIs predictable
[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_ipsec.h"
18
19 #include <credentials/sets/mem_cred.h>
20
21 typedef struct private_exchange_test_helper_t private_exchange_test_helper_t;
22
23 /**
24 * Private data
25 */
26 struct private_exchange_test_helper_t {
27
28 /**
29 * Public interface
30 */
31 exchange_test_helper_t public;
32
33 /**
34 * Config backend
35 */
36 backend_t backend;
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 CALLBACK(get_ike_spi, uint64_t,
50 private_exchange_test_helper_t *this)
51 {
52 return (uint64_t)ref_get(&this->ike_spi);
53 }
54
55 /*
56 * Described in header
57 */
58 exchange_test_helper_t *exchange_test_helper;
59
60 static ike_cfg_t *create_ike_cfg()
61 {
62 ike_cfg_t *ike_cfg;
63
64 ike_cfg = ike_cfg_create(IKEV2, TRUE, FALSE, "127.0.0.1", IKEV2_UDP_PORT,
65 "127.0.0.1", IKEV2_UDP_PORT, FRAGMENTATION_NO, 0);
66 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
67 return ike_cfg;
68 }
69
70 static child_cfg_t *create_child_cfg(bool initiator)
71 {
72 child_cfg_t *child_cfg;
73 child_cfg_create_t child = {
74 .mode = MODE_TUNNEL,
75 };
76
77 child_cfg = child_cfg_create(initiator ? "init" : "resp", &child);
78 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
79 child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP));
80 child_cfg->add_traffic_selector(child_cfg, TRUE,
81 traffic_selector_create_dynamic(0, 0, 65535));
82 child_cfg->add_traffic_selector(child_cfg, FALSE,
83 traffic_selector_create_dynamic(0, 0, 65535));
84 return child_cfg;
85 }
86
87 static void add_auth_cfg(peer_cfg_t *peer_cfg, bool initiator, bool local)
88 {
89 auth_cfg_t *auth;
90 char *id = "init";
91
92 auth = auth_cfg_create();
93 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
94 if (initiator ^ local)
95 {
96 id = "resp";
97 }
98 auth->add(auth, AUTH_RULE_IDENTITY, identification_create_from_string(id));
99 peer_cfg->add_auth_cfg(peer_cfg, auth, local);
100 }
101
102 static peer_cfg_t *create_peer_cfg(bool initiator)
103 {
104 peer_cfg_t *peer_cfg;
105 peer_cfg_create_t peer = {
106 .cert_policy = CERT_SEND_IF_ASKED,
107 .unique = UNIQUE_REPLACE,
108 .keyingtries = 1,
109 };
110
111 peer_cfg = peer_cfg_create(initiator ? "init" : "resp", create_ike_cfg(),
112 &peer);
113 add_auth_cfg(peer_cfg, initiator, TRUE);
114 add_auth_cfg(peer_cfg, initiator, FALSE);
115 peer_cfg->add_child_cfg(peer_cfg, create_child_cfg(initiator));
116 return peer_cfg;
117 }
118
119 METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
120 backend_t *this, host_t *me, host_t *other)
121 {
122 ike_cfg_t *ike_cfg = create_ike_cfg();
123 return enumerator_create_single(ike_cfg, (void*)ike_cfg->destroy);
124 }
125
126 METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
127 backend_t *this, identification_t *me, identification_t *other)
128 {
129 peer_cfg_t *peer_cfg = create_peer_cfg(FALSE);
130 return enumerator_create_single(peer_cfg, (void*)peer_cfg->destroy);
131 }
132
133 METHOD(exchange_test_helper_t, process_message, void,
134 private_exchange_test_helper_t *this, ike_sa_t *ike_sa, message_t *message)
135 {
136 if (!message)
137 {
138 message = this->public.sender->dequeue(this->public.sender);
139 }
140 charon->bus->set_sa(charon->bus, ike_sa);
141 ike_sa->process_message(ike_sa, message);
142 charon->bus->set_sa(charon->bus, NULL);
143 message->destroy(message);
144 }
145
146 METHOD(exchange_test_helper_t, establish_sa, void,
147 private_exchange_test_helper_t *this, ike_sa_t **init, ike_sa_t **resp)
148 {
149 ike_sa_id_t *id_i, *id_r;
150 ike_sa_t *sa_i, *sa_r;
151 peer_cfg_t *peer_cfg;
152
153 sa_i = *init = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
154 IKEV2, TRUE);
155 id_i = sa_i->get_id(sa_i);
156
157 sa_r = *resp = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
158 IKEV2, FALSE);
159 id_r = sa_r->get_id(sa_r);
160
161 peer_cfg = create_peer_cfg(TRUE);
162 sa_i->set_peer_cfg(sa_i, peer_cfg);
163 peer_cfg->destroy(peer_cfg);
164 call_ikesa(sa_i, initiate, create_child_cfg(TRUE), 0, NULL, NULL);
165 /* IKE_SA_INIT --> */
166 id_r->set_initiator_spi(id_r, id_i->get_initiator_spi(id_i));
167 process_message(this, sa_r, NULL);
168 /* <-- IKE_SA_INIT */
169 id_i->set_responder_spi(id_i, id_r->get_responder_spi(id_r));
170 process_message(this, sa_i, NULL);
171 /* IKE_AUTH --> */
172 process_message(this, sa_r, NULL);
173 /* <-- IKE_AUTH */
174 process_message(this, sa_i, NULL);
175 }
176
177 /**
178 * Enable logging in charon as requested
179 */
180 static void initialize_logging()
181 {
182 int level = LEVEL_SILENT;
183 char *verbosity;
184
185 verbosity = getenv("TESTS_VERBOSITY");
186 if (verbosity)
187 {
188 level = atoi(verbosity);
189 }
190 lib->settings->set_int(lib->settings, "%s.filelog.stderr.default",
191 lib->settings->get_int(lib->settings, "%s.filelog.stderr.default",
192 level, lib->ns), lib->ns);
193 lib->settings->set_bool(lib->settings, "%s.filelog.stderr.ike_name", TRUE,
194 lib->ns);
195 charon->load_loggers(charon, NULL, TRUE);
196 }
197
198 /*
199 * Described in header
200 */
201 void exchange_test_helper_init(char *plugins)
202 {
203 private_exchange_test_helper_t *this;
204
205 INIT(this,
206 .public = {
207 .sender = mock_sender_create(),
208 .establish_sa = _establish_sa,
209 .process_message = _process_message,
210 },
211 .backend = {
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 .creds = mem_cred_create(),
217 );
218
219 initialize_logging();
220 /* the libcharon unit tests only load the libstrongswan plugins, unless
221 * TESTS_PLUGINS is defined */
222 charon->initialize(charon, plugins);
223 lib->plugins->status(lib->plugins, LEVEL_CTRL);
224 /* the original sender is not initialized because there is no socket */
225 charon->sender = (sender_t*)this->public.sender;
226 /* and there is no kernel plugin loaded
227 * TODO: we'd have more control if we'd implement kernel_interface_t */
228 charon->kernel->add_ipsec_interface(charon->kernel, mock_ipsec_create);
229 /* like SPIs for IPsec SAs, make IKE SPIs predictable */
230 charon->ike_sa_manager->set_spi_cb(charon->ike_sa_manager, get_ike_spi,
231 this);
232
233 charon->backends->add_backend(charon->backends, &this->backend);
234 lib->credmgr->add_set(lib->credmgr, &this->creds->set);
235
236 this->creds->add_shared(this->creds,
237 shared_key_create(SHARED_IKE, chunk_clone(chunk_from_str("test"))),
238 identification_create_from_string("%any"), NULL);
239
240 exchange_test_helper = &this->public;
241 }
242
243 /*
244 * Described in header
245 */
246 void exchange_test_helper_deinit()
247 {
248 private_exchange_test_helper_t *this;
249
250 this = (private_exchange_test_helper_t*)exchange_test_helper;
251
252 charon->backends->remove_backend(charon->backends, &this->backend);
253 lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
254 this->creds->destroy(this->creds);
255 /* can't let charon do it as it happens too late */
256 charon->sender->destroy(charon->sender);
257 charon->sender = NULL;
258 free(this);
259 }