proposal: correctly enumerate registered AEADs to build default IKE proposal
[strongswan.git] / src / libcharon / config / ike_cfg.c
1 /*
2 * Copyright (C) 2005-2007 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "ike_cfg.h"
18
19 #include <string.h>
20
21 #include <daemon.h>
22
23
24 ENUM(ike_version_names, IKE_ANY, IKEV2,
25 "IKEv1/2",
26 "IKEv1",
27 "IKEv2",
28 );
29
30 typedef struct private_ike_cfg_t private_ike_cfg_t;
31
32 /**
33 * Private data of an ike_cfg_t object
34 */
35 struct private_ike_cfg_t {
36
37 /**
38 * Public part
39 */
40 ike_cfg_t public;
41
42 /**
43 * Number of references hold by others to this ike_cfg
44 */
45 refcount_t refcount;
46
47 /**
48 * IKE version to use
49 */
50 ike_version_t version;
51
52 /**
53 * Address of local host
54 */
55 char *me;
56
57 /**
58 * Address of remote host
59 */
60 char *other;
61
62 /**
63 * Allow override of local address
64 */
65 bool my_allow_any;
66
67 /**
68 * Allow override of remote address
69 */
70 bool other_allow_any;
71
72 /**
73 * our source port
74 */
75 u_int16_t my_port;
76
77 /**
78 * destination port
79 */
80 u_int16_t other_port;
81
82 /**
83 * should we send a certificate request?
84 */
85 bool certreq;
86
87 /**
88 * enforce UDP encapsulation
89 */
90 bool force_encap;
91
92 /**
93 * use IKEv1 fragmentation
94 */
95 fragmentation_t fragmentation;
96
97 /**
98 * DSCP value to use on sent IKE packets
99 */
100 u_int8_t dscp;
101
102 /**
103 * List of proposals to use
104 */
105 linked_list_t *proposals;
106 };
107
108 METHOD(ike_cfg_t, get_version, ike_version_t,
109 private_ike_cfg_t *this)
110 {
111 return this->version;
112 }
113
114 METHOD(ike_cfg_t, send_certreq, bool,
115 private_ike_cfg_t *this)
116 {
117 return this->certreq;
118 }
119
120 METHOD(ike_cfg_t, force_encap_, bool,
121 private_ike_cfg_t *this)
122 {
123 return this->force_encap;
124 }
125
126 METHOD(ike_cfg_t, fragmentation, fragmentation_t,
127 private_ike_cfg_t *this)
128 {
129 return this->fragmentation;
130 }
131
132 METHOD(ike_cfg_t, get_my_addr, char*,
133 private_ike_cfg_t *this, bool *allow_any)
134 {
135 if (allow_any)
136 {
137 *allow_any = this->my_allow_any;
138 }
139 return this->me;
140 }
141
142 METHOD(ike_cfg_t, get_other_addr, char*,
143 private_ike_cfg_t *this, bool *allow_any)
144 {
145 if (allow_any)
146 {
147 *allow_any = this->other_allow_any;
148 }
149 return this->other;
150 }
151
152 METHOD(ike_cfg_t, get_my_port, u_int16_t,
153 private_ike_cfg_t *this)
154 {
155 return this->my_port;
156 }
157
158 METHOD(ike_cfg_t, get_other_port, u_int16_t,
159 private_ike_cfg_t *this)
160 {
161 return this->other_port;
162 }
163
164 METHOD(ike_cfg_t, get_dscp, u_int8_t,
165 private_ike_cfg_t *this)
166 {
167 return this->dscp;
168 }
169
170 METHOD(ike_cfg_t, add_proposal, void,
171 private_ike_cfg_t *this, proposal_t *proposal)
172 {
173 this->proposals->insert_last(this->proposals, proposal);
174 }
175
176 METHOD(ike_cfg_t, get_proposals, linked_list_t*,
177 private_ike_cfg_t *this)
178 {
179 enumerator_t *enumerator;
180 proposal_t *current;
181 linked_list_t *proposals;
182
183 proposals = linked_list_create();
184 enumerator = this->proposals->create_enumerator(this->proposals);
185 while (enumerator->enumerate(enumerator, &current))
186 {
187 current = current->clone(current);
188 proposals->insert_last(proposals, current);
189 }
190 enumerator->destroy(enumerator);
191
192 DBG2(DBG_CFG, "configured proposals: %#P", proposals);
193
194 return proposals;
195 }
196
197 METHOD(ike_cfg_t, select_proposal, proposal_t*,
198 private_ike_cfg_t *this, linked_list_t *proposals, bool private)
199 {
200 enumerator_t *stored_enum, *supplied_enum;
201 proposal_t *stored, *supplied, *selected;
202
203 stored_enum = this->proposals->create_enumerator(this->proposals);
204 supplied_enum = proposals->create_enumerator(proposals);
205
206
207 /* compare all stored proposals with all supplied. Stored ones are preferred.*/
208 while (stored_enum->enumerate(stored_enum, (void**)&stored))
209 {
210 proposals->reset_enumerator(proposals, supplied_enum);
211
212 while (supplied_enum->enumerate(supplied_enum, (void**)&supplied))
213 {
214 selected = stored->select(stored, supplied, private);
215 if (selected)
216 {
217 /* they match, return */
218 stored_enum->destroy(stored_enum);
219 supplied_enum->destroy(supplied_enum);
220 DBG2(DBG_CFG, "received proposals: %#P", proposals);
221 DBG2(DBG_CFG, "configured proposals: %#P", this->proposals);
222 DBG2(DBG_CFG, "selected proposal: %P", selected);
223 return selected;
224 }
225 }
226 }
227 /* no proposal match :-(, will result in a NO_PROPOSAL_CHOSEN... */
228 stored_enum->destroy(stored_enum);
229 supplied_enum->destroy(supplied_enum);
230 DBG1(DBG_CFG, "received proposals: %#P", proposals);
231 DBG1(DBG_CFG, "configured proposals: %#P", this->proposals);
232
233 return NULL;
234 }
235
236 METHOD(ike_cfg_t, get_dh_group, diffie_hellman_group_t,
237 private_ike_cfg_t *this)
238 {
239 enumerator_t *enumerator;
240 proposal_t *proposal;
241 u_int16_t dh_group = MODP_NONE;
242
243 enumerator = this->proposals->create_enumerator(this->proposals);
244 while (enumerator->enumerate(enumerator, &proposal))
245 {
246 if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &dh_group, NULL))
247 {
248 break;
249 }
250 }
251 enumerator->destroy(enumerator);
252 return dh_group;
253 }
254
255 METHOD(ike_cfg_t, equals, bool,
256 private_ike_cfg_t *this, ike_cfg_t *other_public)
257 {
258 private_ike_cfg_t *other = (private_ike_cfg_t*)other_public;
259 enumerator_t *e1, *e2;
260 proposal_t *p1, *p2;
261 bool eq = TRUE;
262
263 if (this == other)
264 {
265 return TRUE;
266 }
267 if (this->public.equals != other->public.equals)
268 {
269 return FALSE;
270 }
271 if (this->proposals->get_count(this->proposals) !=
272 other->proposals->get_count(other->proposals))
273 {
274 return FALSE;
275 }
276 e1 = this->proposals->create_enumerator(this->proposals);
277 e2 = this->proposals->create_enumerator(this->proposals);
278 while (e1->enumerate(e1, &p1) && e2->enumerate(e2, &p2))
279 {
280 if (!p1->equals(p1, p2))
281 {
282 eq = FALSE;
283 break;
284 }
285 }
286 e1->destroy(e1);
287 e2->destroy(e2);
288
289 return (eq &&
290 this->version == other->version &&
291 this->certreq == other->certreq &&
292 this->force_encap == other->force_encap &&
293 this->fragmentation == other->fragmentation &&
294 streq(this->me, other->me) &&
295 streq(this->other, other->other) &&
296 this->my_port == other->my_port &&
297 this->other_port == other->other_port);
298 }
299
300 METHOD(ike_cfg_t, get_ref, ike_cfg_t*,
301 private_ike_cfg_t *this)
302 {
303 ref_get(&this->refcount);
304 return &this->public;
305 }
306
307 METHOD(ike_cfg_t, destroy, void,
308 private_ike_cfg_t *this)
309 {
310 if (ref_put(&this->refcount))
311 {
312 this->proposals->destroy_offset(this->proposals,
313 offsetof(proposal_t, destroy));
314 free(this->me);
315 free(this->other);
316 free(this);
317 }
318 }
319
320 /**
321 * Described in header.
322 */
323 ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap,
324 char *me, bool my_allow_any, u_int16_t my_port,
325 char *other, bool other_allow_any, u_int16_t other_port,
326 fragmentation_t fragmentation, u_int8_t dscp)
327 {
328 private_ike_cfg_t *this;
329
330 INIT(this,
331 .public = {
332 .get_version = _get_version,
333 .send_certreq = _send_certreq,
334 .force_encap = _force_encap_,
335 .fragmentation = _fragmentation,
336 .get_my_addr = _get_my_addr,
337 .get_other_addr = _get_other_addr,
338 .get_my_port = _get_my_port,
339 .get_other_port = _get_other_port,
340 .get_dscp = _get_dscp,
341 .add_proposal = _add_proposal,
342 .get_proposals = _get_proposals,
343 .select_proposal = _select_proposal,
344 .get_dh_group = _get_dh_group,
345 .equals = _equals,
346 .get_ref = _get_ref,
347 .destroy = _destroy,
348 },
349 .refcount = 1,
350 .version = version,
351 .certreq = certreq,
352 .force_encap = force_encap,
353 .fragmentation = fragmentation,
354 .me = strdup(me),
355 .other = strdup(other),
356 .my_allow_any = my_allow_any,
357 .other_allow_any = other_allow_any,
358 .my_port = my_port,
359 .other_port = other_port,
360 .dscp = dscp,
361 .proposals = linked_list_create(),
362 );
363
364 return &this->public;
365 }