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_ike_sa_job.h>
37 #include <queues/jobs/rekey_ike_sa_job.h>
40 typedef struct private_ike_sa_init_t private_ike_sa_init_t
;
43 * Private members of a ike_sa_init_t object..
45 struct private_ike_sa_init_t
{
48 * Public methods and transaction_t interface.
58 * Message sent by our peer, if already generated
63 * Message ID this transaction uses
68 * Times we did send the request
73 * Next transaction followed to this one. May be IKE_AUTH,
74 * or a IKE_SA_INIT retry
79 * Diffie hellman object used to generate public DH value.
81 diffie_hellman_t
*diffie_hellman
;
84 * initiator chosen nonce
89 * responder chosen nonce
94 * connection definition used for initiation
96 connection_t
*connection
;
99 * policy definition forwarded to ike_auth transaction
104 * Negotiated proposal used for IKE_SA
106 proposal_t
*proposal
;
109 * Reqid to pass to IKE_AUTH, used for created CHILD_SA
114 * Unique ID for to enumerate all IKE_SAs in its name
119 * Randomizer to generate nonces
121 randomizer_t
*randomizer
;
124 * Hasher used to build NAT detection hashes
126 hasher_t
*nat_hasher
;
129 * Precomputed NAT hash for source address
131 chunk_t natd_src_hash
;
134 * Precomputed NAT hash for destination address
136 chunk_t natd_dst_hash
;
139 * Did we process any NAT detection notifys for a source address?
144 * Did we process any NAT detection notifys for a destination address?
149 * Have we found a matching source address NAT hash?
151 bool natd_src_matched
;
154 * Have we found a matching destination address NAT hash?
156 bool natd_dst_matched
;
165 * Implementation of ike_sa_init_t.use_dh_group.
167 static bool use_dh_group(private_ike_sa_init_t
*this, diffie_hellman_group_t dh_group
)
169 if (this->connection
->check_dh_group(this->connection
, dh_group
))
171 this->diffie_hellman
= diffie_hellman_create(dh_group
);
172 if (this->diffie_hellman
)
181 * Implementation of ike_sa_init_t.set_config.
183 static void set_config(private_ike_sa_init_t
*this,
184 connection_t
*connection
, policy_t
*policy
)
186 this->connection
= connection
;
187 this->policy
= policy
;
191 * Implementation of ike_sa_init_t.set_reqid.
193 static void set_reqid(private_ike_sa_init_t
*this, u_int32_t reqid
)
199 * Implementation of transaction_t.get_message_id.
201 static u_int32_t
get_message_id(private_ike_sa_init_t
*this)
203 return this->message_id
;
207 * Implementation of transaction_t.requested.
209 static u_int32_t
requested(private_ike_sa_init_t
*this)
211 return this->requested
++;
215 * Build NAT detection hash for a host
217 static chunk_t
generate_natd_hash(private_ike_sa_init_t
*this,
218 ike_sa_id_t
* ike_sa_id
, host_t
*host
)
220 chunk_t natd_chunk
, spi_i_chunk
, spi_r_chunk
, addr_chunk
, port_chunk
;
222 u_int64_t spi_i
, spi_r
;
225 /* prepare all requred chunks */
226 spi_i
= ike_sa_id
->get_initiator_spi(ike_sa_id
);
227 spi_r
= ike_sa_id
->get_responder_spi(ike_sa_id
);
228 spi_i_chunk
.ptr
= (void*)&spi_i
;
229 spi_i_chunk
.len
= sizeof(spi_i
);
230 spi_r_chunk
.ptr
= (void*)&spi_r
;
231 spi_r_chunk
.len
= sizeof(spi_r
);
232 port
= htons(host
->get_port(host
));
233 port_chunk
.ptr
= (void*)&port
;
234 port_chunk
.len
= sizeof(port
);
235 addr_chunk
= host
->get_address(host
);
237 /* natd_hash = SHA1( spi_i | spi_r | address | port ) */
238 natd_chunk
= chunk_cat("cccc", spi_i_chunk
, spi_r_chunk
, addr_chunk
, port_chunk
);
239 this->nat_hasher
->allocate_hash(this->nat_hasher
, natd_chunk
, &natd_hash
);
240 this->logger
->log_chunk(this->logger
, RAW
, "natd_chunk", natd_chunk
);
241 this->logger
->log_chunk(this->logger
, RAW
, "natd_hash", natd_hash
);
243 chunk_free(&natd_chunk
);
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
;
291 /* check if we already have built a message (retransmission) */
294 *result
= this->message
;
298 me
= this->connection
->get_my_host(this->connection
);
299 other
= this->connection
->get_other_host(this->connection
);
301 /* we already set up the IDs. Mine is already fully qualified, other
302 * will be updated in the ike_auth transaction */
303 my_id
= this->policy
->get_my_id(this->policy
);
304 other_id
= this->policy
->get_other_id(this->policy
);
305 this->ike_sa
->set_my_id(this->ike_sa
, my_id
->clone(my_id
));
306 this->ike_sa
->set_other_id(this->ike_sa
, other_id
->clone(other_id
));
307 if (snprintf(name
, sizeof(name
), "%s{%d}",
308 this->connection
->get_name(this->connection
),
309 this->unique_id
) > 0)
311 this->ike_sa
->set_name(this->ike_sa
, name
);
314 /* build the request */
315 request
= message_create();
316 request
->set_source(request
, me
->clone(me
));
317 request
->set_destination(request
, other
->clone(other
));
318 request
->set_exchange_type(request
, IKE_SA_INIT
);
319 request
->set_request(request
, TRUE
);
320 request
->set_message_id(request
, this->message_id
);
321 request
->set_ike_sa_id(request
, this->ike_sa
->get_id(this->ike_sa
));
322 /* apply for caller */
324 /* store for retransmission */
325 this->message
= request
;
327 /* if the DH group is set via use_dh_group(), we already have a DH object */
328 if (!this->diffie_hellman
)
330 diffie_hellman_group_t dh_group
;
332 dh_group
= this->connection
->get_dh_group(this->connection
);
333 this->diffie_hellman
= diffie_hellman_create(dh_group
);
334 if (this->diffie_hellman
== NULL
)
336 this->logger
->log(this->logger
, AUDIT
,
337 "DH group %s (%d) not supported, aborting",
338 mapping_find(diffie_hellman_group_m
, dh_group
), dh_group
);
343 { /* build the SA payload from proposals */
344 sa_payload_t
*sa_payload
;
345 linked_list_t
*proposal_list
;
347 proposal_list
= this->connection
->get_proposals(this->connection
);
348 sa_payload
= sa_payload_create_from_proposal_list(proposal_list
);
349 destroy_proposal_list(proposal_list
);
351 request
->add_payload(request
, (payload_t
*)sa_payload
);
354 { /* build the KE payload from the DH object */
355 ke_payload_t
*ke_payload
;
357 ke_payload
= ke_payload_create_from_diffie_hellman(this->diffie_hellman
);
359 request
->add_payload(request
, (payload_t
*)ke_payload
);
362 { /* build the NONCE payload for us (initiator) */
363 nonce_payload_t
*nonce_payload
;
365 if (this->randomizer
->allocate_pseudo_random_bytes(this->randomizer
,
366 NONCE_SIZE
, &this->nonce_i
) != SUCCESS
)
370 nonce_payload
= nonce_payload_create();
371 nonce_payload
->set_nonce(nonce_payload
, this->nonce_i
);
373 request
->add_payload(request
, (payload_t
*)nonce_payload
);
376 { /* build NAT_DETECTION notifys */
377 notify_payload_t
*notify
;
381 /* N(NAT_DETECTION_SOURCE_IP)+ */
382 list
= charon
->socket
->create_local_address_list(charon
->socket
);
383 while (list
->remove_first(list
, (void**)&host
) == SUCCESS
)
385 /* TODO: should we only include NAT payloads for addresses
386 * of used address family? */
387 notify
= build_natd_payload(this, NAT_DETECTION_SOURCE_IP
, host
);
389 request
->add_payload(request
, (payload_t
*)notify
);
393 /* N(NAT_DETECTION_DESTINATION_IP) */
394 notify
= build_natd_payload(this, NAT_DETECTION_DESTINATION_IP
, other
);
395 request
->add_payload(request
, (payload_t
*)notify
);
398 this->ike_sa
->set_state(this->ike_sa
, IKE_CONNECTING
);
403 * Handle all kind of notifys
405 static status_t
process_notifys(private_ike_sa_init_t
*this, notify_payload_t
*notify_payload
)
407 chunk_t notification_data
;
408 notify_type_t notify_type
= notify_payload
->get_notify_type(notify_payload
);
410 this->logger
->log(this->logger
, CONTROL
|LEVEL1
, "process notify type %s",
411 mapping_find(notify_type_m
, notify_type
));
415 case NO_PROPOSAL_CHOSEN
:
417 this->logger
->log(this->logger
, AUDIT
,
418 "received a NO_PROPOSAL_CHOSEN notify, deleting IKE_SA");
421 case INVALID_MAJOR_VERSION
:
423 this->logger
->log(this->logger
, AUDIT
,
424 "received a INVALID_MAJOR_VERSION notify, deleting IKE_SA");
427 case INVALID_KE_PAYLOAD
:
430 diffie_hellman_group_t dh_group
, old_dh_group
;
431 ike_sa_init_t
*retry
;
433 old_dh_group
= this->connection
->get_dh_group(this->connection
);
434 notify_data
= notify_payload
->get_notification_data(notify_payload
);
435 dh_group
= ntohs(*((u_int16_t
*)notify_data
.ptr
));
437 this->logger
->log(this->logger
, AUDIT
,
438 "peer didn't accept DH group %s, it requested %s",
439 mapping_find(diffie_hellman_group_m
, old_dh_group
),
440 mapping_find(diffie_hellman_group_m
, dh_group
));
441 if (!this->connection
->check_dh_group(this->connection
, dh_group
))
443 this->logger
->log(this->logger
, AUDIT
,
444 "requested DH group not acceptable, aborting");
447 retry
= ike_sa_init_create(this->ike_sa
);
448 retry
->set_config(retry
, this->connection
, this->policy
);
449 this->connection
= NULL
;
451 retry
->use_dh_group(retry
, dh_group
);
452 *this->next
= (transaction_t
*)retry
;
455 case NAT_DETECTION_DESTINATION_IP
:
457 this->natd_dst_seen
= TRUE
;
458 if (this->natd_dst_matched
)
462 notification_data
= notify_payload
->get_notification_data(notify_payload
);
463 if (chunk_equals(notification_data
, this->natd_dst_hash
))
465 this->natd_dst_matched
= TRUE
;
466 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, "NAT-D dst hash match");
470 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, "NAT-D dst hash mismatch");
474 case NAT_DETECTION_SOURCE_IP
:
476 this->natd_src_seen
= TRUE
;;
477 if (this->natd_src_matched
)
481 notification_data
= notify_payload
->get_notification_data(notify_payload
);
482 if (chunk_equals(notification_data
, this->natd_src_hash
))
484 this->natd_src_matched
= TRUE
;
485 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, "NAT-D src hash match");
489 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, "NAT-D src hash mismatch");
495 if (notify_type
< 16383)
497 this->logger
->log(this->logger
, AUDIT
,
498 "received %s notify error (%d), deleting IKE_SA",
499 mapping_find(notify_type_m
, notify_type
),
505 this->logger
->log(this->logger
, CONTROL
,
506 "received %s notify (%d), ignored",
507 mapping_find(notify_type_m
, notify_type
),
516 * Implementation of transaction_t.get_response.
518 static status_t
get_response(private_ike_sa_init_t
*this,
519 message_t
*request
, message_t
**result
,
520 transaction_t
**next
)
525 iterator_t
*payloads
;
526 sa_payload_t
*sa_request
= NULL
;
527 ke_payload_t
*ke_request
= NULL
;
528 nonce_payload_t
*nonce_request
= NULL
;
529 ike_sa_id_t
*ike_sa_id
;
533 /* check if we already have built a response (retransmission) */
536 *result
= this->message
;
540 me
= request
->get_destination(request
);
541 other
= request
->get_source(request
);
542 this->message_id
= request
->get_message_id(request
);
544 /* set up response */
545 response
= message_create();
546 response
->set_source(response
, me
->clone(me
));
547 response
->set_destination(response
, other
->clone(other
));
548 response
->set_exchange_type(response
, IKE_SA_INIT
);
549 response
->set_request(response
, FALSE
);
550 response
->set_message_id(response
, this->message_id
);
551 response
->set_ike_sa_id(response
, this->ike_sa
->get_id(this->ike_sa
));
552 this->message
= response
;
555 /* check message type */
556 if (request
->get_exchange_type(request
) != IKE_SA_INIT
)
558 this->logger
->log(this->logger
, ERROR
,
559 "IKE_SA_INIT request of invalid type, deleting IKE_SA");
563 /* this is the first message to process, find a connection for IKE_SA */
564 this->connection
= charon
->connections
->get_connection_by_hosts(
565 charon
->connections
, me
, other
);
566 if (this->connection
== NULL
)
568 notify_payload_t
*notify
= notify_payload_create();
569 notify
->set_notify_type(notify
, NO_PROPOSAL_CHOSEN
);
570 response
->add_payload(response
, (payload_t
*)notify
);
572 this->logger
->log(this->logger
, AUDIT
,
573 "no connection for hosts %s...%s found, deleting IKE_SA",
574 me
->get_string(me
), other
->get_string(other
));
578 if (snprintf(name
, sizeof(name
), "%s{%d}",
579 this->connection
->get_name(this->connection
),
580 this->unique_id
) > 0)
582 this->ike_sa
->set_name(this->ike_sa
, name
);
584 this->ike_sa
->set_dpd_delay(this->ike_sa
,
585 this->connection
->get_dpd_delay(this->connection
));
587 /* Precompute NAT-D hashes for incoming NAT notify comparison */
588 ike_sa_id
= request
->get_ike_sa_id(request
);
589 this->natd_dst_hash
= generate_natd_hash(this, ike_sa_id
, me
);
590 this->natd_src_hash
= generate_natd_hash(this, ike_sa_id
, other
);
592 /* Iterate over all payloads. */
593 payloads
= request
->get_payload_iterator(request
);
594 while (payloads
->has_next(payloads
))
597 payloads
->current(payloads
, (void**)&payload
);
598 switch (payload
->get_type(payload
))
600 case SECURITY_ASSOCIATION
:
601 sa_request
= (sa_payload_t
*)payload
;
604 ke_request
= (ke_payload_t
*)payload
;
607 nonce_request
= (nonce_payload_t
*)payload
;
611 status
= process_notifys(this, (notify_payload_t
*)payload
);
612 if (status
== FAILED
)
614 payloads
->destroy(payloads
);
615 /* we return SUCCESS, returned FAILED means do next transaction */
618 if (status
== DESTROY_ME
)
620 payloads
->destroy(payloads
);
627 this->logger
->log(this->logger
, ERROR
|LEVEL1
,
628 "ignoring %s payload (%d)",
629 mapping_find(payload_type_m
, payload
->get_type(payload
)),
630 payload
->get_type(payload
));
635 payloads
->destroy(payloads
);
637 /* check if we have all payloads */
638 if (!(sa_request
&& ke_request
&& nonce_request
))
640 notify_payload_t
*notify
= notify_payload_create();
641 notify
->set_notify_type(notify
, INVALID_SYNTAX
);
642 response
->add_payload(response
, (payload_t
*)notify
);
643 this->logger
->log(this->logger
, AUDIT
,
644 "request message incomplete, deleting IKE_SA");
648 { /* process SA payload:
649 * -------------------
650 * - extract proposals
651 * - select our most preferred proposal found in extracted
652 * - if no matches, return NO_PROPOSAL_CHOSEN
653 * - add sa payload with selected proposal
655 sa_payload_t
* sa_response
;
656 linked_list_t
*proposal_list
;
658 proposal_list
= sa_request
->get_proposals(sa_request
);
659 this->proposal
= this->connection
->select_proposal(this->connection
, proposal_list
);
660 destroy_proposal_list(proposal_list
);
661 if (this->proposal
== NULL
)
663 notify_payload_t
*notify
= notify_payload_create();
664 notify
->set_notify_type(notify
, NO_PROPOSAL_CHOSEN
);
665 response
->add_payload(response
, (payload_t
*)notify
);
666 this->logger
->log(this->logger
, AUDIT
,
667 "request did not contain any acceptable proposals, deleting IKE_SA");
670 sa_response
= sa_payload_create_from_proposal(this->proposal
);
671 response
->add_payload(response
, (payload_t
*)sa_response
);
674 { /* process KE payload:
675 * --------------------
676 * - check if used group match the selected proposal
677 * - if not, stop with INVALID_KE_PAYLOAD
678 * - apply others public value to complete diffie hellman exchange
679 * - add our public value to response
681 diffie_hellman_group_t used_group
;
682 ke_payload_t
*ke_response
;
684 used_group
= ke_request
->get_dh_group_number(ke_request
);
686 if (!this->connection
->check_dh_group(this->connection
, used_group
) ||
687 (this->diffie_hellman
= diffie_hellman_create(used_group
)) == NULL
)
689 u_int16_t notify_group
;
690 chunk_t notify_chunk
;
691 notify_payload_t
*notify
;
692 iterator_t
*iterator
;
695 notify_group
= this->connection
->get_dh_group(this->connection
);
696 this->logger
->log(this->logger
, AUDIT
,
697 "request used inacceptable DH group %s, sending INVALID_KE_PAYLOAD with %s, deleting IKE_SA",
698 mapping_find(diffie_hellman_group_m
, used_group
),
699 mapping_find(diffie_hellman_group_m
, notify_group
));
701 /* remove already added payloads */
702 iterator
= response
->get_payload_iterator(response
);
703 while (iterator
->has_next(iterator
))
705 iterator
->current(iterator
, (void**)&payload
);
706 iterator
->remove(iterator
);
707 payload
->destroy(payload
);
709 iterator
->destroy(iterator
);
711 notify_group
= htons(notify_group
);
712 notify_chunk
.ptr
= (u_int8_t
*)¬ify_group
;
713 notify_chunk
.len
= sizeof(notify_group
);
714 notify
= notify_payload_create();
715 notify
->set_notify_type(notify
, INVALID_KE_PAYLOAD
);
716 notify
->set_notification_data(notify
, notify_chunk
);
717 response
->add_payload(response
, (payload_t
*)notify
);
720 this->diffie_hellman
->set_other_public_value(this->diffie_hellman
,
721 ke_request
->get_key_exchange_data(ke_request
));
724 ke_response
= ke_payload_create_from_diffie_hellman(this->diffie_hellman
);
725 response
->add_payload(response
, (payload_t
*)ke_response
);
728 { /* process nonce payload:
729 * ----------------------
730 * - get nonce from payload
731 * - generate own nonce and add to reply
733 nonce_payload_t
*nonce_response
;
735 this->nonce_i
= nonce_request
->get_nonce(nonce_request
);
737 /* build response nonce */
738 if (this->randomizer
->allocate_pseudo_random_bytes(this->randomizer
,
739 NONCE_SIZE
, &this->nonce_r
) != SUCCESS
)
741 notify_payload_t
*notify
= notify_payload_create();
742 notify
->set_notify_type(notify
, NO_PROPOSAL_CHOSEN
);
743 response
->add_payload(response
, (payload_t
*)notify
);
744 this->logger
->log(this->logger
, AUDIT
,
745 "could not get random bytes for nonce, deleting IKE_SA");
748 nonce_response
= nonce_payload_create();
749 nonce_response
->set_nonce(nonce_response
, this->nonce_r
);
750 response
->add_payload(response
, (payload_t
*)nonce_response
);
753 { /* processs NATT stuff:
754 * --------------------
755 * - check if we or other is behind NAT
756 * - enable NATT if so
757 * - build NAT detection notifys for reply
759 notify_payload_t
*notify
;
761 if ((!this->natd_src_seen
&& this->natd_dst_seen
) ||
762 (this->natd_src_seen
&& !this->natd_dst_seen
))
764 notify
= notify_payload_create();
765 notify
->set_notify_type(notify
, INVALID_SYNTAX
);
766 response
->add_payload(response
, (payload_t
*)notify
);
767 this->logger
->log(this->logger
, AUDIT
,
768 "request contained wrong number of NAT-D payloads, deleting IKE_SA");
771 if (this->natd_dst_seen
&& !this->natd_dst_matched
)
773 this->ike_sa
->enable_natt(this->ike_sa
, TRUE
);
775 if (this->natd_src_seen
&& !this->natd_src_matched
)
777 this->ike_sa
->enable_natt(this->ike_sa
, FALSE
);
779 /* build response NAT DETECTION notifys, if remote supports it */
780 if (this->natd_src_seen
|| this->natd_dst_seen
)
782 /* N(NAT_DETECTION_SOURCE_IP) */
783 notify
= build_natd_payload(this, NAT_DETECTION_SOURCE_IP
, me
);
784 response
->add_payload(response
, (payload_t
*)notify
);
786 /* N(NAT_DETECTION_DESTINATION_IP) */
787 notify
= build_natd_payload(this, NAT_DETECTION_DESTINATION_IP
, other
);
788 response
->add_payload(response
, (payload_t
*)notify
);
792 /* derive all the keys used in the IKE_SA */
793 if (this->ike_sa
->derive_keys(this->ike_sa
, this->proposal
,
794 this->diffie_hellman
,
795 this->nonce_i
, this->nonce_r
,
796 FALSE
, NULL
, NULL
) != SUCCESS
)
798 notify_payload_t
*notify
= notify_payload_create();
799 notify
->set_notify_type(notify
, NO_PROPOSAL_CHOSEN
);
800 response
->add_payload(response
, (payload_t
*)notify
);
801 this->logger
->log(this->logger
, AUDIT
,
802 "transform objects could not be created from selected proposal, deleting IKE_SA");
806 this->ike_sa
->set_lifetimes(this->ike_sa
,
807 this->connection
->get_soft_lifetime(this->connection
),
808 this->connection
->get_hard_lifetime(this->connection
));
810 { /* create ike_auth transaction, which will store informations for us */
811 packet_t
*response_packet
;
812 chunk_t request_chunk
, response_chunk
;
813 ike_auth_t
*ike_auth
;
815 /* we normally do not generate the message. But we need the generated message
816 * for authentication in the next state, so we do it here. This is not problematic,
817 * as we don't use a crypter/signer in ike_sa_init... */
818 if (response
->generate(response
, NULL
, NULL
, &response_packet
) != SUCCESS
)
820 this->logger
->log(this->logger
, AUDIT
,
821 "error in response generation, deleting IKE_SA");
824 response_packet
->destroy(response_packet
);
825 request_chunk
= request
->get_packet_data(request
);
826 response_chunk
= response
->get_packet_data(response
);
828 /* create next transaction, for which we except a message */
829 ike_auth
= ike_auth_create(this->ike_sa
);
830 ike_auth
->set_config(ike_auth
, this->connection
, this->policy
);
831 ike_auth
->set_reqid(ike_auth
, this->reqid
);
832 this->connection
= NULL
;
834 ike_auth
->set_nonces(ike_auth
,
835 chunk_clone(this->nonce_i
),
836 chunk_clone(this->nonce_r
));
837 ike_auth
->set_init_messages(ike_auth
, request_chunk
, response_chunk
);
838 *next
= (transaction_t
*)ike_auth
;
841 /* everything went fine. Now we set a timeout to destroy half initiated IKE_SAs */
842 timeout
= charon
->configuration
->get_half_open_ike_sa_timeout(charon
->configuration
);
845 job_t
*job
= (job_t
*)delete_ike_sa_job_create(
846 this->ike_sa
->get_id(this->ike_sa
), FALSE
);
847 charon
->event_queue
->add_relative(charon
->event_queue
, job
, timeout
);
850 this->ike_sa
->set_state(this->ike_sa
, IKE_CONNECTING
);
857 * Implementation of transaction_t.conclude
859 static status_t
conclude(private_ike_sa_init_t
*this, message_t
*response
,
860 transaction_t
**next
)
862 u_int64_t responder_spi
;
863 ike_sa_id_t
*ike_sa_id
;
864 iterator_t
*payloads
;
866 sa_payload_t
*sa_payload
= NULL
;
867 ke_payload_t
*ke_payload
= NULL
;
868 nonce_payload_t
*nonce_payload
= NULL
;
871 /* check message type */
872 if (response
->get_exchange_type(response
) != IKE_SA_INIT
)
874 this->logger
->log(this->logger
, ERROR
,
875 "IKE_SA_INIT response of invalid type, deleting IKE_SA");
879 /* allow setting of next transaction in other functions */
882 me
= this->connection
->get_my_host(this->connection
);
883 other
= this->connection
->get_other_host(this->connection
);
885 /* check if SPI has been updated, but apply only if all goes ok later */
886 responder_spi
= response
->get_responder_spi(response
);
887 if (responder_spi
== 0)
889 this->logger
->log(this->logger
, ERROR
,
890 "response contained a SPI of zero, deleting IKE_SA");
894 /* Precompute NAT-D hashes for later comparison */
895 ike_sa_id
= response
->get_ike_sa_id(response
);
896 this->natd_src_hash
= generate_natd_hash(this, ike_sa_id
, other
);
897 this->natd_dst_hash
= generate_natd_hash(this, ike_sa_id
, me
);
899 /* Iterate over all payloads to collect them */
900 payloads
= response
->get_payload_iterator(response
);
901 while (payloads
->has_next(payloads
))
904 payloads
->current(payloads
, (void**)&payload
);
906 switch (payload
->get_type(payload
))
908 case SECURITY_ASSOCIATION
:
910 sa_payload
= (sa_payload_t
*)payload
;
915 ke_payload
= (ke_payload_t
*)payload
;
920 nonce_payload
= (nonce_payload_t
*)payload
;
925 status
= process_notifys(this, (notify_payload_t
*)payload
);
926 if (status
== FAILED
)
928 payloads
->destroy(payloads
);
929 /* we return SUCCESS, returned FAILED means do next transaction */
932 if (status
== DESTROY_ME
)
934 payloads
->destroy(payloads
);
941 this->logger
->log(this->logger
, ERROR
, "ignoring payload %s (%d)",
942 mapping_find(payload_type_m
, payload
->get_type(payload
)),
943 payload
->get_type(payload
));
948 payloads
->destroy(payloads
);
950 if (!(nonce_payload
&& sa_payload
&& ke_payload
))
952 this->logger
->log(this->logger
, AUDIT
, "response message incomplete, deleting IKE_SA");
956 { /* process SA payload:
957 * -------------------
958 * - get proposals from it
959 * - check if peer selected a proposal
960 * - verify it's selection againts our set
962 proposal_t
*proposal
;
963 linked_list_t
*proposal_list
;
965 /* get the list of selected proposals, the peer has to select only one proposal */
966 proposal_list
= sa_payload
->get_proposals (sa_payload
);
967 if (proposal_list
->get_count(proposal_list
) != 1)
969 this->logger
->log(this->logger
, AUDIT
,
970 "response did not contain a single proposal, deleting IKE_SA");
971 while (proposal_list
->remove_last(proposal_list
, (void**)&proposal
) == SUCCESS
)
973 proposal
->destroy(proposal
);
975 proposal_list
->destroy(proposal_list
);
979 /* we have to re-check if the others selection is valid */
980 this->proposal
= this->connection
->select_proposal(this->connection
, proposal_list
);
981 destroy_proposal_list(proposal_list
);
983 if (this->proposal
== NULL
)
985 this->logger
->log(this->logger
, AUDIT
,
986 "peer selected a proposal we did not offer, deleting IKE_SA");
991 { /* process KE payload:
992 * -------------------
993 * - extract others public value
994 * - complete diffie-hellman exchange
996 this->diffie_hellman
->set_other_public_value(this->diffie_hellman
,
997 ke_payload
->get_key_exchange_data(ke_payload
));
1000 { /* process NONCE payload:
1001 * ----------------------
1002 * - extract nonce used for key derivation */
1003 this->nonce_r
= nonce_payload
->get_nonce(nonce_payload
);
1006 { /* process NATT stuff:
1007 * -------------------
1008 * - check if we or other is NATted
1009 * - switch to port 4500 if so
1011 if ((!this->natd_dst_seen
&& this->natd_src_seen
) ||
1012 (this->natd_dst_seen
&& !this->natd_src_seen
))
1014 this->logger
->log(this->logger
, AUDIT
,
1015 "request contained wrong number of NAT-D payloads, deleting IKE_SA");
1018 if (this->natd_src_seen
&& !this->natd_src_matched
)
1020 this->ike_sa
->enable_natt(this->ike_sa
, FALSE
);
1022 if (this->natd_dst_seen
&& !this->natd_dst_matched
)
1024 this->ike_sa
->enable_natt(this->ike_sa
, TRUE
);
1026 if (this->ike_sa
->is_natt_enabled(this->ike_sa
))
1028 me
= this->ike_sa
->get_my_host(this->ike_sa
);
1029 me
->set_port(me
, IKEV2_NATT_PORT
);
1030 other
= this->ike_sa
->get_other_host(this->ike_sa
);
1031 other
->set_port(other
, IKEV2_NATT_PORT
);
1033 this->logger
->log(this->logger
, CONTROL
|LEVEL1
, "switching to port %d", IKEV2_NATT_PORT
);
1037 /* because we are original initiator we have to update the responder SPI to the new one */
1038 ike_sa_id
= this->ike_sa
->get_id(this->ike_sa
);
1039 ike_sa_id
->set_responder_spi(ike_sa_id
, responder_spi
);
1041 /* derive all the keys used in the IKE_SA */
1042 if (this->ike_sa
->derive_keys(this->ike_sa
, this->proposal
,
1043 this->diffie_hellman
,
1044 this->nonce_i
, this->nonce_r
,
1045 TRUE
, NULL
, NULL
) != SUCCESS
)
1047 this->logger
->log(this->logger
, AUDIT
,
1048 "transform objects could not be created from selected proposal, deleting IKE_SA");
1052 this->ike_sa
->set_lifetimes(this->ike_sa
,
1053 this->connection
->get_soft_lifetime(this->connection
),
1054 this->connection
->get_hard_lifetime(this->connection
));
1056 { /* create ike_auth transaction, which will continue IKE_SA setup */
1057 chunk_t request_chunk
, response_chunk
;
1058 ike_auth_t
*ike_auth
;
1060 request_chunk
= this->message
->get_packet_data(this->message
);
1061 response_chunk
= response
->get_packet_data(response
);
1063 /* create next transaction, for which we except a message */
1064 ike_auth
= ike_auth_create(this->ike_sa
);
1065 ike_auth
->set_config(ike_auth
, this->connection
, this->policy
);
1066 ike_auth
->set_reqid(ike_auth
, this->reqid
);
1067 this->connection
= NULL
;
1068 this->policy
= NULL
;
1069 ike_auth
->set_nonces(ike_auth
,
1070 chunk_clone(this->nonce_i
),
1071 chunk_clone(this->nonce_r
));
1072 ike_auth
->set_init_messages(ike_auth
, request_chunk
, response_chunk
);
1073 *next
= (transaction_t
*)ike_auth
;
1079 static void destroy(private_ike_sa_init_t
*this)
1081 DESTROY_IF(this->message
);
1082 DESTROY_IF(this->diffie_hellman
);
1083 DESTROY_IF(this->proposal
);
1084 DESTROY_IF(this->connection
);
1085 DESTROY_IF(this->policy
);
1086 chunk_free(&this->nonce_i
);
1087 chunk_free(&this->nonce_r
);
1088 this->randomizer
->destroy(this->randomizer
);
1089 this->nat_hasher
->destroy(this->nat_hasher
);
1090 chunk_free(&this->natd_src_hash
);
1091 chunk_free(&this->natd_dst_hash
);
1096 * Described in header.
1098 ike_sa_init_t
*ike_sa_init_create(ike_sa_t
*ike_sa
)
1100 static u_int unique_id
= 0;
1101 private_ike_sa_init_t
*this = malloc_thing(private_ike_sa_init_t
);
1103 /* transaction interface functions */
1104 this->public.transaction
.get_request
= (status_t(*)(transaction_t
*,message_t
**))get_request
;
1105 this->public.transaction
.get_response
= (status_t(*)(transaction_t
*,message_t
*,message_t
**,transaction_t
**))get_response
;
1106 this->public.transaction
.conclude
= (status_t(*)(transaction_t
*,message_t
*,transaction_t
**))conclude
;
1107 this->public.transaction
.get_message_id
= (u_int32_t(*)(transaction_t
*))get_message_id
;
1108 this->public.transaction
.requested
= (u_int32_t(*)(transaction_t
*))requested
;
1109 this->public.transaction
.destroy
= (void(*)(transaction_t
*))destroy
;
1111 /* public functions */
1112 this->public.set_config
= (void(*)(ike_sa_init_t
*,connection_t
*,policy_t
*))set_config
;
1113 this->public.set_reqid
= (void(*)(ike_sa_init_t
*,u_int32_t
))set_reqid
;
1114 this->public.use_dh_group
= (bool(*)(ike_sa_init_t
*,diffie_hellman_group_t
))use_dh_group
;
1117 this->ike_sa
= ike_sa
;
1118 this->message_id
= 0;
1119 this->message
= NULL
;
1120 this->requested
= 0;
1121 this->diffie_hellman
= NULL
;
1122 this->nonce_i
= CHUNK_INITIALIZER
;
1123 this->nonce_r
= CHUNK_INITIALIZER
;
1124 this->connection
= NULL
;
1125 this->policy
= NULL
;
1126 this->proposal
= NULL
;
1127 this->unique_id
= ++unique_id
;
1129 this->randomizer
= randomizer_create();
1130 this->nat_hasher
= hasher_create(HASH_SHA1
);
1131 this->natd_src_hash
= CHUNK_INITIALIZER
;
1132 this->natd_dst_hash
= CHUNK_INITIALIZER
;
1133 this->natd_src_seen
= FALSE
;
1134 this->natd_dst_seen
= FALSE
;
1135 this->natd_src_matched
= FALSE
;
1136 this->natd_dst_matched
= FALSE
;
1137 this->logger
= logger_manager
->get_logger(logger_manager
, IKE_SA
);
1139 return &this->public;