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>
39 typedef struct private_ike_sa_init_t private_ike_sa_init_t
;
42 * Private members of a ike_sa_init_t object..
44 struct private_ike_sa_init_t
{
47 * Public methods and transaction_t interface.
57 * Message sent by our peer, if already generated
62 * Message ID this transaction uses
67 * Times we did send the request
72 * Next transaction followed to this one. May be IKE_AUTH,
73 * or a IKE_SA_INIT retry
78 * Diffie hellman object used to generate public DH value.
80 diffie_hellman_t
*diffie_hellman
;
83 * initiator chosen nonce
88 * responder chosen nonce
93 * connection definition used
95 connection_t
*connection
;
98 * Negotiated proposal used for IKE_SA
100 proposal_t
*proposal
;
103 * Randomizer to generate nonces
105 randomizer_t
*randomizer
;
108 * Hasher used to build NAT detection hashes
110 hasher_t
*nat_hasher
;
113 * Precomputed NAT hash for source address
115 chunk_t natd_src_hash
;
118 * Precomputed NAT hash for destination address
120 chunk_t natd_dst_hash
;
123 * Did we process any NAT detection notifys for a source address?
128 * Did we process any NAT detection notifys for a destination address?
133 * Have we found a matching source address NAT hash?
135 bool natd_src_matched
;
138 * Have we found a matching destination address NAT hash?
140 bool natd_dst_matched
;
149 * Implementation of ike_sa_init_t.use_dh_group.
151 static bool use_dh_group(private_ike_sa_init_t
*this, diffie_hellman_group_t dh_group
)
153 this->connection
= this->ike_sa
->get_connection(this->ike_sa
);
155 if (this->connection
->check_dh_group(this->connection
, dh_group
))
157 this->diffie_hellman
= diffie_hellman_create(dh_group
);
158 if (this->diffie_hellman
)
167 * Implementation of transaction_t.get_message_id.
169 static u_int32_t
get_message_id(private_ike_sa_init_t
*this)
171 return this->message_id
;
175 * Implementation of transaction_t.requested.
177 static u_int32_t
requested(private_ike_sa_init_t
*this)
179 return this->requested
++;
183 * Build NAT detection hash for a host
185 static chunk_t
generate_natd_hash(private_ike_sa_init_t
*this,
186 ike_sa_id_t
* ike_sa_id
, host_t
*host
)
191 u_int64_t spi_i
, spi_r
;
194 spi_i
= ike_sa_id
->get_initiator_spi(ike_sa_id
);
195 spi_r
= ike_sa_id
->get_responder_spi(ike_sa_id
);
197 switch (host
->get_family(host
))
201 struct sockaddr_in
* sai
;
202 natd_string
= chunk_alloc(sizeof(spi_i
) + sizeof(spi_r
) +
203 sizeof(sai
->sin_addr
.s_addr
) +
204 sizeof(sai
->sin_port
));
205 sai
= (struct sockaddr_in
*)host
->get_sockaddr(host
);
207 *(u_int64_t
*)p
= spi_i
; p
+= sizeof(spi_i
);
208 *(u_int64_t
*)p
= spi_r
; p
+= sizeof(spi_r
);
209 *(u_int32_t
*)p
= sai
->sin_addr
.s_addr
; p
+= sizeof(sai
->sin_addr
.s_addr
);
210 *(u_int16_t
*)p
= sai
->sin_port
; p
+= sizeof(sai
->sin_port
);
215 /* TODO: Add IPv6 support */
216 natd_string
= CHUNK_INITIALIZER
;
219 this->nat_hasher
->allocate_hash(this->nat_hasher
, natd_string
, &natd_hash
);
221 sprintf(buf
, "natd_hash(%016llx %016llx %s:%d) == SHA1(", spi_i
, spi_r
,
222 host
->get_string(host
), host
->get_port(host
));
223 chunk_to_hex(buf
+ strlen(buf
), sizeof(buf
) - strlen(buf
), natd_string
);
224 strcat(buf
, ") == ");
225 chunk_to_hex(buf
+ strlen(buf
), sizeof(buf
) - strlen(buf
), natd_hash
);
226 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, buf
);
228 chunk_free(&natd_string
);
233 * Build a NAT detection notify payload.
235 static notify_payload_t
*build_natd_payload(private_ike_sa_init_t
*this,
236 notify_type_t type
, host_t
*host
)
239 notify_payload_t
*notify
;
240 ike_sa_id_t
*ike_sa_id
;
242 ike_sa_id
= this->ike_sa
->get_id(this->ike_sa
);
243 notify
= notify_payload_create();
244 notify
->set_notify_type(notify
, type
);
245 hash
= generate_natd_hash(this, ike_sa_id
, host
);
246 notify
->set_notification_data(notify
, hash
);
253 * Implementation of transaction_t.get_request.
255 static status_t
get_request(private_ike_sa_init_t
*this, message_t
**result
)
260 /* check if we already have built a message (retransmission) */
263 *result
= this->message
;
267 this->connection
= this->ike_sa
->get_connection(this->ike_sa
);
268 me
= this->connection
->get_my_host(this->connection
);
269 other
= this->connection
->get_other_host(this->connection
);
271 /* build the request */
272 request
= message_create();
273 request
->set_source(request
, me
->clone(me
));
274 request
->set_destination(request
, other
->clone(other
));
275 request
->set_exchange_type(request
, IKE_SA_INIT
);
276 request
->set_request(request
, TRUE
);
277 request
->set_message_id(request
, this->message_id
);
278 request
->set_ike_sa_id(request
, this->ike_sa
->get_id(this->ike_sa
));
279 /* apply for caller */
281 /* store for retransmission */
282 this->message
= request
;
284 /* if the DH group is set via use_dh_group(), we already have a DH object */
285 if (!this->diffie_hellman
)
287 diffie_hellman_group_t dh_group
;
289 dh_group
= this->connection
->get_dh_group(this->connection
);
290 this->diffie_hellman
= diffie_hellman_create(dh_group
);
291 if (this->diffie_hellman
== NULL
)
293 this->logger
->log(this->logger
, AUDIT
,
294 "DH group %s (%d) not supported, aborting",
295 mapping_find(diffie_hellman_group_m
, dh_group
), dh_group
);
300 { /* build the SA payload from proposals */
301 sa_payload_t
*sa_payload
;
302 linked_list_t
*proposal_list
;
304 proposal_list
= this->connection
->get_proposals(this->connection
);
305 sa_payload
= sa_payload_create_from_proposal_list(proposal_list
);
307 request
->add_payload(request
, (payload_t
*)sa_payload
);
310 { /* build the KE payload from the DH object */
311 ke_payload_t
*ke_payload
;
313 ke_payload
= ke_payload_create_from_diffie_hellman(this->diffie_hellman
);
315 request
->add_payload(request
, (payload_t
*)ke_payload
);
318 { /* build the NONCE payload for us (initiator) */
319 nonce_payload_t
*nonce_payload
;
321 if (this->randomizer
->allocate_pseudo_random_bytes(this->randomizer
,
322 NONCE_SIZE
, &this->nonce_i
) != SUCCESS
)
326 nonce_payload
= nonce_payload_create();
327 nonce_payload
->set_nonce(nonce_payload
, this->nonce_i
);
329 request
->add_payload(request
, (payload_t
*)nonce_payload
);
332 { /* build NAT_DETECTION notifys */
333 notify_payload_t
*notify
;
334 iterator_t
*iterator
;
337 /* N(NAT_DETECTION_SOURCE_IP)+ */
338 iterator
= charon
->interfaces
->create_address_iterator(charon
->interfaces
);
339 while (iterator
->iterate(iterator
, (void**)&host
))
341 notify
= build_natd_payload(this, NAT_DETECTION_SOURCE_IP
, host
);
342 request
->add_payload(request
, (payload_t
*)notify
);
344 iterator
->destroy(iterator
);
346 /* N(NAT_DETECTION_DESTINATION_IP) */
347 notify
= build_natd_payload(this, NAT_DETECTION_DESTINATION_IP
, other
);
348 request
->add_payload(request
, (payload_t
*)notify
);
351 this->ike_sa
->set_state(this->ike_sa
, IKE_CONNECTING
);
356 * Handle all kind of notifys
358 static status_t
process_notifys(private_ike_sa_init_t
*this, notify_payload_t
*notify_payload
)
360 chunk_t notification_data
;
361 notify_type_t notify_type
= notify_payload
->get_notify_type(notify_payload
);
363 this->logger
->log(this->logger
, CONTROL
|LEVEL1
, "process notify type %s",
364 mapping_find(notify_type_m
, notify_type
));
368 case NO_PROPOSAL_CHOSEN
:
370 this->logger
->log(this->logger
, AUDIT
,
371 "received a NO_PROPOSAL_CHOSEN notify, deleting IKE_SA");
374 case INVALID_MAJOR_VERSION
:
376 this->logger
->log(this->logger
, AUDIT
,
377 "received a INVALID_MAJOR_VERSION notify, deleting IKE_SA");
380 case INVALID_KE_PAYLOAD
:
383 diffie_hellman_group_t dh_group
, old_dh_group
;
384 ike_sa_init_t
*retry
;
386 old_dh_group
= this->connection
->get_dh_group(this->connection
);
387 notify_data
= notify_payload
->get_notification_data(notify_payload
);
388 dh_group
= ntohs(*((u_int16_t
*)notify_data
.ptr
));
390 this->logger
->log(this->logger
, AUDIT
,
391 "peer didn't accept DH group %s, it requested %s",
392 mapping_find(diffie_hellman_group_m
, old_dh_group
),
393 mapping_find(diffie_hellman_group_m
, dh_group
));
394 if (!this->connection
->check_dh_group(this->connection
, dh_group
))
396 this->logger
->log(this->logger
, AUDIT
,
397 "requested DH group not acceptable, aborting");
400 retry
= ike_sa_init_create(this->ike_sa
);
401 retry
->use_dh_group(retry
, dh_group
);
402 *this->next
= (transaction_t
*)retry
;
405 case NAT_DETECTION_DESTINATION_IP
:
407 this->natd_dst_seen
= TRUE
;
408 if (this->natd_dst_matched
)
412 notification_data
= notify_payload
->get_notification_data(notify_payload
);
413 if (chunk_equals(notification_data
, this->natd_dst_hash
))
415 this->natd_dst_matched
= TRUE
;
416 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, "NAT-D dst hash match");
420 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, "NAT-D dst hash mismatch");
424 case NAT_DETECTION_SOURCE_IP
:
426 this->natd_src_seen
= TRUE
;;
427 if (this->natd_src_matched
)
431 notification_data
= notify_payload
->get_notification_data(notify_payload
);
432 if (chunk_equals(notification_data
, this->natd_src_hash
))
434 this->natd_src_matched
= TRUE
;
435 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, "NAT-D src hash match");
439 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, "NAT-D src hash mismatch");
445 if (notify_type
< 16383)
447 this->logger
->log(this->logger
, AUDIT
,
448 "received %s notify error (%d), deleting IKE_SA",
449 mapping_find(notify_type_m
, notify_type
),
455 this->logger
->log(this->logger
, CONTROL
,
456 "received %s notify (%d), ignored",
457 mapping_find(notify_type_m
, notify_type
),
466 * Implementation of transaction_t.get_response.
468 static status_t
get_response(private_ike_sa_init_t
*this,
469 message_t
*request
, message_t
**result
,
470 transaction_t
**next
)
475 iterator_t
*payloads
;
476 sa_payload_t
*sa_request
= NULL
;
477 ke_payload_t
*ke_request
= NULL
;
478 nonce_payload_t
*nonce_request
= NULL
;
479 ike_sa_id_t
*ike_sa_id
;
482 /* check if we already have built a response (retransmission) */
485 *result
= this->message
;
489 me
= request
->get_destination(request
);
490 other
= request
->get_source(request
);
491 this->message_id
= request
->get_message_id(request
);
493 /* set up response */
494 response
= message_create();
495 response
->set_source(response
, me
->clone(me
));
496 response
->set_destination(response
, other
->clone(other
));
497 response
->set_exchange_type(response
, IKE_SA_INIT
);
498 response
->set_request(response
, FALSE
);
499 response
->set_message_id(response
, this->message_id
);
500 response
->set_ike_sa_id(response
, this->ike_sa
->get_id(this->ike_sa
));
501 this->message
= response
;
504 /* check message type */
505 if (request
->get_exchange_type(request
) != IKE_SA_INIT
)
507 this->logger
->log(this->logger
, ERROR
,
508 "IKE_SA_INIT request of invalid type, deleting IKE_SA");
512 /* this is the first message to process, find a connection for IKE_SA */
513 this->connection
= charon
->connections
->get_connection_by_hosts(
514 charon
->connections
, me
, other
);
515 if (this->connection
== NULL
)
517 notify_payload_t
*notify
= notify_payload_create();
518 notify
->set_notify_type(notify
, NO_PROPOSAL_CHOSEN
);
519 response
->add_payload(response
, (payload_t
*)notify
);
521 this->logger
->log(this->logger
, AUDIT
,
522 "no connection for hosts %s...%s found, deleting IKE_SA",
523 me
->get_string(me
), other
->get_string(other
));
526 this->ike_sa
->set_connection(this->ike_sa
, this->connection
);
528 /* Precompute NAT-D hashes for incoming NAT notify comparison */
529 ike_sa_id
= request
->get_ike_sa_id(request
);
530 this->natd_dst_hash
= generate_natd_hash(this, ike_sa_id
, me
);
531 this->natd_src_hash
= generate_natd_hash(this, ike_sa_id
, other
);
533 /* Iterate over all payloads. */
534 payloads
= request
->get_payload_iterator(request
);
535 while (payloads
->has_next(payloads
))
538 payloads
->current(payloads
, (void**)&payload
);
539 switch (payload
->get_type(payload
))
541 case SECURITY_ASSOCIATION
:
542 sa_request
= (sa_payload_t
*)payload
;
545 ke_request
= (ke_payload_t
*)payload
;
548 nonce_request
= (nonce_payload_t
*)payload
;
552 status
= process_notifys(this, (notify_payload_t
*)payload
);
553 if (status
== FAILED
)
555 payloads
->destroy(payloads
);
556 /* we return SUCCESS, returned FAILED means do next transaction */
559 if (status
== DESTROY_ME
)
561 payloads
->destroy(payloads
);
568 this->logger
->log(this->logger
, ERROR
|LEVEL1
,
569 "ignoring %s payload (%d)",
570 mapping_find(payload_type_m
, payload
->get_type(payload
)),
571 payload
->get_type(payload
));
576 payloads
->destroy(payloads
);
578 /* check if we have all payloads */
579 if (!(sa_request
&& ke_request
&& nonce_request
))
581 notify_payload_t
*notify
= notify_payload_create();
582 notify
->set_notify_type(notify
, INVALID_SYNTAX
);
583 response
->add_payload(response
, (payload_t
*)notify
);
584 this->logger
->log(this->logger
, AUDIT
,
585 "request message incomplete, deleting IKE_SA");
589 { /* process SA payload:
590 * -------------------
591 * - extract proposals
592 * - select our most preferred proposal found in extracted
593 * - if no matches, return NO_PROPOSAL_CHOSEN
594 * - add sa payload with selected proposal
596 sa_payload_t
* sa_response
;
597 linked_list_t
*proposal_list
;
598 proposal_t
*proposal
;
600 proposal_list
= sa_request
->get_proposals(sa_request
);
601 this->proposal
= this->connection
->select_proposal(this->connection
, proposal_list
);
602 while(proposal_list
->remove_last(proposal_list
, (void**)&proposal
) == SUCCESS
)
604 proposal
->destroy(proposal
);
606 proposal_list
->destroy(proposal_list
);
607 if (this->proposal
== NULL
)
609 notify_payload_t
*notify
= notify_payload_create();
610 notify
->set_notify_type(notify
, NO_PROPOSAL_CHOSEN
);
611 response
->add_payload(response
, (payload_t
*)notify
);
612 this->logger
->log(this->logger
, AUDIT
,
613 "request did not contain any acceptable proposals, deleting IKE_SA");
616 sa_response
= sa_payload_create_from_proposal(this->proposal
);
617 response
->add_payload(response
, (payload_t
*)sa_response
);
620 { /* process KE payload:
621 * --------------------
622 * - check if used group match the selected proposal
623 * - if not, stop with INVALID_KE_PAYLOAD
624 * - apply others public value to complete diffie hellman exchange
625 * - add our public value to response
627 diffie_hellman_group_t used_group
;
628 ke_payload_t
*ke_response
;
630 used_group
= ke_request
->get_dh_group_number(ke_request
);
632 if (!this->connection
->check_dh_group(this->connection
, used_group
) ||
633 (this->diffie_hellman
= diffie_hellman_create(used_group
)) == NULL
)
635 u_int16_t notify_group
;
636 chunk_t notify_chunk
;
637 notify_payload_t
*notify
;
638 iterator_t
*iterator
;
641 notify_group
= this->connection
->get_dh_group(this->connection
);
642 this->logger
->log(this->logger
, AUDIT
,
643 "request used inacceptable DH group %s, sending INVALID_KE_PAYLOAD with %s, deleting IKE_SA",
644 mapping_find(diffie_hellman_group_m
, used_group
),
645 mapping_find(diffie_hellman_group_m
, notify_group
));
647 /* remove already added payloads */
648 iterator
= response
->get_payload_iterator(response
);
649 while (iterator
->has_next(iterator
))
651 iterator
->current(iterator
, (void**)&payload
);
652 iterator
->remove(iterator
);
653 payload
->destroy(payload
);
655 iterator
->destroy(iterator
);
657 notify_group
= htons(notify_group
);
658 notify_chunk
.ptr
= (u_int8_t
*)¬ify_group
;
659 notify_chunk
.len
= sizeof(notify_group
);
660 notify
= notify_payload_create();
661 notify
->set_notify_type(notify
, INVALID_KE_PAYLOAD
);
662 notify
->set_notification_data(notify
, notify_chunk
);
663 response
->add_payload(response
, (payload_t
*)notify
);
666 this->diffie_hellman
->set_other_public_value(this->diffie_hellman
,
667 ke_request
->get_key_exchange_data(ke_request
));
670 ke_response
= ke_payload_create_from_diffie_hellman(this->diffie_hellman
);
671 response
->add_payload(response
, (payload_t
*)ke_response
);
674 { /* process nonce payload:
675 * ----------------------
676 * - get nonce from payload
677 * - generate own nonce and add to reply
679 nonce_payload_t
*nonce_response
;
681 this->nonce_i
= nonce_request
->get_nonce(nonce_request
);
683 /* build response nonce */
684 if (this->randomizer
->allocate_pseudo_random_bytes(this->randomizer
,
685 NONCE_SIZE
, &this->nonce_r
) != SUCCESS
)
687 notify_payload_t
*notify
= notify_payload_create();
688 notify
->set_notify_type(notify
, NO_PROPOSAL_CHOSEN
);
689 response
->add_payload(response
, (payload_t
*)notify
);
690 this->logger
->log(this->logger
, AUDIT
,
691 "could not get random bytes for nonce, deleting IKE_SA");
694 nonce_response
= nonce_payload_create();
695 nonce_response
->set_nonce(nonce_response
, this->nonce_r
);
696 response
->add_payload(response
, (payload_t
*)nonce_response
);
699 { /* processs NATT stuff:
700 * --------------------
701 * - check if we or other is behind NAT
702 * - enable NATT if so
703 * - build NAT detection notifys for reply
705 notify_payload_t
*notify
;
707 if ((!this->natd_src_seen
&& this->natd_dst_seen
) ||
708 (this->natd_src_seen
&& !this->natd_dst_seen
))
710 notify
= notify_payload_create();
711 notify
->set_notify_type(notify
, INVALID_SYNTAX
);
712 response
->add_payload(response
, (payload_t
*)notify
);
713 this->logger
->log(this->logger
, AUDIT
,
714 "request contained wrong number of NAT-D payloads, deleting IKE_SA");
717 if (this->natd_dst_seen
&& !this->natd_dst_matched
)
719 this->ike_sa
->enable_natt(this->ike_sa
, TRUE
);
721 if (this->natd_src_seen
&& !this->natd_src_matched
)
723 this->ike_sa
->enable_natt(this->ike_sa
, FALSE
);
725 /* build response NAT DETECTION notifys, if remote supports it */
726 if (this->natd_src_seen
|| this->natd_dst_seen
)
728 /* N(NAT_DETECTION_SOURCE_IP) */
729 notify
= build_natd_payload(this, NAT_DETECTION_SOURCE_IP
, me
);
730 response
->add_payload(response
, (payload_t
*)notify
);
732 /* N(NAT_DETECTION_DESTINATION_IP) */
733 notify
= build_natd_payload(this, NAT_DETECTION_DESTINATION_IP
, other
);
734 response
->add_payload(response
, (payload_t
*)notify
);
738 /* derive all the keys used in the IKE_SA */
739 if (this->ike_sa
->build_transforms(this->ike_sa
, this->proposal
,
740 this->diffie_hellman
,
741 this->nonce_i
, this->nonce_r
,
744 notify_payload_t
*notify
= notify_payload_create();
745 notify
->set_notify_type(notify
, NO_PROPOSAL_CHOSEN
);
746 response
->add_payload(response
, (payload_t
*)notify
);
747 this->logger
->log(this->logger
, AUDIT
,
748 "transform objects could not be created from selected proposal, deleting IKE_SA");
752 { /* create ike_auth transaction, which will store informations for us */
753 packet_t
*response_packet
;
754 chunk_t request_chunk
, response_chunk
;
755 ike_auth_t
*ike_auth
;
757 /* we normally do not generate the message. But we need the generated message
758 * for authentication in the next state, so we do it here. This is not problematic,
759 * as we don't use a crypter/signer in ike_sa_init... */
760 if (response
->generate(response
, NULL
, NULL
, &response_packet
) != SUCCESS
)
762 this->logger
->log(this->logger
, AUDIT
,
763 "error in response generation, deleting IKE_SA");
766 response_packet
->destroy(response_packet
);
767 request_chunk
= request
->get_packet_data(request
);
768 response_chunk
= response
->get_packet_data(response
);
770 /* create next transaction, for which we except a message */
771 ike_auth
= ike_auth_create(this->ike_sa
);
772 ike_auth
->set_nonces(ike_auth
,
773 chunk_clone(this->nonce_i
),
774 chunk_clone(this->nonce_r
));
775 ike_auth
->set_init_messages(ike_auth
, request_chunk
, response_chunk
);
776 *next
= (transaction_t
*)ike_auth
;
779 /* everything went fine. Now we set a timeout to destroy half initiated IKE_SAs */
780 timeout
= charon
->configuration
->get_half_open_ike_sa_timeout(charon
->configuration
);
783 job_t
*job
= (job_t
*)delete_half_open_ike_sa_job_create(this->ike_sa
->get_id(this->ike_sa
));
784 charon
->event_queue
->add_relative(charon
->event_queue
, job
, timeout
);
787 this->ike_sa
->set_state(this->ike_sa
, IKE_CONNECTING
);
793 * Implementation of transaction_t.conclude
795 static status_t
conclude(private_ike_sa_init_t
*this, message_t
*response
,
796 transaction_t
**next
)
798 u_int64_t responder_spi
;
799 ike_sa_id_t
*ike_sa_id
;
800 iterator_t
*payloads
;
802 sa_payload_t
*sa_payload
= NULL
;
803 ke_payload_t
*ke_payload
= NULL
;
804 nonce_payload_t
*nonce_payload
= NULL
;
808 /* check message type */
809 if (response
->get_exchange_type(response
) != IKE_SA_INIT
)
811 this->logger
->log(this->logger
, ERROR
,
812 "IKE_SA_INIT response of invalid type, deleting IKE_SA");
816 /* allow setting of next transaction in other functions */
819 this->connection
= this->ike_sa
->get_connection(this->ike_sa
);
820 me
= this->connection
->get_my_host(this->connection
);
821 other
= this->connection
->get_other_host(this->connection
);
823 /* check if SPI has been updated, but apply only if all goes ok later */
824 responder_spi
= response
->get_responder_spi(response
);
825 if (responder_spi
== 0)
827 this->logger
->log(this->logger
, ERROR
,
828 "response contained a SPI of zero, deleting IKE_SA");
832 /* Precompute NAT-D hashes for later comparison */
833 ike_sa_id
= response
->get_ike_sa_id(response
);
834 this->natd_src_hash
= generate_natd_hash(this, ike_sa_id
, other
);
835 this->natd_dst_hash
= generate_natd_hash(this, ike_sa_id
, me
);
837 /* Iterate over all payloads to collect them */
838 payloads
= response
->get_payload_iterator(response
);
839 while (payloads
->has_next(payloads
))
842 payloads
->current(payloads
, (void**)&payload
);
844 switch (payload
->get_type(payload
))
846 case SECURITY_ASSOCIATION
:
848 sa_payload
= (sa_payload_t
*)payload
;
853 ke_payload
= (ke_payload_t
*)payload
;
858 nonce_payload
= (nonce_payload_t
*)payload
;
863 status
= process_notifys(this, (notify_payload_t
*)payload
);
864 if (status
== FAILED
)
866 payloads
->destroy(payloads
);
867 /* we return SUCCESS, returned FAILED means do next transaction */
870 if (status
== DESTROY_ME
)
872 payloads
->destroy(payloads
);
879 this->logger
->log(this->logger
, ERROR
, "ignoring payload %s (%d)",
880 mapping_find(payload_type_m
, payload
->get_type(payload
)),
881 payload
->get_type(payload
));
886 payloads
->destroy(payloads
);
888 if (!(nonce_payload
&& sa_payload
&& ke_payload
))
890 this->logger
->log(this->logger
, AUDIT
, "response message incomplete, deleting IKE_SA");
894 { /* process SA payload:
895 * -------------------
896 * - get proposals from it
897 * - check if peer selected a proposal
898 * - verify it's selection againts our set
900 proposal_t
*proposal
;
901 linked_list_t
*proposal_list
;
903 /* get the list of selected proposals, the peer has to select only one proposal */
904 proposal_list
= sa_payload
->get_proposals (sa_payload
);
905 if (proposal_list
->get_count(proposal_list
) != 1)
907 this->logger
->log(this->logger
, AUDIT
,
908 "response did not contain a single proposal, deleting IKE_SA");
909 while (proposal_list
->remove_last(proposal_list
, (void**)&proposal
) == SUCCESS
)
911 proposal
->destroy(proposal
);
913 proposal_list
->destroy(proposal_list
);
917 /* we have to re-check if the others selection is valid */
918 this->proposal
= this->connection
->select_proposal(this->connection
, proposal_list
);
919 while (proposal_list
->remove_last(proposal_list
, (void**)&proposal
) == SUCCESS
)
921 proposal
->destroy(proposal
);
923 proposal_list
->destroy(proposal_list
);
925 if (this->proposal
== NULL
)
927 this->logger
->log(this->logger
, AUDIT
,
928 "peer selected a proposal we did not offer, deleting IKE_SA");
933 { /* process KE payload:
934 * -------------------
935 * - extract others public value
936 * - complete diffie-hellman exchange
938 this->diffie_hellman
->set_other_public_value(this->diffie_hellman
,
939 ke_payload
->get_key_exchange_data(ke_payload
));
942 { /* process NONCE payload:
943 * ----------------------
944 * - extract nonce used for key derivation */
945 this->nonce_r
= nonce_payload
->get_nonce(nonce_payload
);
948 { /* process NATT stuff:
949 * -------------------
950 * - check if we or other is NATted
951 * - switch to port 4500 if so
953 if ((!this->natd_dst_seen
&& this->natd_src_seen
) ||
954 (this->natd_dst_seen
&& !this->natd_src_seen
))
956 this->logger
->log(this->logger
, AUDIT
,
957 "request contained wrong number of NAT-D payloads, deleting IKE_SA");
960 if (this->natd_src_seen
&& !this->natd_src_matched
)
962 this->ike_sa
->enable_natt(this->ike_sa
, FALSE
);
964 if (this->natd_dst_seen
&& !this->natd_dst_matched
)
966 this->ike_sa
->enable_natt(this->ike_sa
, TRUE
);
968 if (this->ike_sa
->is_natt_enabled(this->ike_sa
))
970 me
->set_port(me
, IKEV2_NATT_PORT
);
971 other
->set_port(other
, IKEV2_NATT_PORT
);
972 this->logger
->log(this->logger
, CONTROL
|LEVEL1
, "switching to port %d", IKEV2_NATT_PORT
);
974 policy
= this->ike_sa
->get_policy(this->ike_sa
);
975 policy
->update_my_ts(policy
, me
);
976 policy
->update_other_ts(policy
, other
);
979 /* because we are original initiator we have to update the responder SPI to the new one */
980 ike_sa_id
= this->ike_sa
->get_id(this->ike_sa
);
981 ike_sa_id
->set_responder_spi(ike_sa_id
, responder_spi
);
983 /* derive all the keys used in the IKE_SA */
984 if (this->ike_sa
->build_transforms(this->ike_sa
, this->proposal
,
985 this->diffie_hellman
,
986 this->nonce_i
, this->nonce_r
,
989 this->logger
->log(this->logger
, AUDIT
,
990 "transform objects could not be created from selected proposal, deleting IKE_SA");
994 { /* create ike_auth transaction, which will continue IKE_SA setup */
995 chunk_t request_chunk
, response_chunk
;
996 ike_auth_t
*ike_auth
;
998 request_chunk
= this->message
->get_packet_data(this->message
);
999 response_chunk
= response
->get_packet_data(response
);
1001 /* create next transaction, for which we except a message */
1002 ike_auth
= ike_auth_create(this->ike_sa
);
1003 ike_auth
->set_nonces(ike_auth
,
1004 chunk_clone(this->nonce_i
),
1005 chunk_clone(this->nonce_r
));
1006 ike_auth
->set_init_messages(ike_auth
, request_chunk
, response_chunk
);
1007 *next
= (transaction_t
*)ike_auth
;
1013 static void destroy(private_ike_sa_init_t
*this)
1017 this->message
->destroy(this->message
);
1019 if (this->diffie_hellman
)
1021 this->diffie_hellman
->destroy(this->diffie_hellman
);
1025 this->proposal
->destroy(this->proposal
);
1027 chunk_free(&this->nonce_i
);
1028 chunk_free(&this->nonce_r
);
1029 this->randomizer
->destroy(this->randomizer
);
1030 this->nat_hasher
->destroy(this->nat_hasher
);
1031 chunk_free(&this->natd_src_hash
);
1032 chunk_free(&this->natd_dst_hash
);
1037 * Described in header.
1039 ike_sa_init_t
*ike_sa_init_create(ike_sa_t
*ike_sa
)
1041 private_ike_sa_init_t
*this = malloc_thing(private_ike_sa_init_t
);
1043 /* transaction interface functions */
1044 this->public.transaction
.get_request
= (status_t(*)(transaction_t
*,message_t
**))get_request
;
1045 this->public.transaction
.get_response
= (status_t(*)(transaction_t
*,message_t
*,message_t
**,transaction_t
**))get_response
;
1046 this->public.transaction
.conclude
= (status_t(*)(transaction_t
*,message_t
*,transaction_t
**))conclude
;
1047 this->public.transaction
.get_message_id
= (u_int32_t(*)(transaction_t
*))get_message_id
;
1048 this->public.transaction
.requested
= (u_int32_t(*)(transaction_t
*))requested
;
1049 this->public.transaction
.destroy
= (void(*)(transaction_t
*))destroy
;
1051 /* public functions */
1052 this->public.use_dh_group
= (bool(*)(ike_sa_init_t
*,diffie_hellman_group_t
))use_dh_group
;
1055 this->ike_sa
= ike_sa
;
1056 this->message_id
= 0;
1057 this->message
= NULL
;
1058 this->requested
= 0;
1059 this->diffie_hellman
= NULL
;
1060 this->nonce_i
= CHUNK_INITIALIZER
;
1061 this->nonce_r
= CHUNK_INITIALIZER
;
1062 this->connection
= NULL
;
1063 this->proposal
= NULL
;
1064 this->randomizer
= randomizer_create();
1065 this->nat_hasher
= hasher_create(HASH_SHA1
);
1066 this->natd_src_hash
= CHUNK_INITIALIZER
;
1067 this->natd_dst_hash
= CHUNK_INITIALIZER
;
1068 this->natd_src_seen
= FALSE
;
1069 this->natd_dst_seen
= FALSE
;
1070 this->natd_src_matched
= FALSE
;
1071 this->natd_dst_matched
= FALSE
;
1072 this->logger
= logger_manager
->get_logger(logger_manager
, IKE_SA
);
1074 return &this->public;