- implemented until state change
[strongswan.git] / Source / charon / states / responder_init.c
1 /**
2 * @file responder_init.c
3 *
4 * @brief Start state of a IKE_SA as responder
5 *
6 */
7
8 /*
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include "responder_init.h"
24
25 #include "ike_sa_init_responded.h"
26 #include "../globals.h"
27 #include "../utils/allocator.h"
28 #include "../payloads/sa_payload.h"
29 #include "../payloads/ke_payload.h"
30 #include "../payloads/nonce_payload.h"
31 #include "../transforms/diffie_hellman.h"
32
33 /**
34 * Private data of a responder_init_t object.
35 *
36 */
37 typedef struct private_responder_init_s private_responder_init_t;
38 struct private_responder_init_s {
39 /**
40 * Methods of the state_t interface.
41 */
42 responder_init_t public;
43
44 /**
45 * Assigned IKE_SA.
46 */
47 protected_ike_sa_t *ike_sa;
48
49 /**
50 * Diffie Hellman object used to compute shared secret.
51 *
52 * After processing of incoming IKE_SA_INIT-Request the shared key is
53 * passed to the next state of type ike_sa_init_responded_t.
54 */
55 diffie_hellman_t *diffie_hellman;
56
57 /**
58 * Diffie Hellman group number.
59 */
60 u_int16_t dh_group_number;
61
62 /**
63 * Priority used to get matching dh_group number.
64 */
65 u_int16_t dh_group_priority;
66
67 /**
68 * Sent nonce value.
69 *
70 * This value is passed to the next state of type ike_sa_init_responded_t.
71 */
72 chunk_t sent_nonce;
73
74 /**
75 * Received nonce value
76 *
77 * This value is passed to the next state of type ike_sa_init_responded_t.
78 */
79 chunk_t received_nonce;
80
81 /**
82 * Logger used to log data
83 *
84 * Is logger of ike_sa!
85 */
86 logger_t *logger;
87
88 /**
89 * Proposals used to initiate connection
90 */
91 linked_list_t *proposals;
92
93 /**
94 * Builds the SA payload for this state.
95 *
96 * @param this calling object
97 * @param payload The generated SA payload object of type ke_payload_t is
98 * stored at this location.
99 * @return
100 * - SUCCESS
101 * - OUT_OF_RES
102 */
103 status_t (*build_sa_payload) (private_responder_init_t *this, payload_t **payload);
104
105 /**
106 * Builds the KE payload for this state.
107 *
108 * @param this calling object
109 * @param payload The generated KE payload object of type ke_payload_t is
110 * stored at this location.
111 * @return
112 * - SUCCESS
113 * - OUT_OF_RES
114 */
115 status_t (*build_ke_payload) (private_responder_init_t *this, payload_t **payload);
116 /**
117 * Builds the NONCE payload for this state.
118 *
119 * @param this calling object
120 * @param payload The generated NONCE payload object of type ke_payload_t is
121 * stored at this location.
122 * @return
123 * - SUCCESS
124 * - OUT_OF_RES
125 */
126 status_t (*build_nonce_payload) (private_responder_init_t *this, payload_t **payload);
127
128 /**
129 * Destroy function called internally of this class after state change succeeded.
130 *
131 * This destroy function does not destroy objects which were passed to the new state.
132 *
133 * @param this calling object
134 * @return SUCCESS in any case
135 */
136 status_t (*destroy_after_state_change) (private_responder_init_t *this);
137 };
138
139 /**
140 * Implements state_t.get_state
141 */
142 static status_t process_message(private_responder_init_t *this, message_t *message, state_t **new_state)
143 {
144 linked_list_iterator_t *payloads;
145 host_t *source, *destination;
146 status_t status;
147 message_t *response;
148 payload_t *payload;
149 packet_t *packet;
150 chunk_t shared_secret;
151 exchange_type_t exchange_type;
152 ike_sa_init_responded_t *next_state;
153
154 exchange_type = message->get_exchange_type(message);
155 if (exchange_type != IKE_SA_INIT)
156 {
157 this->logger->log(this->logger, ERROR | MORE, "Message of type %s not supported in state responder_init",mapping_find(exchange_type_m,exchange_type));
158 return FAILED;
159 }
160
161 if (!message->get_request(message))
162 {
163 this->logger->log(this->logger, ERROR | MORE, "Only requests of type IKE_SA_INIT supported in state responder_init");
164 return FAILED;
165 }
166
167 /* this is the first message we process, so copy host infos */
168 message->get_source(message, &source);
169 message->get_destination(message, &destination);
170
171 /* we need to clone them, since we destroy the message later */
172 destination->clone(destination, &(this->ike_sa->me.host));
173 source->clone(source, &(this->ike_sa->other.host));
174
175 /* parse incoming message */
176 status = message->parse_body(message);
177 if (status != SUCCESS)
178 {
179 this->logger->log(this->logger, ERROR | MORE, "Could not parse body of request message");
180 return status;
181 }
182
183 /* iterate over incoming payloads. We can be sure, the message contains only accepted payloads! */
184 status = message->get_payload_iterator(message, &payloads);
185 if (status != SUCCESS)
186 {
187 this->logger->log(this->logger, ERROR, "Fatal error: Could not get payload interator");
188 return status;
189 }
190
191 while (payloads->has_next(payloads))
192 {
193 payload_t *payload;
194
195 /* get current payload */
196 payloads->current(payloads, (void**)&payload);
197
198 this->logger->log(this->logger, CONTROL|MORE, "Processing payload of type %s", mapping_find(payload_type_m, payload->get_type(payload)));
199 switch (payload->get_type(payload))
200 {
201 case SECURITY_ASSOCIATION:
202 {
203 sa_payload_t *sa_payload = (sa_payload_t*)payload;
204 linked_list_iterator_t *suggested_proposals, *accepted_proposals;
205
206 status = this->proposals->create_iterator(this->proposals, &accepted_proposals, FALSE);
207 if (status != SUCCESS)
208 {
209 this->logger->log(this->logger, ERROR, "Fatal error: Could not create iterator on list for proposals");
210 payloads->destroy(payloads);
211 return status;
212 }
213
214 /* get the list of suggested proposals */
215 status = sa_payload->create_proposal_substructure_iterator(sa_payload, &suggested_proposals, TRUE);
216 if (status != SUCCESS)
217 {
218 this->logger->log(this->logger, ERROR, "Fatal error: Could not create iterator on suggested proposals");
219 accepted_proposals->destroy(accepted_proposals);
220 payloads->destroy(payloads);
221 return status;
222 }
223
224 /* now let the configuration-manager select a subset of the proposals */
225 status = global_configuration_manager->select_proposals_for_host(global_configuration_manager,
226 this->ike_sa->other.host, suggested_proposals, accepted_proposals);
227 if (status != SUCCESS)
228 {
229 this->logger->log(this->logger, CONTROL | MORE, "No proposal of suggested proposals selected");
230 suggested_proposals->destroy(suggested_proposals);
231 accepted_proposals->destroy(accepted_proposals);
232 payloads->destroy(payloads);
233 return status;
234 }
235
236 /* iterators are not needed anymore */
237 suggested_proposals->destroy(suggested_proposals);
238 accepted_proposals->destroy(accepted_proposals);
239
240 this->logger->log(this->logger, CONTROL | MORE, "SA Payload processed");
241 /* ok, we have what we need for sa_payload (proposals are stored in this->proposals)*/
242 break;
243 }
244 case KEY_EXCHANGE:
245 {
246 ke_payload_t *ke_payload = (ke_payload_t*)payload;
247 diffie_hellman_group_t group;
248 diffie_hellman_t *dh;
249 bool allowed_group;
250
251 group = ke_payload->get_dh_group_number(ke_payload);
252
253 status = global_configuration_manager->is_dh_group_allowed_for_host(global_configuration_manager,
254 this->ike_sa->other.host, group, &allowed_group);
255
256 if (status != SUCCESS)
257 {
258 this->logger->log(this->logger, ERROR | MORE, "Could not get informations about DH group");
259 payloads->destroy(payloads);
260 return status;
261 }
262 if (!allowed_group)
263 {
264 /** @todo Send info reply */
265 }
266
267 /* create diffie hellman object to handle DH exchange */
268 dh = diffie_hellman_create(group);
269 if (dh == NULL)
270 {
271 this->logger->log(this->logger, ERROR, "Could not generate DH object");
272 payloads->destroy(payloads);
273 return OUT_OF_RES;
274 }
275
276 this->logger->log(this->logger, CONTROL | MORE, "Set other DH public value");
277
278 status = dh->set_other_public_value(dh, ke_payload->get_key_exchange_data(ke_payload));
279 if (status != SUCCESS)
280 {
281 this->logger->log(this->logger, ERROR, "Could not set other DH public value");
282 dh->destroy(dh);
283 payloads->destroy(payloads);
284 return OUT_OF_RES;
285 }
286
287 this->diffie_hellman = dh;
288
289 this->logger->log(this->logger, CONTROL | MORE, "KE Payload processed");
290 break;
291 }
292 case NONCE:
293 {
294 nonce_payload_t *nonce_payload = (nonce_payload_t*)payload;
295
296 if (this->received_nonce.ptr != NULL)
297 {
298 this->logger->log(this->logger, CONTROL | MOST, "Destroy stored received nonce");
299 allocator_free(this->received_nonce.ptr);
300 this->received_nonce.ptr = NULL;
301 this->received_nonce.len = 0;
302 }
303
304 this->logger->log(this->logger, CONTROL | MORE, "Get nonce value and store it");
305 status = nonce_payload->get_nonce(nonce_payload, &(this->received_nonce));
306 if (status != SUCCESS)
307 {
308 this->logger->log(this->logger, ERROR, "Fatal error: Could not get nonce");
309 payloads->destroy(payloads);
310 return OUT_OF_RES;
311 }
312
313 this->logger->log(this->logger, CONTROL | MORE, "Nonce Payload processed");
314 break;
315 }
316 default:
317 {
318 this->logger->log(this->logger, ERROR | MORE, "Payload type not supported!");
319 payloads->destroy(payloads);
320 return OUT_OF_RES;
321 }
322
323 }
324
325 }
326 /* iterator can be destroyed */
327 payloads->destroy(payloads);
328
329 this->logger->log(this->logger, CONTROL | MORE, "Request successfully handled. Going to create reply.");
330
331 this->logger->log(this->logger, CONTROL | MOST, "Going to create nonce.");
332 if (this->ike_sa->randomizer->allocate_pseudo_random_bytes(this->ike_sa->randomizer, NONCE_SIZE, &(this->sent_nonce)) != SUCCESS)
333 {
334 this->logger->log(this->logger, ERROR, "Could not create nonce!");
335 return OUT_OF_RES;
336 }
337
338
339 /* set up the reply */
340 status = this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, FALSE, &response);
341 if (status != SUCCESS)
342 {
343 this->logger->log(this->logger, ERROR, "Could not create empty message");
344 return status;
345 }
346
347 /* build SA payload */
348 status = this->build_sa_payload(this, &payload);
349 if (status != SUCCESS)
350 {
351 this->logger->log(this->logger, ERROR, "Could not build SA payload");
352 return status;
353 }
354
355 this ->logger->log(this->logger, CONTROL|MOST, "add SA payload to message");
356 status = response->add_payload(response, payload);
357 if (status != SUCCESS)
358 {
359 this->logger->log(this->logger, ERROR, "Could not add SA payload to message");
360 return status;
361 }
362
363 /* build KE payload */
364 status = this->build_ke_payload(this,&payload);
365 if (status != SUCCESS)
366 {
367 this->logger->log(this->logger, ERROR, "Could not build KE payload");
368 return status;
369 }
370
371 this ->logger->log(this->logger, CONTROL|MOST, "add KE payload to message");
372 status = response->add_payload(response, payload);
373 if (status != SUCCESS)
374 {
375 this->logger->log(this->logger, ERROR, "Could not add KE payload to message");
376 return status;
377 }
378
379 /* build Nonce payload */
380 status = this->build_nonce_payload(this, &payload);
381 if (status != SUCCESS)
382 {
383 this->logger->log(this->logger, ERROR, "Could not build NONCE payload");
384 return status;
385 }
386
387 this ->logger->log(this->logger, CONTROL|MOST, "add nonce payload to message");
388 status = response->add_payload(response, payload);
389 if (status != SUCCESS)
390 {
391 this->logger->log(this->logger, ERROR, "Could not add nonce payload to message");
392 return status;
393 }
394
395 /* generate packet */
396 this ->logger->log(this->logger, CONTROL|MOST, "generate packet from message");
397 status = response->generate(response, &packet);
398 if (status != SUCCESS)
399 {
400 this->logger->log(this->logger, ERROR, "Fatal error: could not generate packet from message");
401 return status;
402 }
403
404 this ->logger->log(this->logger, CONTROL|MOST, "Add packet to global send queue");
405 status = global_send_queue->add(global_send_queue, packet);
406 if (status != SUCCESS)
407 {
408 this->logger->log(this->logger, ERROR, "Could not add packet to send queue");
409 return status;
410 }
411
412 status = this->diffie_hellman->get_shared_secret(this->diffie_hellman, &shared_secret);
413 this->logger->log_chunk(this->logger, PRIVATE, "Shared secret", &shared_secret);
414
415
416 /* state can now be changed */
417 this ->logger->log(this->logger, CONTROL|MOST, "Create next state object");
418
419 next_state = ike_sa_init_responded_create(this->ike_sa, shared_secret, this->received_nonce, this->sent_nonce);
420
421 if (next_state == NULL)
422 {
423 this ->logger->log(this->logger, ERROR, "Fatal error: could not create next state object of type ike_sa_init_responded_t");
424 allocator_free_chunk(shared_secret);
425 return FAILED;
426 }
427
428 if ( this->ike_sa->last_responded_message != NULL)
429 {
430 /* destroy message */
431 this ->logger->log(this->logger, CONTROL|MOST, "Destroy stored last responded message");
432 this->ike_sa->last_responded_message->destroy(this->ike_sa->last_responded_message);
433 }
434 this->ike_sa->last_responded_message = response;
435
436 /* message counter can now be increased */
437 this ->logger->log(this->logger, CONTROL|MOST, "Increate message counter for incoming messages");
438 this->ike_sa->message_id_in++;
439
440 *new_state = (state_t *) next_state;
441 /* state has NOW changed :-) */
442 this ->logger->log(this->logger, CONTROL|MORE, "Changed state of IKE_SA from %s to %s",mapping_find(ike_sa_state_m,RESPONDER_INIT),mapping_find(ike_sa_state_m,IKE_SA_INIT_RESPONDED) );
443
444 this ->logger->log(this->logger, CONTROL|MOST, "Destroy old sate object");
445 this->destroy_after_state_change(this);
446
447 return SUCCESS;
448 }
449
450 /**
451 * implements private_initiator_init_t.build_sa_payload
452 */
453 static status_t build_sa_payload(private_responder_init_t *this, payload_t **payload)
454 {
455 sa_payload_t* sa_payload;
456 linked_list_iterator_t *proposal_iterator;
457 status_t status;
458
459
460 /* SA payload takes proposals from this->ike_sa_init_data.proposals and writes them to the created sa_payload */
461
462 this->logger->log(this->logger, CONTROL|MORE, "building sa payload");
463
464 status = this->proposals->create_iterator(this->proposals, &proposal_iterator, FALSE);
465 if (status != SUCCESS)
466 {
467 this->logger->log(this->logger, ERROR, "Fatal error: Could not create iterator on list for proposals");
468 return status;
469 }
470
471 sa_payload = sa_payload_create();
472 if (sa_payload == NULL)
473 {
474 this->logger->log(this->logger, ERROR, "Fatal error: Could not create SA payload object");
475 return OUT_OF_RES;
476 }
477
478 while (proposal_iterator->has_next(proposal_iterator))
479 {
480 proposal_substructure_t *current_proposal;
481 proposal_substructure_t *current_proposal_clone;
482 status = proposal_iterator->current(proposal_iterator,(void **) &current_proposal);
483 if (status != SUCCESS)
484 {
485 this->logger->log(this->logger, ERROR, "Could not get current proposal needed to copy");
486 proposal_iterator->destroy(proposal_iterator);
487 sa_payload->destroy(sa_payload);
488 return status;
489 }
490 status = current_proposal->clone(current_proposal,&current_proposal_clone);
491 if (status != SUCCESS)
492 {
493 this->logger->log(this->logger, ERROR, "Could not clone current proposal");
494 proposal_iterator->destroy(proposal_iterator);
495 sa_payload->destroy(sa_payload);
496 return status;
497 }
498
499 status = sa_payload->add_proposal_substructure(sa_payload,current_proposal_clone);
500 if (status != SUCCESS)
501 {
502 this->logger->log(this->logger, ERROR, "Could not add cloned proposal to SA payload");
503 proposal_iterator->destroy(proposal_iterator);
504 sa_payload->destroy(sa_payload);
505 return status;
506 }
507
508 }
509
510 proposal_iterator->destroy(proposal_iterator);
511
512 this->logger->log(this->logger, CONTROL|MORE, "sa payload builded");
513
514 *payload = (payload_t *) sa_payload;
515
516 return SUCCESS;
517 }
518
519 /**
520 * implements private_initiator_init_t.build_ke_payload
521 */
522 static status_t build_ke_payload(private_responder_init_t *this, payload_t **payload)
523 {
524 ke_payload_t *ke_payload;
525 chunk_t key_data;
526 status_t status;
527
528 this->logger->log(this->logger, CONTROL|MORE, "building ke payload");
529
530
531 this ->logger->log(this->logger, CONTROL|MORE, "get public dh value to send in ke payload");
532 status = this->diffie_hellman->get_my_public_value(this->diffie_hellman,&key_data);
533 if (status != SUCCESS)
534 {
535 this->logger->log(this->logger, ERROR, "Could not get my DH public value");
536 return status;
537 }
538
539 ke_payload = ke_payload_create();
540 if (ke_payload == NULL)
541 {
542 this->logger->log(this->logger, ERROR, "Could not create KE payload");
543 allocator_free_chunk(key_data);
544 return OUT_OF_RES;
545 }
546 ke_payload->set_dh_group_number(ke_payload, MODP_1024_BIT);
547 if (ke_payload->set_key_exchange_data(ke_payload, key_data) != SUCCESS)
548 {
549 this->logger->log(this->logger, ERROR, "Could not set key exchange data of KE payload");
550 ke_payload->destroy(ke_payload);
551 allocator_free_chunk(key_data);
552 return OUT_OF_RES;
553 }
554 allocator_free_chunk(key_data);
555
556 *payload = (payload_t *) ke_payload;
557 return SUCCESS;
558 }
559
560 /**
561 * implements private_initiator_init_t.build_nonce_payload
562 */
563 static status_t build_nonce_payload(private_responder_init_t *this, payload_t **payload)
564 {
565 nonce_payload_t *nonce_payload;
566 status_t status;
567
568 this->logger->log(this->logger, CONTROL|MORE, "building nonce payload");
569
570 nonce_payload = nonce_payload_create();
571 if (nonce_payload == NULL)
572 {
573 this->logger->log(this->logger, ERROR, "Fatal error: could not create nonce payload object");
574 return OUT_OF_RES;
575 }
576
577 status = nonce_payload->set_nonce(nonce_payload, this->sent_nonce);
578
579 if (status != SUCCESS)
580 {
581 this->logger->log(this->logger, ERROR, "Fatal error: could not set nonce data of payload");
582 nonce_payload->destroy(nonce_payload);
583 return status;
584 }
585
586 *payload = (payload_t *) nonce_payload;
587
588 return SUCCESS;
589 }
590
591
592 /**
593 * Implements state_t.get_state
594 */
595 static ike_sa_state_t get_state(private_responder_init_t *this)
596 {
597 return RESPONDER_INIT;
598 }
599
600 /**
601 * Implements state_t.get_state
602 */
603 static status_t destroy(private_responder_init_t *this)
604 {
605 this->logger->log(this->logger, CONTROL | MORE, "Going to destroy responder init state object");
606
607 /* destroy stored proposal */
608 this->logger->log(this->logger, CONTROL | MOST, "Destroy stored proposals");
609 while (this->proposals->get_count(this->proposals) > 0)
610 {
611 proposal_substructure_t *current_proposal;
612 this->proposals->remove_first(this->proposals,(void **)&current_proposal);
613 current_proposal->destroy(current_proposal);
614 }
615 this->proposals->destroy(this->proposals);
616
617 if (this->sent_nonce.ptr != NULL)
618 {
619 this->logger->log(this->logger, CONTROL | MOST, "Destroy sent nonce");
620 allocator_free(this->sent_nonce.ptr);
621 }
622
623 if (this->received_nonce.ptr != NULL)
624 {
625 this->logger->log(this->logger, CONTROL | MOST, "Destroy received nonce");
626 allocator_free(this->received_nonce.ptr);
627 }
628
629 /* destroy diffie hellman object */
630 if (this->diffie_hellman != NULL)
631 {
632 this->logger->log(this->logger, CONTROL | MOST, "Destroy diffie_hellman_t object");
633 this->diffie_hellman->destroy(this->diffie_hellman);
634 }
635
636 allocator_free(this);
637
638 return SUCCESS;
639
640 }
641
642 /**
643 * Implements private_responder_init_t.destroy_after_state_change
644 */
645 static status_t destroy_after_state_change (private_responder_init_t *this)
646 {
647 this->logger->log(this->logger, CONTROL | MORE, "Going to destroy responder_init_t state object");
648
649 /* destroy stored proposal */
650 this->logger->log(this->logger, CONTROL | MOST, "Destroy stored proposals");
651 while (this->proposals->get_count(this->proposals) > 0)
652 {
653 proposal_substructure_t *current_proposal;
654 this->proposals->remove_first(this->proposals,(void **)&current_proposal);
655 current_proposal->destroy(current_proposal);
656 }
657 this->proposals->destroy(this->proposals);
658
659 /* destroy diffie hellman object */
660 if (this->diffie_hellman != NULL)
661 {
662 this->logger->log(this->logger, CONTROL | MOST, "Destroy diffie_hellman_t object");
663 this->diffie_hellman->destroy(this->diffie_hellman);
664 }
665
666 allocator_free(this);
667 return SUCCESS;
668 }
669
670 /*
671 * Described in header.
672 */
673 responder_init_t *responder_init_create(protected_ike_sa_t *ike_sa)
674 {
675 private_responder_init_t *this = allocator_alloc_thing(private_responder_init_t);
676
677 if (this == NULL)
678 {
679 return NULL;
680 }
681
682 /* interface functions */
683 this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *,state_t **)) process_message;
684 this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
685 this->public.state_interface.destroy = (status_t (*) (state_t *)) destroy;
686
687 /* private functions */
688 this->build_sa_payload = build_sa_payload;
689 this->build_ke_payload = build_ke_payload;
690 this->build_nonce_payload = build_nonce_payload;
691 this->destroy_after_state_change = destroy_after_state_change;
692
693 /* private data */
694 this->ike_sa = ike_sa;
695 this->logger = this->ike_sa->logger;
696 this->sent_nonce.ptr = NULL;
697 this->sent_nonce.len = 0;
698 this->received_nonce.ptr = NULL;
699 this->received_nonce.len = 0;
700 this->proposals = linked_list_create();
701 if (this->proposals == NULL)
702 {
703 allocator_free(this);
704 return NULL;
705 }
706
707 return &(this->public);
708 }