4 * @brief Implementation of ike_sa_init_t transaction.
9 * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
10 * Copyright (C) 2005-2006 Martin Willi
11 * Copyright (C) 2005 Jan Hutter
12 * Hochschule fuer Technik Rapperswil
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>.
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
25 #include "ike_sa_init.h"
30 #include <crypto/diffie_hellman.h>
31 #include <crypto/hashers/hasher.h>
32 #include <encoding/payloads/sa_payload.h>
33 #include <encoding/payloads/ke_payload.h>
34 #include <encoding/payloads/nonce_payload.h>
35 #include <sa/transactions/ike_auth.h>
36 #include <queues/jobs/delete_half_open_ike_sa_job.h>
37 #include <queues/jobs/delete_established_ike_sa_job.h>
38 #include <queues/jobs/rekey_ike_sa_job.h>
41 typedef struct private_ike_sa_init_t private_ike_sa_init_t
;
44 * Private members of a ike_sa_init_t object..
46 struct private_ike_sa_init_t
{
49 * Public methods and transaction_t interface.
59 * Message sent by our peer, if already generated
64 * Message ID this transaction uses
69 * Times we did send the request
74 * Next transaction followed to this one. May be IKE_AUTH,
75 * or a IKE_SA_INIT retry
80 * Diffie hellman object used to generate public DH value.
82 diffie_hellman_t
*diffie_hellman
;
85 * initiator chosen nonce
90 * responder chosen nonce
95 * connection definition used for initiation
97 connection_t
*connection
;
100 * policy definition forwarded to ike_auth transaction
105 * Negotiated proposal used for IKE_SA
107 proposal_t
*proposal
;
110 * Randomizer to generate nonces
112 randomizer_t
*randomizer
;
115 * Hasher used to build NAT detection hashes
117 hasher_t
*nat_hasher
;
120 * Precomputed NAT hash for source address
122 chunk_t natd_src_hash
;
125 * Precomputed NAT hash for destination address
127 chunk_t natd_dst_hash
;
130 * Did we process any NAT detection notifys for a source address?
135 * Did we process any NAT detection notifys for a destination address?
140 * Have we found a matching source address NAT hash?
142 bool natd_src_matched
;
145 * Have we found a matching destination address NAT hash?
147 bool natd_dst_matched
;
156 * Implementation of ike_sa_init_t.use_dh_group.
158 static bool use_dh_group(private_ike_sa_init_t
*this, diffie_hellman_group_t dh_group
)
160 if (this->connection
->check_dh_group(this->connection
, dh_group
))
162 this->diffie_hellman
= diffie_hellman_create(dh_group
);
163 if (this->diffie_hellman
)
172 * Implementation of ike_sa_init_t.set_config.
174 static void set_config(private_ike_sa_init_t
*this,
175 connection_t
*connection
, policy_t
*policy
)
177 this->connection
= connection
;
178 this->policy
= policy
;
182 * Implementation of transaction_t.get_message_id.
184 static u_int32_t
get_message_id(private_ike_sa_init_t
*this)
186 return this->message_id
;
190 * Implementation of transaction_t.requested.
192 static u_int32_t
requested(private_ike_sa_init_t
*this)
194 return this->requested
++;
198 * Build NAT detection hash for a host
200 static chunk_t
generate_natd_hash(private_ike_sa_init_t
*this,
201 ike_sa_id_t
* ike_sa_id
, host_t
*host
)
206 u_int64_t spi_i
, spi_r
;
209 spi_i
= ike_sa_id
->get_initiator_spi(ike_sa_id
);
210 spi_r
= ike_sa_id
->get_responder_spi(ike_sa_id
);
212 switch (host
->get_family(host
))
216 struct sockaddr_in
* sai
;
217 natd_string
= chunk_alloc(sizeof(spi_i
) + sizeof(spi_r
) +
218 sizeof(sai
->sin_addr
.s_addr
) +
219 sizeof(sai
->sin_port
));
220 sai
= (struct sockaddr_in
*)host
->get_sockaddr(host
);
222 *(u_int64_t
*)p
= spi_i
; p
+= sizeof(spi_i
);
223 *(u_int64_t
*)p
= spi_r
; p
+= sizeof(spi_r
);
224 *(u_int32_t
*)p
= sai
->sin_addr
.s_addr
; p
+= sizeof(sai
->sin_addr
.s_addr
);
225 *(u_int16_t
*)p
= sai
->sin_port
; p
+= sizeof(sai
->sin_port
);
230 /* TODO: Add IPv6 support */
231 natd_string
= CHUNK_INITIALIZER
;
234 this->nat_hasher
->allocate_hash(this->nat_hasher
, natd_string
, &natd_hash
);
236 sprintf(buf
, "natd_hash(%016llx %016llx %s:%d) == SHA1(", spi_i
, spi_r
,
237 host
->get_string(host
), host
->get_port(host
));
238 chunk_to_hex(buf
+ strlen(buf
), sizeof(buf
) - strlen(buf
), natd_string
);
239 strcat(buf
, ") == ");
240 chunk_to_hex(buf
+ strlen(buf
), sizeof(buf
) - strlen(buf
), natd_hash
);
241 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, buf
);
243 chunk_free(&natd_string
);
248 * Build a NAT detection notify payload.
250 static notify_payload_t
*build_natd_payload(private_ike_sa_init_t
*this,
251 notify_type_t type
, host_t
*host
)
254 notify_payload_t
*notify
;
255 ike_sa_id_t
*ike_sa_id
;
257 ike_sa_id
= this->ike_sa
->get_id(this->ike_sa
);
258 notify
= notify_payload_create();
259 notify
->set_notify_type(notify
, type
);
260 hash
= generate_natd_hash(this, ike_sa_id
, host
);
261 notify
->set_notification_data(notify
, hash
);
268 * destroy a list of proposals
270 static void destroy_proposal_list(linked_list_t
*list
)
272 proposal_t
*proposal
;
274 while (list
->remove_last(list
, (void**)&proposal
) == SUCCESS
)
276 proposal
->destroy(proposal
);
282 * Implementation of transaction_t.get_request.
284 static status_t
get_request(private_ike_sa_init_t
*this, message_t
**result
)
288 identification_t
*my_id
, *other_id
;
290 /* check if we already have built a message (retransmission) */
293 *result
= this->message
;
297 me
= this->connection
->get_my_host(this->connection
);
298 other
= this->connection
->get_other_host(this->connection
);
300 /* we already set up the IDs. Mine is already fully qualified, other
301 * will be updated in the ike_auth transaction */
302 my_id
= this->policy
->get_my_id(this->policy
);
303 other_id
= this->policy
->get_other_id(this->policy
);
304 this->ike_sa
->set_my_id(this->ike_sa
, my_id
->clone(my_id
));
305 this->ike_sa
->set_other_id(this->ike_sa
, other_id
->clone(other_id
));
307 /* build the request */
308 request
= message_create();
309 request
->set_source(request
, me
->clone(me
));
310 request
->set_destination(request
, other
->clone(other
));
311 request
->set_exchange_type(request
, IKE_SA_INIT
);
312 request
->set_request(request
, TRUE
);
313 request
->set_message_id(request
, this->message_id
);
314 request
->set_ike_sa_id(request
, this->ike_sa
->get_id(this->ike_sa
));
315 /* apply for caller */
317 /* store for retransmission */
318 this->message
= request
;
320 /* if the DH group is set via use_dh_group(), we already have a DH object */
321 if (!this->diffie_hellman
)
323 diffie_hellman_group_t dh_group
;
325 dh_group
= this->connection
->get_dh_group(this->connection
);
326 this->diffie_hellman
= diffie_hellman_create(dh_group
);
327 if (this->diffie_hellman
== NULL
)
329 this->logger
->log(this->logger
, AUDIT
,
330 "DH group %s (%d) not supported, aborting",
331 mapping_find(diffie_hellman_group_m
, dh_group
), dh_group
);
336 { /* build the SA payload from proposals */
337 sa_payload_t
*sa_payload
;
338 linked_list_t
*proposal_list
;
340 proposal_list
= this->connection
->get_proposals(this->connection
);
341 sa_payload
= sa_payload_create_from_proposal_list(proposal_list
);
342 destroy_proposal_list(proposal_list
);
344 request
->add_payload(request
, (payload_t
*)sa_payload
);
347 { /* build the KE payload from the DH object */
348 ke_payload_t
*ke_payload
;
350 ke_payload
= ke_payload_create_from_diffie_hellman(this->diffie_hellman
);
352 request
->add_payload(request
, (payload_t
*)ke_payload
);
355 { /* build the NONCE payload for us (initiator) */
356 nonce_payload_t
*nonce_payload
;
358 if (this->randomizer
->allocate_pseudo_random_bytes(this->randomizer
,
359 NONCE_SIZE
, &this->nonce_i
) != SUCCESS
)
363 nonce_payload
= nonce_payload_create();
364 nonce_payload
->set_nonce(nonce_payload
, this->nonce_i
);
366 request
->add_payload(request
, (payload_t
*)nonce_payload
);
369 { /* build NAT_DETECTION notifys */
370 notify_payload_t
*notify
;
371 iterator_t
*iterator
;
374 /* N(NAT_DETECTION_SOURCE_IP)+ */
375 iterator
= charon
->interfaces
->create_address_iterator(charon
->interfaces
);
376 while (iterator
->iterate(iterator
, (void**)&host
))
378 notify
= build_natd_payload(this, NAT_DETECTION_SOURCE_IP
, host
);
379 request
->add_payload(request
, (payload_t
*)notify
);
381 iterator
->destroy(iterator
);
383 /* N(NAT_DETECTION_DESTINATION_IP) */
384 notify
= build_natd_payload(this, NAT_DETECTION_DESTINATION_IP
, other
);
385 request
->add_payload(request
, (payload_t
*)notify
);
388 this->ike_sa
->set_state(this->ike_sa
, IKE_CONNECTING
);
393 * Handle all kind of notifys
395 static status_t
process_notifys(private_ike_sa_init_t
*this, notify_payload_t
*notify_payload
)
397 chunk_t notification_data
;
398 notify_type_t notify_type
= notify_payload
->get_notify_type(notify_payload
);
400 this->logger
->log(this->logger
, CONTROL
|LEVEL1
, "process notify type %s",
401 mapping_find(notify_type_m
, notify_type
));
405 case NO_PROPOSAL_CHOSEN
:
407 this->logger
->log(this->logger
, AUDIT
,
408 "received a NO_PROPOSAL_CHOSEN notify, deleting IKE_SA");
411 case INVALID_MAJOR_VERSION
:
413 this->logger
->log(this->logger
, AUDIT
,
414 "received a INVALID_MAJOR_VERSION notify, deleting IKE_SA");
417 case INVALID_KE_PAYLOAD
:
420 diffie_hellman_group_t dh_group
, old_dh_group
;
421 ike_sa_init_t
*retry
;
423 old_dh_group
= this->connection
->get_dh_group(this->connection
);
424 notify_data
= notify_payload
->get_notification_data(notify_payload
);
425 dh_group
= ntohs(*((u_int16_t
*)notify_data
.ptr
));
427 this->logger
->log(this->logger
, AUDIT
,
428 "peer didn't accept DH group %s, it requested %s",
429 mapping_find(diffie_hellman_group_m
, old_dh_group
),
430 mapping_find(diffie_hellman_group_m
, dh_group
));
431 if (!this->connection
->check_dh_group(this->connection
, dh_group
))
433 this->logger
->log(this->logger
, AUDIT
,
434 "requested DH group not acceptable, aborting");
437 retry
= ike_sa_init_create(this->ike_sa
);
438 retry
->set_config(retry
, this->connection
, this->policy
);
439 this->connection
= NULL
;
441 retry
->use_dh_group(retry
, dh_group
);
442 *this->next
= (transaction_t
*)retry
;
445 case NAT_DETECTION_DESTINATION_IP
:
447 this->natd_dst_seen
= TRUE
;
448 if (this->natd_dst_matched
)
452 notification_data
= notify_payload
->get_notification_data(notify_payload
);
453 if (chunk_equals(notification_data
, this->natd_dst_hash
))
455 this->natd_dst_matched
= TRUE
;
456 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, "NAT-D dst hash match");
460 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, "NAT-D dst hash mismatch");
464 case NAT_DETECTION_SOURCE_IP
:
466 this->natd_src_seen
= TRUE
;;
467 if (this->natd_src_matched
)
471 notification_data
= notify_payload
->get_notification_data(notify_payload
);
472 if (chunk_equals(notification_data
, this->natd_src_hash
))
474 this->natd_src_matched
= TRUE
;
475 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, "NAT-D src hash match");
479 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, "NAT-D src hash mismatch");
485 if (notify_type
< 16383)
487 this->logger
->log(this->logger
, AUDIT
,
488 "received %s notify error (%d), deleting IKE_SA",
489 mapping_find(notify_type_m
, notify_type
),
495 this->logger
->log(this->logger
, CONTROL
,
496 "received %s notify (%d), ignored",
497 mapping_find(notify_type_m
, notify_type
),
506 * Implementation of transaction_t.get_response.
508 static status_t
get_response(private_ike_sa_init_t
*this,
509 message_t
*request
, message_t
**result
,
510 transaction_t
**next
)
515 iterator_t
*payloads
;
516 sa_payload_t
*sa_request
= NULL
;
517 ke_payload_t
*ke_request
= NULL
;
518 nonce_payload_t
*nonce_request
= NULL
;
519 ike_sa_id_t
*ike_sa_id
;
522 /* check if we already have built a response (retransmission) */
525 *result
= this->message
;
529 me
= request
->get_destination(request
);
530 other
= request
->get_source(request
);
531 this->message_id
= request
->get_message_id(request
);
533 /* set up response */
534 response
= message_create();
535 response
->set_source(response
, me
->clone(me
));
536 response
->set_destination(response
, other
->clone(other
));
537 response
->set_exchange_type(response
, IKE_SA_INIT
);
538 response
->set_request(response
, FALSE
);
539 response
->set_message_id(response
, this->message_id
);
540 response
->set_ike_sa_id(response
, this->ike_sa
->get_id(this->ike_sa
));
541 this->message
= response
;
544 /* check message type */
545 if (request
->get_exchange_type(request
) != IKE_SA_INIT
)
547 this->logger
->log(this->logger
, ERROR
,
548 "IKE_SA_INIT request of invalid type, deleting IKE_SA");
552 /* this is the first message to process, find a connection for IKE_SA */
553 this->connection
= charon
->connections
->get_connection_by_hosts(
554 charon
->connections
, me
, other
);
555 if (this->connection
== NULL
)
557 notify_payload_t
*notify
= notify_payload_create();
558 notify
->set_notify_type(notify
, NO_PROPOSAL_CHOSEN
);
559 response
->add_payload(response
, (payload_t
*)notify
);
561 this->logger
->log(this->logger
, AUDIT
,
562 "no connection for hosts %s...%s found, deleting IKE_SA",
563 me
->get_string(me
), other
->get_string(other
));
566 this->ike_sa
->set_name(this->ike_sa
,
567 this->connection
->get_name(this->connection
));
569 /* Precompute NAT-D hashes for incoming NAT notify comparison */
570 ike_sa_id
= request
->get_ike_sa_id(request
);
571 this->natd_dst_hash
= generate_natd_hash(this, ike_sa_id
, me
);
572 this->natd_src_hash
= generate_natd_hash(this, ike_sa_id
, other
);
574 /* Iterate over all payloads. */
575 payloads
= request
->get_payload_iterator(request
);
576 while (payloads
->has_next(payloads
))
579 payloads
->current(payloads
, (void**)&payload
);
580 switch (payload
->get_type(payload
))
582 case SECURITY_ASSOCIATION
:
583 sa_request
= (sa_payload_t
*)payload
;
586 ke_request
= (ke_payload_t
*)payload
;
589 nonce_request
= (nonce_payload_t
*)payload
;
593 status
= process_notifys(this, (notify_payload_t
*)payload
);
594 if (status
== FAILED
)
596 payloads
->destroy(payloads
);
597 /* we return SUCCESS, returned FAILED means do next transaction */
600 if (status
== DESTROY_ME
)
602 payloads
->destroy(payloads
);
609 this->logger
->log(this->logger
, ERROR
|LEVEL1
,
610 "ignoring %s payload (%d)",
611 mapping_find(payload_type_m
, payload
->get_type(payload
)),
612 payload
->get_type(payload
));
617 payloads
->destroy(payloads
);
619 /* check if we have all payloads */
620 if (!(sa_request
&& ke_request
&& nonce_request
))
622 notify_payload_t
*notify
= notify_payload_create();
623 notify
->set_notify_type(notify
, INVALID_SYNTAX
);
624 response
->add_payload(response
, (payload_t
*)notify
);
625 this->logger
->log(this->logger
, AUDIT
,
626 "request message incomplete, deleting IKE_SA");
630 { /* process SA payload:
631 * -------------------
632 * - extract proposals
633 * - select our most preferred proposal found in extracted
634 * - if no matches, return NO_PROPOSAL_CHOSEN
635 * - add sa payload with selected proposal
637 sa_payload_t
* sa_response
;
638 linked_list_t
*proposal_list
;
640 proposal_list
= sa_request
->get_proposals(sa_request
);
641 this->proposal
= this->connection
->select_proposal(this->connection
, proposal_list
);
642 destroy_proposal_list(proposal_list
);
643 if (this->proposal
== NULL
)
645 notify_payload_t
*notify
= notify_payload_create();
646 notify
->set_notify_type(notify
, NO_PROPOSAL_CHOSEN
);
647 response
->add_payload(response
, (payload_t
*)notify
);
648 this->logger
->log(this->logger
, AUDIT
,
649 "request did not contain any acceptable proposals, deleting IKE_SA");
652 sa_response
= sa_payload_create_from_proposal(this->proposal
);
653 response
->add_payload(response
, (payload_t
*)sa_response
);
656 { /* process KE payload:
657 * --------------------
658 * - check if used group match the selected proposal
659 * - if not, stop with INVALID_KE_PAYLOAD
660 * - apply others public value to complete diffie hellman exchange
661 * - add our public value to response
663 diffie_hellman_group_t used_group
;
664 ke_payload_t
*ke_response
;
666 used_group
= ke_request
->get_dh_group_number(ke_request
);
668 if (!this->connection
->check_dh_group(this->connection
, used_group
) ||
669 (this->diffie_hellman
= diffie_hellman_create(used_group
)) == NULL
)
671 u_int16_t notify_group
;
672 chunk_t notify_chunk
;
673 notify_payload_t
*notify
;
674 iterator_t
*iterator
;
677 notify_group
= this->connection
->get_dh_group(this->connection
);
678 this->logger
->log(this->logger
, AUDIT
,
679 "request used inacceptable DH group %s, sending INVALID_KE_PAYLOAD with %s, deleting IKE_SA",
680 mapping_find(diffie_hellman_group_m
, used_group
),
681 mapping_find(diffie_hellman_group_m
, notify_group
));
683 /* remove already added payloads */
684 iterator
= response
->get_payload_iterator(response
);
685 while (iterator
->has_next(iterator
))
687 iterator
->current(iterator
, (void**)&payload
);
688 iterator
->remove(iterator
);
689 payload
->destroy(payload
);
691 iterator
->destroy(iterator
);
693 notify_group
= htons(notify_group
);
694 notify_chunk
.ptr
= (u_int8_t
*)¬ify_group
;
695 notify_chunk
.len
= sizeof(notify_group
);
696 notify
= notify_payload_create();
697 notify
->set_notify_type(notify
, INVALID_KE_PAYLOAD
);
698 notify
->set_notification_data(notify
, notify_chunk
);
699 response
->add_payload(response
, (payload_t
*)notify
);
702 this->diffie_hellman
->set_other_public_value(this->diffie_hellman
,
703 ke_request
->get_key_exchange_data(ke_request
));
706 ke_response
= ke_payload_create_from_diffie_hellman(this->diffie_hellman
);
707 response
->add_payload(response
, (payload_t
*)ke_response
);
710 { /* process nonce payload:
711 * ----------------------
712 * - get nonce from payload
713 * - generate own nonce and add to reply
715 nonce_payload_t
*nonce_response
;
717 this->nonce_i
= nonce_request
->get_nonce(nonce_request
);
719 /* build response nonce */
720 if (this->randomizer
->allocate_pseudo_random_bytes(this->randomizer
,
721 NONCE_SIZE
, &this->nonce_r
) != SUCCESS
)
723 notify_payload_t
*notify
= notify_payload_create();
724 notify
->set_notify_type(notify
, NO_PROPOSAL_CHOSEN
);
725 response
->add_payload(response
, (payload_t
*)notify
);
726 this->logger
->log(this->logger
, AUDIT
,
727 "could not get random bytes for nonce, deleting IKE_SA");
730 nonce_response
= nonce_payload_create();
731 nonce_response
->set_nonce(nonce_response
, this->nonce_r
);
732 response
->add_payload(response
, (payload_t
*)nonce_response
);
735 { /* processs NATT stuff:
736 * --------------------
737 * - check if we or other is behind NAT
738 * - enable NATT if so
739 * - build NAT detection notifys for reply
741 notify_payload_t
*notify
;
743 if ((!this->natd_src_seen
&& this->natd_dst_seen
) ||
744 (this->natd_src_seen
&& !this->natd_dst_seen
))
746 notify
= notify_payload_create();
747 notify
->set_notify_type(notify
, INVALID_SYNTAX
);
748 response
->add_payload(response
, (payload_t
*)notify
);
749 this->logger
->log(this->logger
, AUDIT
,
750 "request contained wrong number of NAT-D payloads, deleting IKE_SA");
753 if (this->natd_dst_seen
&& !this->natd_dst_matched
)
755 this->ike_sa
->enable_natt(this->ike_sa
, TRUE
);
757 if (this->natd_src_seen
&& !this->natd_src_matched
)
759 this->ike_sa
->enable_natt(this->ike_sa
, FALSE
);
761 /* build response NAT DETECTION notifys, if remote supports it */
762 if (this->natd_src_seen
|| this->natd_dst_seen
)
764 /* N(NAT_DETECTION_SOURCE_IP) */
765 notify
= build_natd_payload(this, NAT_DETECTION_SOURCE_IP
, me
);
766 response
->add_payload(response
, (payload_t
*)notify
);
768 /* N(NAT_DETECTION_DESTINATION_IP) */
769 notify
= build_natd_payload(this, NAT_DETECTION_DESTINATION_IP
, other
);
770 response
->add_payload(response
, (payload_t
*)notify
);
774 /* derive all the keys used in the IKE_SA */
775 if (this->ike_sa
->derive_keys(this->ike_sa
, this->proposal
,
776 this->diffie_hellman
,
777 this->nonce_i
, this->nonce_r
,
778 FALSE
, NULL
, NULL
) != SUCCESS
)
780 notify_payload_t
*notify
= notify_payload_create();
781 notify
->set_notify_type(notify
, NO_PROPOSAL_CHOSEN
);
782 response
->add_payload(response
, (payload_t
*)notify
);
783 this->logger
->log(this->logger
, AUDIT
,
784 "transform objects could not be created from selected proposal, deleting IKE_SA");
788 this->ike_sa
->set_lifetimes(this->ike_sa
,
789 this->connection
->get_soft_lifetime(this->connection
),
790 this->connection
->get_hard_lifetime(this->connection
));
792 { /* create ike_auth transaction, which will store informations for us */
793 packet_t
*response_packet
;
794 chunk_t request_chunk
, response_chunk
;
795 ike_auth_t
*ike_auth
;
797 /* we normally do not generate the message. But we need the generated message
798 * for authentication in the next state, so we do it here. This is not problematic,
799 * as we don't use a crypter/signer in ike_sa_init... */
800 if (response
->generate(response
, NULL
, NULL
, &response_packet
) != SUCCESS
)
802 this->logger
->log(this->logger
, AUDIT
,
803 "error in response generation, deleting IKE_SA");
806 response_packet
->destroy(response_packet
);
807 request_chunk
= request
->get_packet_data(request
);
808 response_chunk
= response
->get_packet_data(response
);
810 /* create next transaction, for which we except a message */
811 ike_auth
= ike_auth_create(this->ike_sa
);
812 ike_auth
->set_config(ike_auth
, this->connection
, this->policy
);
813 this->connection
= NULL
;
815 ike_auth
->set_nonces(ike_auth
,
816 chunk_clone(this->nonce_i
),
817 chunk_clone(this->nonce_r
));
818 ike_auth
->set_init_messages(ike_auth
, request_chunk
, response_chunk
);
819 *next
= (transaction_t
*)ike_auth
;
822 /* everything went fine. Now we set a timeout to destroy half initiated IKE_SAs */
823 timeout
= charon
->configuration
->get_half_open_ike_sa_timeout(charon
->configuration
);
826 job_t
*job
= (job_t
*)delete_half_open_ike_sa_job_create(this->ike_sa
->get_id(this->ike_sa
));
827 charon
->event_queue
->add_relative(charon
->event_queue
, job
, timeout
);
830 this->ike_sa
->set_state(this->ike_sa
, IKE_CONNECTING
);
837 * Implementation of transaction_t.conclude
839 static status_t
conclude(private_ike_sa_init_t
*this, message_t
*response
,
840 transaction_t
**next
)
842 u_int64_t responder_spi
;
843 ike_sa_id_t
*ike_sa_id
;
844 iterator_t
*payloads
;
846 sa_payload_t
*sa_payload
= NULL
;
847 ke_payload_t
*ke_payload
= NULL
;
848 nonce_payload_t
*nonce_payload
= NULL
;
851 /* check message type */
852 if (response
->get_exchange_type(response
) != IKE_SA_INIT
)
854 this->logger
->log(this->logger
, ERROR
,
855 "IKE_SA_INIT response of invalid type, deleting IKE_SA");
859 /* allow setting of next transaction in other functions */
862 me
= this->connection
->get_my_host(this->connection
);
863 other
= this->connection
->get_other_host(this->connection
);
865 /* check if SPI has been updated, but apply only if all goes ok later */
866 responder_spi
= response
->get_responder_spi(response
);
867 if (responder_spi
== 0)
869 this->logger
->log(this->logger
, ERROR
,
870 "response contained a SPI of zero, deleting IKE_SA");
874 /* Precompute NAT-D hashes for later comparison */
875 ike_sa_id
= response
->get_ike_sa_id(response
);
876 this->natd_src_hash
= generate_natd_hash(this, ike_sa_id
, other
);
877 this->natd_dst_hash
= generate_natd_hash(this, ike_sa_id
, me
);
879 /* Iterate over all payloads to collect them */
880 payloads
= response
->get_payload_iterator(response
);
881 while (payloads
->has_next(payloads
))
884 payloads
->current(payloads
, (void**)&payload
);
886 switch (payload
->get_type(payload
))
888 case SECURITY_ASSOCIATION
:
890 sa_payload
= (sa_payload_t
*)payload
;
895 ke_payload
= (ke_payload_t
*)payload
;
900 nonce_payload
= (nonce_payload_t
*)payload
;
905 status
= process_notifys(this, (notify_payload_t
*)payload
);
906 if (status
== FAILED
)
908 payloads
->destroy(payloads
);
909 /* we return SUCCESS, returned FAILED means do next transaction */
912 if (status
== DESTROY_ME
)
914 payloads
->destroy(payloads
);
921 this->logger
->log(this->logger
, ERROR
, "ignoring payload %s (%d)",
922 mapping_find(payload_type_m
, payload
->get_type(payload
)),
923 payload
->get_type(payload
));
928 payloads
->destroy(payloads
);
930 if (!(nonce_payload
&& sa_payload
&& ke_payload
))
932 this->logger
->log(this->logger
, AUDIT
, "response message incomplete, deleting IKE_SA");
936 { /* process SA payload:
937 * -------------------
938 * - get proposals from it
939 * - check if peer selected a proposal
940 * - verify it's selection againts our set
942 proposal_t
*proposal
;
943 linked_list_t
*proposal_list
;
945 /* get the list of selected proposals, the peer has to select only one proposal */
946 proposal_list
= sa_payload
->get_proposals (sa_payload
);
947 if (proposal_list
->get_count(proposal_list
) != 1)
949 this->logger
->log(this->logger
, AUDIT
,
950 "response did not contain a single proposal, deleting IKE_SA");
951 while (proposal_list
->remove_last(proposal_list
, (void**)&proposal
) == SUCCESS
)
953 proposal
->destroy(proposal
);
955 proposal_list
->destroy(proposal_list
);
959 /* we have to re-check if the others selection is valid */
960 this->proposal
= this->connection
->select_proposal(this->connection
, proposal_list
);
961 destroy_proposal_list(proposal_list
);
963 if (this->proposal
== NULL
)
965 this->logger
->log(this->logger
, AUDIT
,
966 "peer selected a proposal we did not offer, deleting IKE_SA");
971 { /* process KE payload:
972 * -------------------
973 * - extract others public value
974 * - complete diffie-hellman exchange
976 this->diffie_hellman
->set_other_public_value(this->diffie_hellman
,
977 ke_payload
->get_key_exchange_data(ke_payload
));
980 { /* process NONCE payload:
981 * ----------------------
982 * - extract nonce used for key derivation */
983 this->nonce_r
= nonce_payload
->get_nonce(nonce_payload
);
986 { /* process NATT stuff:
987 * -------------------
988 * - check if we or other is NATted
989 * - switch to port 4500 if so
991 if ((!this->natd_dst_seen
&& this->natd_src_seen
) ||
992 (this->natd_dst_seen
&& !this->natd_src_seen
))
994 this->logger
->log(this->logger
, AUDIT
,
995 "request contained wrong number of NAT-D payloads, deleting IKE_SA");
998 if (this->natd_src_seen
&& !this->natd_src_matched
)
1000 this->ike_sa
->enable_natt(this->ike_sa
, FALSE
);
1002 if (this->natd_dst_seen
&& !this->natd_dst_matched
)
1004 this->ike_sa
->enable_natt(this->ike_sa
, TRUE
);
1006 if (this->ike_sa
->is_natt_enabled(this->ike_sa
))
1008 /* update host in IKE_SA */
1009 me
= this->ike_sa
->get_my_host(this->ike_sa
);
1011 me
->set_port(me
, IKEV2_NATT_PORT
);
1012 this->ike_sa
->set_my_host(this->ike_sa
, me
);
1013 other
= this->ike_sa
->get_other_host(this->ike_sa
);
1014 other
= other
->clone(other
);
1015 other
->set_port(other
, IKEV2_NATT_PORT
);
1016 this->ike_sa
->set_other_host(this->ike_sa
, other
);
1018 this->logger
->log(this->logger
, CONTROL
|LEVEL1
, "switching to port %d", IKEV2_NATT_PORT
);
1022 /* because we are original initiator we have to update the responder SPI to the new one */
1023 ike_sa_id
= this->ike_sa
->get_id(this->ike_sa
);
1024 ike_sa_id
->set_responder_spi(ike_sa_id
, responder_spi
);
1026 /* derive all the keys used in the IKE_SA */
1027 if (this->ike_sa
->derive_keys(this->ike_sa
, this->proposal
,
1028 this->diffie_hellman
,
1029 this->nonce_i
, this->nonce_r
,
1030 TRUE
, NULL
, NULL
) != SUCCESS
)
1032 this->logger
->log(this->logger
, AUDIT
,
1033 "transform objects could not be created from selected proposal, deleting IKE_SA");
1037 this->ike_sa
->set_lifetimes(this->ike_sa
,
1038 this->connection
->get_soft_lifetime(this->connection
),
1039 this->connection
->get_hard_lifetime(this->connection
));
1041 { /* create ike_auth transaction, which will continue IKE_SA setup */
1042 chunk_t request_chunk
, response_chunk
;
1043 ike_auth_t
*ike_auth
;
1045 request_chunk
= this->message
->get_packet_data(this->message
);
1046 response_chunk
= response
->get_packet_data(response
);
1048 /* create next transaction, for which we except a message */
1049 ike_auth
= ike_auth_create(this->ike_sa
);
1050 ike_auth
->set_config(ike_auth
, this->connection
, this->policy
);
1051 this->connection
= NULL
;
1052 this->policy
= NULL
;
1053 ike_auth
->set_nonces(ike_auth
,
1054 chunk_clone(this->nonce_i
),
1055 chunk_clone(this->nonce_r
));
1056 ike_auth
->set_init_messages(ike_auth
, request_chunk
, response_chunk
);
1057 *next
= (transaction_t
*)ike_auth
;
1063 static void destroy(private_ike_sa_init_t
*this)
1065 DESTROY_IF(this->message
);
1066 DESTROY_IF(this->diffie_hellman
);
1067 DESTROY_IF(this->proposal
);
1068 DESTROY_IF(this->connection
);
1069 DESTROY_IF(this->policy
);
1070 chunk_free(&this->nonce_i
);
1071 chunk_free(&this->nonce_r
);
1072 this->randomizer
->destroy(this->randomizer
);
1073 this->nat_hasher
->destroy(this->nat_hasher
);
1074 chunk_free(&this->natd_src_hash
);
1075 chunk_free(&this->natd_dst_hash
);
1080 * Described in header.
1082 ike_sa_init_t
*ike_sa_init_create(ike_sa_t
*ike_sa
)
1084 private_ike_sa_init_t
*this = malloc_thing(private_ike_sa_init_t
);
1086 /* transaction interface functions */
1087 this->public.transaction
.get_request
= (status_t(*)(transaction_t
*,message_t
**))get_request
;
1088 this->public.transaction
.get_response
= (status_t(*)(transaction_t
*,message_t
*,message_t
**,transaction_t
**))get_response
;
1089 this->public.transaction
.conclude
= (status_t(*)(transaction_t
*,message_t
*,transaction_t
**))conclude
;
1090 this->public.transaction
.get_message_id
= (u_int32_t(*)(transaction_t
*))get_message_id
;
1091 this->public.transaction
.requested
= (u_int32_t(*)(transaction_t
*))requested
;
1092 this->public.transaction
.destroy
= (void(*)(transaction_t
*))destroy
;
1094 /* public functions */
1095 this->public.set_config
= (void(*)(ike_sa_init_t
*,connection_t
*,policy_t
*))set_config
;
1096 this->public.use_dh_group
= (bool(*)(ike_sa_init_t
*,diffie_hellman_group_t
))use_dh_group
;
1099 this->ike_sa
= ike_sa
;
1100 this->message_id
= 0;
1101 this->message
= NULL
;
1102 this->requested
= 0;
1103 this->diffie_hellman
= NULL
;
1104 this->nonce_i
= CHUNK_INITIALIZER
;
1105 this->nonce_r
= CHUNK_INITIALIZER
;
1106 this->connection
= NULL
;
1107 this->policy
= NULL
;
1108 this->proposal
= NULL
;
1109 this->randomizer
= randomizer_create();
1110 this->nat_hasher
= hasher_create(HASH_SHA1
);
1111 this->natd_src_hash
= CHUNK_INITIALIZER
;
1112 this->natd_dst_hash
= CHUNK_INITIALIZER
;
1113 this->natd_src_seen
= FALSE
;
1114 this->natd_dst_seen
= FALSE
;
1115 this->natd_src_matched
= FALSE
;
1116 this->natd_dst_matched
= FALSE
;
1117 this->logger
= logger_manager
->get_logger(logger_manager
, IKE_SA
);
1119 return &this->public;