- moved hasher_*_t to *_hasher_t
[strongswan.git] / Source / charon / config / configuration_manager.c
1 /**
2 * @file configuration.c
3 *
4 * @brief Configuration class used to store IKE_SA-configurations.
5 *
6 * Object of this type represents the configuration for all IKE_SA's and their child_sa's.
7 *
8 */
9
10 /*
11 * Copyright (C) 2005 Jan Hutter, Martin Willi
12 * Hochschule fuer Technik Rapperswil
13 *
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2 of the License, or (at your
17 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
23 */
24
25 #include <stdlib.h>
26
27 #include "configuration_manager.h"
28
29 #include <types.h>
30 #include <globals.h>
31 #include <utils/allocator.h>
32 #include <encoding/payloads/nonce_payload.h>
33 #include <encoding/payloads/proposal_substructure.h>
34 #include <encoding/payloads/ke_payload.h>
35 #include <encoding/payloads/transform_attribute.h>
36
37 typedef struct private_configuration_manager_t private_configuration_manager_t;
38
39 /**
40 * Private data of an configuration_t object
41 */
42 struct private_configuration_manager_t {
43
44 /**
45 * Public part
46 */
47 configuration_manager_t public;
48
49 /**
50 * Assigned logger object
51 */
52 logger_t *logger;
53 };
54
55 /**
56 * Implements function configuration_manager_t.get_remote_host.
57 */
58 static status_t get_remote_host(private_configuration_manager_t *this, char *name, host_t **host)
59 {
60 /*
61 * For testing purposes, hard coded host informations for two configurations are returned.
62 *
63 * Further improvements could store them in a linked list or hash table.
64 */
65
66 host_t *remote;
67 status_t status = SUCCESS;
68
69 if (strcmp(name, "pinflb30") == 0)
70 {
71 remote = host_create(AF_INET, "152.96.193.130", 500);
72 }
73 else if (strcmp(name, "pinflb31") == 0)
74 {
75 remote = host_create(AF_INET, "152.96.193.131", 500);
76 }
77 else if (strcmp(name, "localhost") == 0)
78 {
79 remote = host_create(AF_INET, "127.0.0.1", 500);
80 }
81 else
82 {
83 status = NOT_FOUND;
84 }
85 if ((status != NOT_FOUND) && (remote == NULL))
86 {
87 return OUT_OF_RES;
88 }
89
90 *host = remote;
91 return status;
92 }
93
94 /**
95 * Implements function configuration_manager_t.get_local_host.
96 */
97 static status_t get_local_host(private_configuration_manager_t *this, char *name, host_t **host)
98 {
99 /*
100 * For testing purposes, only the default route is returned for each configuration.
101 *
102 * Further improvements could store different local host informations in a linked list or hash table.
103 */
104 host_t *local;
105 local = host_create(AF_INET, "0.0.0.0", 0);
106 if (local == NULL)
107 {
108 return OUT_OF_RES;
109 }
110 *host = local;
111 return SUCCESS;
112 }
113
114 /**
115 * Implements function configuration_manager_t.get_dh_group_number.
116 */
117 static status_t get_dh_group_number(private_configuration_manager_t *this,char *name, u_int16_t *dh_group_number, u_int16_t priority)
118 {
119 /* Currently only two dh_group_numbers are supported for each configuration*/
120
121 if (priority == 1)
122 {
123 *dh_group_number = MODP_1024_BIT;
124 }
125 else
126 {
127 *dh_group_number = MODP_768_BIT;
128 }
129 return SUCCESS;
130 }
131
132 /**
133 * Implements function configuration_manager_t.get_proposals_for_host.
134 */
135 static status_t get_proposals_for_host(private_configuration_manager_t *this, host_t *host, iterator_t *iterator)
136 {
137 /*
138 * Currently the following hard coded proposal is created and returned for all hosts:
139 * - ENCR_AES_CBC 128Bit
140 * - PRF_HMAC_MD5 128Bit
141 * - AUTH_HMAC_MD5_96 128Bit
142 * - MODP_1024_BIT
143 */
144 proposal_substructure_t *proposal;
145 transform_substructure_t *transform;
146 transform_attribute_t *attribute;
147 status_t status;
148
149 proposal = proposal_substructure_create();
150 if (proposal == NULL)
151 {
152 return OUT_OF_RES;
153 }
154
155 proposal->set_proposal_number(proposal, 1);
156 proposal->set_protocol_id(proposal, 1);
157
158 /*
159 * Encryption Algorithm
160 */
161 transform = transform_substructure_create();
162 if (transform == NULL)
163 {
164 proposal->destroy(proposal);
165 return OUT_OF_RES;
166 }
167 status = proposal->add_transform_substructure(proposal, transform);
168 if (status != SUCCESS)
169 {
170 proposal->destroy(proposal);
171 return OUT_OF_RES;
172 }
173 transform->set_transform_type(transform, ENCRYPTION_ALGORITHM);
174 transform->set_transform_id(transform, ENCR_AES_CBC);
175
176 attribute = transform_attribute_create();
177 if (attribute == NULL)
178 {
179 proposal->destroy(proposal);
180 return OUT_OF_RES;
181 }
182 status = transform->add_transform_attribute(transform, attribute);
183 if (status != SUCCESS)
184 {
185 proposal->destroy(proposal);
186 return OUT_OF_RES;
187 }
188 attribute->set_attribute_type(attribute, KEY_LENGTH);
189 attribute->set_value(attribute, 16);
190
191 /*
192 * Pseudo-random Function
193 */
194 transform = transform_substructure_create();
195 if (transform == NULL)
196 {
197 proposal->destroy(proposal);
198 return OUT_OF_RES;
199 }
200 status = proposal->add_transform_substructure(proposal, transform);
201 if (status != SUCCESS)
202 {
203 proposal->destroy(proposal);
204 return OUT_OF_RES;
205 }
206 transform->set_transform_type(transform, PSEUDO_RANDOM_FUNCTION);
207 transform->set_transform_id(transform, PRF_HMAC_MD5);
208
209 attribute = transform_attribute_create();
210 if (attribute == NULL)
211 {
212 proposal->destroy(proposal);
213 return OUT_OF_RES;
214 }
215 status = transform->add_transform_attribute(transform, attribute);
216 if (status != SUCCESS)
217 {
218 proposal->destroy(proposal);
219 return OUT_OF_RES;
220 }
221 attribute->set_attribute_type(attribute, KEY_LENGTH);
222 attribute->set_value(attribute, 16);
223
224
225 /*
226 * Integrity Algorithm
227 */
228 transform = transform_substructure_create();
229 if (transform == NULL)
230 {
231 proposal->destroy(proposal);
232 return OUT_OF_RES;
233 }
234 status = proposal->add_transform_substructure(proposal, transform);
235 if (status != SUCCESS)
236 {
237 proposal->destroy(proposal);
238 return OUT_OF_RES;
239 }
240 transform->set_transform_type(transform, INTEGRITIY_ALGORITHM);
241 transform->set_transform_id(transform, AUTH_HMAC_MD5_96);
242
243 attribute = transform_attribute_create();
244 if (attribute == NULL)
245 {
246 proposal->destroy(proposal);
247 return OUT_OF_RES;
248 }
249 status = transform->add_transform_attribute(transform, attribute);
250 if (status != SUCCESS)
251 {
252 proposal->destroy(proposal);
253 return OUT_OF_RES;
254 }
255 attribute->set_attribute_type(attribute, KEY_LENGTH);
256 attribute->set_value(attribute, 16);
257
258
259 /*
260 * Diffie-Hellman Group
261 */
262 transform = transform_substructure_create();
263 if (transform == NULL)
264 {
265 proposal->destroy(proposal);
266 return OUT_OF_RES;
267 }
268 status = proposal->add_transform_substructure(proposal, transform);
269 if (status != SUCCESS)
270 {
271 proposal->destroy(proposal);
272 return OUT_OF_RES;
273 }
274 transform->set_transform_type(transform, DIFFIE_HELLMAN_GROUP);
275 transform->set_transform_id(transform, MODP_1024_BIT);
276
277 iterator->insert_after(iterator, (void*)proposal);
278
279 return SUCCESS;
280 }
281
282 /**
283 * Implements function configuration_manager_t.select_proposals_for_host.
284 */
285 static status_t select_proposals_for_host(private_configuration_manager_t *this, host_t *host, iterator_t *in, iterator_t *out)
286 {
287 /* Currently the first suggested proposal is selected, cloned and then returned*/
288 status_t status;
289 proposal_substructure_t *first_suggested_proposal;
290 proposal_substructure_t *selected_proposal;
291
292 this->logger->log(this->logger,CONTROL | MORE, "Going to select first suggested proposal");
293 if (!in->has_next(in))
294 {
295 this->logger->log(this->logger,ERROR | MORE, "No proposal suggested");
296 /* no suggested proposal! */
297 return FAILED;
298 }
299
300 status = in->current(in,(void **) &first_suggested_proposal);
301 if (status != SUCCESS)
302 {
303 this->logger->log(this->logger,ERROR, "Fatal error: could not get first proposal from iterator");
304 return status;
305 }
306 status = first_suggested_proposal->clone(first_suggested_proposal,&selected_proposal);
307 if (status != SUCCESS)
308 {
309 this->logger->log(this->logger,ERROR, "Fatal error: could not clone proposal");
310 /* could not clone proposal */
311 return status;
312 }
313
314 status = out->insert_after(out,selected_proposal);
315 if (status != SUCCESS)
316 {
317 this->logger->log(this->logger,ERROR, "Fatal error: could not insert selected proposal in out iterator");
318 }
319 return status;
320 }
321
322 /**
323 * Implements function configuration_manager_t.get_transforms_for_host_and_proposals.
324 */
325 static status_t get_transforms_for_host_and_proposals (private_configuration_manager_t *this, host_t *host, iterator_t *proposals,encryption_algorithm_t *encryption_algorithm,pseudo_random_function_t *pseudo_random_function, integrity_algorithm_t *integrity_algorithm)
326 {
327 /*
328 * Currently the given proposals are not checked if they are valid for specific host!
329 *
330 * The first proposal is taken and the appropriate transform objects are created (only if they are supported)
331 */
332
333 encryption_algorithm_t selected_encryption_algorithm = ENCR_UNDEFINED;
334 pseudo_random_function_t selected_pseudo_random_function = PRF_UNDEFINED;
335 integrity_algorithm_t selected_integrity_algorithm = AUTH_UNDEFINED;
336 proposal_substructure_t *proposal;
337 iterator_t *transforms;
338 status_t status;
339
340 this->logger->log(this->logger,CONTROL|MORE, "Going to get transforms for given proposal");
341
342 if (!proposals->has_next(proposals))
343 {
344 this->logger->log(this->logger,ERROR | MORE, "No proposal available");
345 return FAILED;
346 }
347
348 status = proposals->current(proposals,(void **) &(proposal));
349 if (status != SUCCESS)
350 {
351 this->logger->log(this->logger,ERROR, "Fatal error: could not get first proposal from iterator");
352 return status;
353 }
354
355 status = proposal->create_transform_substructure_iterator(proposal,&transforms,TRUE);
356 if (status != SUCCESS)
357 {
358 this->logger->log(this->logger,ERROR, "Fatal error: could not create iterator of transforms");
359 return status;
360 }
361
362 while (transforms->has_next(transforms))
363 {
364 transform_substructure_t *current_transform;
365 transform_type_t transform_type;
366 u_int16_t transform_id;
367
368 status = transforms->current(transforms,(void **) &(current_transform));
369 if (status != SUCCESS)
370 {
371 this->logger->log(this->logger,ERROR, "Fatal error: could not get current transform substructure object");
372 transforms->destroy(transforms);
373 return status;
374 }
375
376 transform_type = current_transform->get_transform_type(current_transform);
377 transform_id = current_transform->get_transform_id(current_transform);
378
379 this->logger->log(this->logger,CONTROL | MOST, "Going to process transform of type %s",mapping_find(transform_type_m,transform_type));
380 switch (transform_type)
381 {
382 case ENCRYPTION_ALGORITHM:
383 {
384 this->logger->log(this->logger,CONTROL | MORE, "Encryption algorithm: %s",mapping_find(encryption_algorithm_m,transform_id));
385 selected_encryption_algorithm = transform_id;
386 break;
387 }
388 case PSEUDO_RANDOM_FUNCTION:
389 {
390 this->logger->log(this->logger,CONTROL | MORE, "Create transform object for PRF of type %s",mapping_find(pseudo_random_function_m,transform_id));
391 selected_pseudo_random_function = transform_id;
392 break;
393 }
394 case INTEGRITIY_ALGORITHM:
395 {
396 this->logger->log(this->logger,CONTROL | MORE, "Integrity algorithm: %s",mapping_find(integrity_algorithm_m,transform_id));
397 selected_integrity_algorithm = transform_id;
398 break;
399 }
400 case DIFFIE_HELLMAN_GROUP:
401 {
402 this->logger->log(this->logger,CONTROL | MORE, "DH Group: %s",mapping_find(diffie_hellman_group_m,transform_id));
403 break;
404 }
405 default:
406 {
407 this->logger->log(this->logger,ERROR | MORE, "Transform type not supported!");
408 transforms->destroy(transforms);
409 return FAILED;
410 }
411 }
412 }
413
414 transforms->destroy(transforms);
415
416 *encryption_algorithm = selected_encryption_algorithm;
417 *pseudo_random_function = selected_pseudo_random_function;
418 *integrity_algorithm = selected_integrity_algorithm;
419 return SUCCESS;
420 }
421
422 /**
423 * Implements function configuration_manager_t.is_dh_group_allowed_for_host.
424 */
425 static status_t is_dh_group_allowed_for_host(private_configuration_manager_t *this, host_t *host, diffie_hellman_group_t group, bool *allowed)
426 {
427 /*
428 * Only the two DH groups 768 and 1024 are supported for each configuration
429 */
430
431 if (group == MODP_768_BIT || group == MODP_1024_BIT)
432 {
433 *allowed = TRUE;
434 }
435 *allowed = FALSE;
436
437 this->logger->log(this->logger,CONTROL | MORE, "DH group %s is %s",mapping_find(diffie_hellman_group_m, group),(allowed)? "allowed" : "not allowed");
438 return SUCCESS;
439 }
440
441
442 /**
443 * Implements function destroy of configuration_t.
444 * See #configuration_s.destroy for description.
445 */
446 static status_t destroy(private_configuration_manager_t *this)
447 {
448 this->logger->log(this->logger,CONTROL | MORE, "Going to destroy configuration manager ");
449
450 this->logger->log(this->logger,CONTROL | MOST, "Destroy assigned logger");
451 global_logger_manager->destroy_logger(global_logger_manager,this->logger);
452 allocator_free(this);
453 return SUCCESS;
454 }
455
456 /*
457 * Described in header-file
458 */
459 configuration_manager_t *configuration_manager_create()
460 {
461 private_configuration_manager_t *this = allocator_alloc_thing(private_configuration_manager_t);
462
463 if (this == NULL)
464 {
465 return NULL;
466 }
467
468 /* public functions */
469 this->public.destroy = (status_t(*)(configuration_manager_t*))destroy;
470 this->public.get_remote_host = (status_t(*)(configuration_manager_t*,char*,host_t**))get_remote_host;
471 this->public.get_local_host = (status_t(*)(configuration_manager_t*,char*,host_t**))get_local_host;
472 this->public.get_dh_group_number = (status_t(*)(configuration_manager_t*,char*,u_int16_t *, u_int16_t))get_dh_group_number;
473 this->public.get_proposals_for_host = (status_t(*)(configuration_manager_t*,host_t*,iterator_t*))get_proposals_for_host;
474 this->public.select_proposals_for_host = (status_t(*)(configuration_manager_t*,host_t*,iterator_t*,iterator_t*))select_proposals_for_host;
475 this->public.get_transforms_for_host_and_proposals = (status_t (*) (configuration_manager_t *, host_t *, iterator_t *,encryption_algorithm_t *,pseudo_random_function_t *, integrity_algorithm_t *)) get_transforms_for_host_and_proposals;
476 this->public.is_dh_group_allowed_for_host = (status_t(*)(configuration_manager_t*,host_t*,diffie_hellman_group_t,bool*)) is_dh_group_allowed_for_host;
477
478 /* private variables */
479 this->logger = global_logger_manager->create_logger(global_logger_manager,CONFIGURATION_MANAGER,NULL);
480
481 if (this->logger == NULL)
482 {
483 allocator_free(this);
484 return NULL;
485 }
486
487 return (&this->public);
488 }