- process_configuration implemented
[strongswan.git] / Source / charon / ike_sa.c
1 /**
2 * @file ike_sa.c
3 *
4 * @brief Class ike_sa_t. An object of this type is managed by an
5 * ike_sa_manager_t object and represents an IKE_SA
6 *
7 */
8
9 /*
10 * Copyright (C) 2005 Jan Hutter, Martin Willi
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 */
23
24 #include "ike_sa.h"
25
26 #include "types.h"
27 #include "globals.h"
28 #include "definitions.h"
29 #include "utils/allocator.h"
30 #include "utils/linked_list.h"
31 #include "utils/logger_manager.h"
32 #include "utils/randomizer.h"
33 #include "transforms/diffie_hellman.h"
34 #include "payloads/sa_payload.h"
35 #include "payloads/nonce_payload.h"
36 #include "payloads/ke_payload.h"
37 #include "payloads/transform_substructure.h"
38 #include "payloads/transform_attribute.h"
39
40
41 /**
42 *
43 * This implementation supports only window size 1
44 */
45 #define WINDOW_SIZE 1
46
47 /**
48 * States in which a IKE_SA can actually be
49 */
50 typedef enum ike_sa_state_e ike_sa_state_t;
51
52 enum ike_sa_state_e {
53
54 /**
55 * IKE_SA is is not in a state
56 */
57 NO_STATE = 1,
58
59 /**
60 * A IKE_SA_INIT-message was sent: role initiator
61 */
62 IKE_SA_INIT_REQUESTED = 2,
63
64 /**
65 * A IKE_SA_INIT-message was replied: role responder
66 */
67 IKE_SA_INIT_RESPONDED = 3,
68
69 /**
70 * An IKE_AUTH-message was sent after a successful
71 * IKE_SA_INIT-exchange: role initiator
72 */
73 IKE_AUTH_REQUESTED = 4,
74
75 /**
76 * An IKE_AUTH-message was replied: role responder.
77 * In this state, all the informations for an IKE_SA
78 * and one CHILD_SA are known.
79 */
80 IKE_SA_INITIALIZED = 5
81 };
82
83 /**
84 * string mappings for ike_sa_state
85 */
86 mapping_t ike_sa_state_m[] = {
87 {NO_STATE, "NO_STATE"},
88 {IKE_SA_INIT_REQUESTED, "IKE_SA_INIT_REQUESTED"},
89 {IKE_SA_INIT_RESPONDED, "IKE_SA_INIT_RESPONDED"},
90 {IKE_AUTH_REQUESTED, "IKE_AUTH_REQUESTED"},
91 {IKE_SA_INITIALIZED, "IKE_SA_INITIALIZED"},
92 {MAPPING_END, NULL}
93 };
94
95
96 /**
97 * Private data of an message_t object
98 */
99 typedef struct private_ike_sa_s private_ike_sa_t;
100
101 struct private_ike_sa_s {
102
103 /**
104 * Public part of a ike_sa_t object
105 */
106 ike_sa_t public;
107
108 status_t (*build_sa_payload) (private_ike_sa_t *this, sa_payload_t **payload);
109 status_t (*build_ke_payload) (private_ike_sa_t *this, ke_payload_t **payload);
110 status_t (*build_nonce_payload) (private_ike_sa_t *this, nonce_payload_t **payload);
111
112 status_t (*build_message) (private_ike_sa_t *this, exchange_type_t type, bool request, message_t **message);
113
114
115 status_t (*transto_ike_sa_init_requested) (private_ike_sa_t *this, char *name);
116 status_t (*transto_ike_sa_init_responded) (private_ike_sa_t *this, message_t *message);
117 status_t (*transto_ike_auth_requested) (private_ike_sa_t *this, message_t *message);
118
119 /* Private values */
120 /**
121 * Identifier for the current IKE_SA
122 */
123 ike_sa_id_t *ike_sa_id;
124
125 /**
126 * Linked List containing the child sa's of the current IKE_SA
127 */
128 linked_list_t *child_sas;
129
130 /**
131 * Current state of the IKE_SA
132 */
133 ike_sa_state_t state;
134
135 /**
136 * this SA's source for random data
137 */
138 randomizer_t *randomizer;
139
140 /**
141 * contains the last X sent messages
142 *
143 * X is windows size (here 1)
144 */
145 linked_list_t *sent_messages;
146
147 struct {
148 host_t *host;
149 } me;
150
151 struct {
152 host_t *host;
153 } other;
154
155
156 struct {
157 /**
158 * Diffie Hellman object used to compute shared secret
159 */
160 diffie_hellman_t *diffie_hellman;
161 /**
162 * Diffie Hellman group number
163 */
164 u_int16_t dh_group_number;
165
166 /**
167 * Priority used get matching dh_group number
168 */
169 u_int16_t dh_group_priority;
170 /**
171 *
172 */
173 chunk_t sent_nonce;
174 /**
175 *
176 */
177 chunk_t received_nonce;
178 } ike_sa_init_data;
179
180
181 /**
182 * next message id to receive
183 */
184 u_int32_t message_id_in;
185
186 /**
187 * next message id to send
188 */
189 u_int32_t message_id_out;
190
191 /**
192 * a logger for this IKE_SA
193 */
194 logger_t *logger;
195 };
196
197 /**
198 * @brief implements function process_message of private_ike_sa_t
199 */
200 static status_t process_message (private_ike_sa_t *this, message_t *message)
201 {
202 u_int32_t message_id;
203 this->logger->log(this->logger, CONTROL|MORE, "Process message of exchange type %s",
204 mapping_find(exchange_type_m,message->get_exchange_type(message)));
205
206 /* check message id */
207
208 // message_id = message->get_message_id(message);
209 // if (message_id < (message_id_in - WINDOW_SIZE))
210 // {
211 // this->logger->log(this->logger, ERROR, "message cause of message id not handled");
212 // /* message is to old */
213 // return FAILED;
214 // }
215 // if (message_id > (message_id_in))
216 // {
217 // this->logger->log(this->logger, ERROR, "message id %d not as expected %d",message_id,message_id_in);
218 // /* message is to old */
219 // return FAILED;
220 // }
221 //
222 //
223 //
224 // message->get_exchange_type(message);
225
226
227 switch (message->get_exchange_type(message))
228 {
229 case IKE_SA_INIT:
230 {
231 if (message->get_request(message)) {
232 if (this->state == NO_STATE)
233 {
234 /* state transission NO_STATE => IKE_SA_INIT_RESPONDED */
235 return this->transto_ike_sa_init_responded(this, message);
236 }
237 }
238 else
239 {
240 if (this->state == IKE_SA_INIT_REQUESTED)
241 {
242 /* state transission IKE_SA_INIT_REQUESTED => IKE_AUTH_REQUESTED*/
243 return this->transto_ike_auth_requested(this, message);
244 }
245 }
246 break;
247 }
248 case IKE_AUTH:
249 {
250 /* break; */
251 }
252 case CREATE_CHILD_SA:
253 {
254 /* break; */
255 }
256 case INFORMATIONAL:
257 {
258 /* break; */
259 }
260 default:
261 {
262 this->logger->log(this->logger, ERROR, "processing %s-message not supported.",
263 mapping_find(exchange_type_m,message->get_exchange_type(message)));
264 return NOT_SUPPORTED;
265 }
266 }
267 this->logger->log(this->logger, ERROR, "received %s-message in state %s, rejected.",
268 mapping_find(exchange_type_m, message->get_exchange_type(message)),
269 mapping_find(ike_sa_state_m, this->state));
270 return INVALID_STATE;
271 }
272
273
274 static status_t build_message(private_ike_sa_t *this, exchange_type_t type, bool request, message_t **message)
275 {
276 status_t status;
277 message_t *new_message;
278 host_t *source, *destination;
279
280 new_message = message_create();
281 if (new_message == NULL)
282 {
283 return OUT_OF_RES;
284 }
285
286 status = this->me.host->clone(this->me.host, &source);
287 status |= this->other.host->clone(this->other.host, &destination);
288 if (status != SUCCESS)
289 {
290 new_message->destroy(new_message);
291 return status;
292 }
293 new_message->set_source(new_message, source);
294 new_message->set_destination(new_message, destination);
295
296 new_message->set_exchange_type(new_message, type);
297 new_message->set_request(new_message, request);
298
299 new_message->set_message_id(new_message, this->message_id_in);
300
301 new_message->set_ike_sa_id(new_message, this->ike_sa_id);
302
303 *message = new_message;
304
305 return SUCCESS;
306 }
307
308
309 static status_t transto_ike_sa_init_requested(private_ike_sa_t *this, char *name)
310 {
311 message_t *message;
312 payload_t *payload;
313 packet_t *packet;
314 status_t status;
315
316 this->logger->log(this->logger, CONTROL, "initializing connection");
317
318 status = global_configuration_manager->get_local_host(global_configuration_manager, name, &(this->me.host));
319 if (status != SUCCESS)
320 {
321 return INVALID_ARG;
322 }
323
324 status = global_configuration_manager->get_remote_host(global_configuration_manager, name, &(this->other.host));
325 if (status != SUCCESS)
326 {
327 return INVALID_ARG;
328 }
329
330 status = global_configuration_manager->get_dh_group_number(global_configuration_manager, name, &(this->ike_sa_init_data.dh_group_number), this->ike_sa_init_data.dh_group_priority);
331 if (status != SUCCESS)
332 {
333 return INVALID_ARG;
334 }
335
336 this ->logger->log(this->logger, CONTROL|MORE, "create diffie hellman object");
337 if (this->ike_sa_init_data.diffie_hellman != NULL)
338 {
339 this->logger->log(this->logger, ERROR, "Object of type diffie_hellman_t already existing!");
340 return FAILED;
341 }
342 this->ike_sa_init_data.diffie_hellman = diffie_hellman_create(this->ike_sa_init_data.dh_group_number);
343 if (this->ike_sa_init_data.diffie_hellman == NULL)
344 {
345 this->logger->log(this->logger, ERROR, "Object of type diffie_hellman_t could not be created!");
346 return FAILED;
347 }
348
349 if (this->ike_sa_init_data.sent_nonce.ptr != NULL)
350 {
351 this->logger->log(this->logger, ERROR, "Nonce for IKE_SA_INIT phase already existing!");
352 return FAILED;
353 }
354
355 if (this->randomizer->allocate_pseudo_random_bytes(this->randomizer, 16, &(this->ike_sa_init_data.sent_nonce)) != SUCCESS)
356 {
357 this->logger->log(this->logger, ERROR, "Could not create nonce!");
358 return OUT_OF_RES;
359 }
360
361
362 /* going to build message */
363
364 status = this->build_message(this, IKE_SA_INIT, TRUE, &message);
365 if (status != SUCCESS)
366 {
367 this->logger->log(this->logger, ERROR, "Could not build message");
368 return status;
369 }
370
371 /* build SA payload */
372 status = this->build_sa_payload(this, (sa_payload_t**)&payload);
373 if (status != SUCCESS)
374 {
375 this->logger->log(this->logger, ERROR, "Could not build SA payload");
376 message->destroy(message);
377 return status;
378 }
379 message->add_payload(message, payload);
380
381 /* build KE payload */
382 status = this->build_ke_payload(this,(ke_payload_t **) &payload);
383 if (status != SUCCESS)
384 {
385 this->logger->log(this->logger, ERROR, "Could not build KE payload");
386 message->destroy(message);
387 return status;
388 }
389 message->add_payload(message, payload);
390
391 /* build Nonce payload */
392 status = this->build_nonce_payload(this, (nonce_payload_t**)&payload);
393 if (status != SUCCESS)
394 {
395 this->logger->log(this->logger, ERROR, "Could not build NONCE payload");
396 message->destroy(message);
397 return status;
398 }
399 message->add_payload(message, payload);
400
401
402 status = message->generate(message, &packet);
403 if (status != SUCCESS)
404 {
405 this->logger->log(this->logger, ERROR, "Could not generate message");
406 message->destroy(message);
407 return status;
408 }
409
410 status = global_send_queue->add(global_send_queue, packet);
411 if (status != SUCCESS)
412 {
413 this->logger->log(this->logger, ERROR, "Could not add packet to send queue");
414 message->destroy(message);
415 return status;
416 }
417
418 if ( this->sent_messages->get_count(this->sent_messages) >= WINDOW_SIZE)
419 {
420 message_t *removed_message;
421 /* destroy message */
422 this->sent_messages->remove_last(this->sent_messages,(void **)&removed_message);
423 removed_message->destroy(removed_message);
424 }
425
426 status = this->sent_messages->insert_first(this->sent_messages,(void *) message);
427 if (status != SUCCESS)
428 {
429 this->logger->log(this->logger, ERROR, "Could not store last received message");
430 message->destroy(message);
431 return status;
432 }
433
434 /* message counter can no be increased */
435 this->message_id_in++;
436
437 /* states has NOW changed :-) */
438 this->state = IKE_SA_INIT_REQUESTED;
439
440 return SUCCESS;
441 }
442
443 static status_t transto_ike_sa_init_responded(private_ike_sa_t *this, message_t *message)
444 {
445 status_t status;
446 linked_list_iterator_t *payloads;
447 message_t *respond;
448
449 status = message->parse_body(message);
450 if (status != SUCCESS)
451 {
452 return status;
453 }
454
455
456
457
458
459 status = message->get_payload_iterator(message, &payloads);
460 if (status != SUCCESS)
461 {
462 respond->destroy(respond);
463 return status;
464 }
465 while (payloads->has_next(payloads))
466 {
467 payload_t *payload;
468 payloads->current(payloads, (void**)payload);
469 switch (payload->get_type(payload))
470 {
471 case SECURITY_ASSOCIATION:
472 {
473 sa_payload_t *sa_payload;
474 linked_list_iterator_t *proposals;
475
476 sa_payload = (sa_payload_t*)payload;
477 status = sa_payload->create_proposal_substructure_iterator(sa_payload, &proposals, TRUE);
478 if (status != SUCCESS)
479 {
480 payloads->destroy(payloads);
481 return status;
482 }
483 //global_configuration_manager->select_proposals_for_host
484
485 break;
486 }
487 case KEY_EXCHANGE:
488 {
489 break;
490 }
491 case NONCE:
492 {
493 break;
494 }
495 default:
496 {
497
498 }
499
500 }
501
502 }
503
504
505
506
507
508 /*
509 job_t *delete_job;
510 delete_job = (job_t *) delete_ike_sa_job_create(this->ike_sa_id);
511 if (delete_job == NULL)
512 {
513 this->logger->log(this->logger, ERROR, "Job to delete IKE SA could not be created");
514 }
515
516 status = global_job_queue->add(global_job_queue,delete_job);
517 if (status != SUCCESS)
518 {
519 this->logger->log(this->logger, ERROR, "%s Job to delete IKE SA could not be added to job queue",mapping_find(status_m,status));
520 delete_job->destroy_all(delete_job);
521 }*/
522 return SUCCESS;
523 }
524
525 static status_t transto_ike_auth_requested(private_ike_sa_t *this, message_t *message)
526 {
527 return SUCCESS;
528 }
529
530 /**
531 * @brief implements function process_configuration of private_ike_sa_t
532 */
533 static status_t initialize_connection(private_ike_sa_t *this, char *name)
534 {
535 /* work is done in transto_ike_sa_init_requested */
536 return (this->transto_ike_sa_init_requested(this,name));
537 }
538
539 /**
540 * @brief implements function private_ike_sa_t.get_id
541 */
542 static ike_sa_id_t* get_id(private_ike_sa_t *this)
543 {
544 return this->ike_sa_id;
545 }
546
547 /**
548 * implements private_ike_sa_t.build_sa_payload
549 */
550 static status_t build_sa_payload(private_ike_sa_t *this, sa_payload_t **payload)
551 {
552 sa_payload_t* sa_payload;
553 linked_list_iterator_t *iterator;
554 status_t status;
555
556 this->logger->log(this->logger, CONTROL|MORE, "building sa payload");
557
558 sa_payload = sa_payload_create();
559 if (sa_payload == NULL)
560 {
561 return OUT_OF_RES;
562 }
563 status = sa_payload->create_proposal_substructure_iterator(sa_payload, &iterator, FALSE);
564 if (status != SUCCESS)
565 {
566 sa_payload->destroy(sa_payload);
567 return status;
568 }
569 status = global_configuration_manager->get_proposals_for_host(global_configuration_manager, this->other.host, iterator);
570 if (status != SUCCESS)
571 {
572 sa_payload->destroy(sa_payload);
573 return status;
574 }
575
576 *payload = sa_payload;
577
578 return SUCCESS;
579 }
580
581 static status_t build_ke_payload(private_ike_sa_t *this, ke_payload_t **payload)
582 {
583 ke_payload_t *ke_payload;
584 chunk_t key_data;
585 status_t status;
586
587 this->logger->log(this->logger, CONTROL|MORE, "building ke payload");
588
589 if (this->state != NO_STATE)
590 {
591 this->logger->log(this->logger, ERROR, "KE payload in state %s not supported",mapping_find(ike_sa_state_m,this->state));
592 return FALSE;
593 }
594
595 switch(this->ike_sa_id->is_initiator(this->ike_sa_id))
596 {
597 case TRUE:
598 {
599 this ->logger->log(this->logger, CONTROL|MORE, "get public dh value to send in ke payload");
600 status = this->ike_sa_init_data.diffie_hellman->get_my_public_value(this->ike_sa_init_data.diffie_hellman,&key_data);
601 if (status != SUCCESS)
602 {
603 this->logger->log(this->logger, ERROR, "Could not get my DH public value");
604 return status;
605 }
606
607 ke_payload = ke_payload_create();
608 if (ke_payload == NULL)
609 {
610 this->logger->log(this->logger, ERROR, "Could not create KE payload");
611 allocator_free_chunk(key_data);
612 return OUT_OF_RES;
613 }
614 ke_payload->set_dh_group_number(ke_payload, MODP_1024_BIT);
615 if (ke_payload->set_key_exchange_data(ke_payload, key_data) != SUCCESS)
616 {
617 this->logger->log(this->logger, ERROR, "Could not set key exchange data of KE payload");
618 ke_payload->destroy(ke_payload);
619 allocator_free_chunk(key_data);
620 return OUT_OF_RES;
621 }
622 allocator_free_chunk(key_data);
623
624 *payload = ke_payload;
625 return SUCCESS;
626 }
627 default: /* FALSE */
628 {
629 break;
630 }
631 }
632
633 return FAILED;
634 }
635
636 /**
637 * implements private_ike_sa_t.build_nonce_payload
638 */
639 static status_t build_nonce_payload(private_ike_sa_t *this, nonce_payload_t **payload)
640 {
641 nonce_payload_t *nonce_payload;
642
643 this->logger->log(this->logger, CONTROL|MORE, "building nonce payload");
644 nonce_payload = nonce_payload_create();
645 if (nonce_payload == NULL)
646 {
647 return OUT_OF_RES;
648 }
649
650 nonce_payload->set_nonce(nonce_payload, this->ike_sa_init_data.sent_nonce);
651
652 *payload = nonce_payload;
653
654 return SUCCESS;
655 }
656
657 /**
658 * @brief implements function destroy of private_ike_sa_t
659 */
660 static status_t destroy (private_ike_sa_t *this)
661 {
662 /* destroy child sa's */
663 while (this->child_sas->get_count(this->child_sas) > 0)
664 {
665 void *child_sa;
666 if (this->child_sas->remove_first(this->child_sas,&child_sa) != SUCCESS)
667 {
668 break;
669 }
670 /* destroy child sa */
671 }
672 this->child_sas->destroy(this->child_sas);
673
674 /* destroy ike_sa_id */
675 this->ike_sa_id->destroy(this->ike_sa_id);
676
677 /* destroy stored sent messages */
678 while (this->sent_messages->get_count(this->sent_messages) > 0)
679 {
680 message_t *message;
681 if (this->sent_messages->remove_first(this->sent_messages,(void **) &message) != SUCCESS)
682 {
683 break;
684 }
685 message->destroy(message);
686 }
687 this->sent_messages->destroy(this->sent_messages);
688
689 this->randomizer->destroy(this->randomizer);
690 if (this->ike_sa_init_data.diffie_hellman != NULL)
691 {
692 this->ike_sa_init_data.diffie_hellman->destroy(this->ike_sa_init_data.diffie_hellman);
693 }
694 if (this->ike_sa_init_data.sent_nonce.ptr != NULL)
695 {
696 allocator_free_chunk(this->ike_sa_init_data.sent_nonce);
697 }
698 if (this->ike_sa_init_data.received_nonce.ptr != NULL)
699 {
700 allocator_free_chunk(this->ike_sa_init_data.received_nonce);
701 }
702
703 global_logger_manager->destroy_logger(global_logger_manager, this->logger);
704
705 allocator_free(this);
706
707 return SUCCESS;
708 }
709
710 /*
711 * Described in Header
712 */
713 ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
714 {
715 private_ike_sa_t *this = allocator_alloc_thing(private_ike_sa_t);
716 if (this == NULL)
717 {
718 return NULL;
719 }
720
721
722 /* Public functions */
723 this->public.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message;
724 this->public.initialize_connection = (status_t(*)(ike_sa_t*, char*)) initialize_connection;
725 this->public.get_id = (ike_sa_id_t*(*)(ike_sa_t*)) get_id;
726 this->public.destroy = (status_t(*)(ike_sa_t*))destroy;
727
728 /* private functions */
729 this->build_sa_payload = build_sa_payload;
730 this->build_nonce_payload = build_nonce_payload;
731 this->build_ke_payload = build_ke_payload;
732 this->build_message = build_message;
733 this->transto_ike_sa_init_requested = transto_ike_sa_init_requested;
734 this->transto_ike_sa_init_responded = transto_ike_sa_init_responded;
735 this->transto_ike_auth_requested = transto_ike_auth_requested;
736
737
738
739 /* initialize private fields */
740 if (ike_sa_id->clone(ike_sa_id,&(this->ike_sa_id)) != SUCCESS)
741 {
742 allocator_free(this);
743 return NULL;
744 }
745 this->child_sas = linked_list_create();
746 if (this->child_sas == NULL)
747 {
748 this->ike_sa_id->destroy(this->ike_sa_id);
749 allocator_free(this);
750 return NULL;
751 }
752 this->randomizer = randomizer_create();
753 if (this->randomizer == NULL)
754 {
755 this->child_sas->destroy(this->child_sas);
756 this->ike_sa_id->destroy(this->ike_sa_id);
757 allocator_free(this);
758 }
759 this->sent_messages = linked_list_create();
760 if (this->sent_messages == NULL)
761 {
762 this->randomizer->destroy(this->randomizer);
763 this->child_sas->destroy(this->child_sas);
764 this->ike_sa_id->destroy(this->ike_sa_id);
765 allocator_free(this);
766 }
767 this->logger = global_logger_manager->create_logger(global_logger_manager, IKE_SA, NULL);
768 if (this->logger == NULL)
769 {
770 this->randomizer->destroy(this->randomizer);
771 this->child_sas->destroy(this->child_sas);
772 this->ike_sa_id->destroy(this->ike_sa_id);
773 this->sent_messages->destroy(this->sent_messages);
774 allocator_free(this);
775 }
776
777 this->me.host = NULL;
778 this->other.host = NULL;
779 this->ike_sa_init_data.diffie_hellman = NULL;
780 this->ike_sa_init_data.dh_group_number = 0;
781 /* 1 means highest priority */
782 this->ike_sa_init_data.dh_group_priority = 1;
783 this->ike_sa_init_data.sent_nonce.len = 0;
784 this->ike_sa_init_data.sent_nonce.ptr = NULL;
785 this->ike_sa_init_data.received_nonce.len = 0;
786 this->ike_sa_init_data.received_nonce.ptr = NULL;
787 this->message_id_out = 0;
788 this->message_id_in = 0;
789
790
791 /* at creation time, IKE_SA isn't in a specific state */
792 this->state = NO_STATE;
793
794 return (&this->public);
795 }