4 * @brief Implementation of ike_sa_init_t transaction.
9 * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
10 * Copyright (C) 2005 Jan Hutter, Martin Willi
11 * Hochschule fuer Technik Rapperswil
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 #include "ike_sa_init.h"
29 #include <crypto/diffie_hellman.h>
30 #include <crypto/hashers/hasher.h>
31 #include <encoding/payloads/sa_payload.h>
32 #include <encoding/payloads/ke_payload.h>
33 #include <encoding/payloads/nonce_payload.h>
34 #include <sa/transactions/ike_auth.h>
35 #include <queues/jobs/delete_half_open_ike_sa_job.h>
38 typedef struct private_ike_sa_init_t private_ike_sa_init_t
;
41 * Private members of a ike_sa_init_t object..
43 struct private_ike_sa_init_t
{
46 * Public methods and transaction_t interface.
56 * Message sent by our peer, if already generated
61 * Message ID this transaction uses
66 * Times we did send the request
71 * Next transaction followed to this one. May be IKE_AUTH,
72 * or a IKE_SA_INIT retry
77 * Diffie hellman object used to generate public DH value.
79 diffie_hellman_t
*diffie_hellman
;
82 * initiator chosen nonce
87 * responder chosen nonce
92 * connection definition used
94 connection_t
*connection
;
97 * Negotiated proposal used for IKE_SA
102 * Randomizer to generate nonces
104 randomizer_t
*randomizer
;
107 * Hasher used to build NAT detection hashes
109 hasher_t
*nat_hasher
;
112 * Precomputed NAT hash for source address
114 chunk_t natd_src_hash
;
117 * Precomputed NAT hash for destination address
119 chunk_t natd_dst_hash
;
122 * Did we process any NAT detection notifys for a source address?
127 * Did we process any NAT detection notifys for a destination address?
132 * Have we found a matching source address NAT hash?
134 bool natd_src_matched
;
137 * Have we found a matching destination address NAT hash?
139 bool natd_dst_matched
;
148 * Implementation of ike_sa_init_t.use_dh_group.
150 static bool use_dh_group(private_ike_sa_init_t
*this, diffie_hellman_group_t dh_group
)
152 this->connection
= this->ike_sa
->get_connection(this->ike_sa
);
154 if (this->connection
->check_dh_group(this->connection
, dh_group
))
156 this->diffie_hellman
= diffie_hellman_create(dh_group
);
157 if (this->diffie_hellman
)
166 * Implementation of transaction_t.get_message_id.
168 static u_int32_t
get_message_id(private_ike_sa_init_t
*this)
170 return this->message_id
;
174 * Implementation of transaction_t.requested.
176 static u_int32_t
requested(private_ike_sa_init_t
*this)
178 return this->requested
++;
182 * Build NAT detection hash for a host
184 static chunk_t
generate_natd_hash(private_ike_sa_init_t
*this,
185 ike_sa_id_t
* ike_sa_id
, host_t
*host
)
190 u_int64_t spi_i
, spi_r
;
193 spi_i
= ike_sa_id
->get_initiator_spi(ike_sa_id
);
194 spi_r
= ike_sa_id
->get_responder_spi(ike_sa_id
);
196 switch (host
->get_family(host
))
200 struct sockaddr_in
* sai
;
201 natd_string
= chunk_alloc(sizeof(spi_i
) + sizeof(spi_r
) +
202 sizeof(sai
->sin_addr
.s_addr
) +
203 sizeof(sai
->sin_port
));
204 sai
= (struct sockaddr_in
*)host
->get_sockaddr(host
);
206 *(u_int64_t
*)p
= spi_i
; p
+= sizeof(spi_i
);
207 *(u_int64_t
*)p
= spi_r
; p
+= sizeof(spi_r
);
208 *(u_int32_t
*)p
= sai
->sin_addr
.s_addr
; p
+= sizeof(sai
->sin_addr
.s_addr
);
209 *(u_int16_t
*)p
= sai
->sin_port
; p
+= sizeof(sai
->sin_port
);
214 /* TODO: Add IPv6 support */
215 natd_string
= CHUNK_INITIALIZER
;
218 this->nat_hasher
->allocate_hash(this->nat_hasher
, natd_string
, &natd_hash
);
220 sprintf(buf
, "natd_hash(%016llx %016llx %s:%d) == SHA1(", spi_i
, spi_r
,
221 host
->get_address(host
), host
->get_port(host
));
222 chunk_to_hex(buf
+ strlen(buf
), sizeof(buf
) - strlen(buf
), natd_string
);
223 strcat(buf
, ") == ");
224 chunk_to_hex(buf
+ strlen(buf
), sizeof(buf
) - strlen(buf
), natd_hash
);
225 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, buf
);
227 chunk_free(&natd_string
);
232 * Build a NAT detection notify payload.
234 static notify_payload_t
*build_natd_payload(private_ike_sa_init_t
*this,
235 notify_type_t type
, host_t
*host
)
238 notify_payload_t
*notify
;
239 ike_sa_id_t
*ike_sa_id
;
241 ike_sa_id
= this->ike_sa
->get_id(this->ike_sa
);
242 notify
= notify_payload_create();
243 notify
->set_notify_type(notify
, type
);
244 hash
= generate_natd_hash(this, ike_sa_id
, host
);
245 notify
->set_notification_data(notify
, hash
);
252 * Implementation of transaction_t.get_request.
254 static status_t
get_request(private_ike_sa_init_t
*this, message_t
**result
)
259 /* check if we already have built a message (retransmission) */
262 *result
= this->message
;
266 this->connection
= this->ike_sa
->get_connection(this->ike_sa
);
267 me
= this->connection
->get_my_host(this->connection
);
268 other
= this->connection
->get_other_host(this->connection
);
270 /* build the request */
271 request
= message_create();
272 request
->set_source(request
, me
->clone(me
));
273 request
->set_destination(request
, other
->clone(other
));
274 request
->set_exchange_type(request
, IKE_SA_INIT
);
275 request
->set_request(request
, TRUE
);
276 request
->set_message_id(request
, this->message_id
);
277 request
->set_ike_sa_id(request
, this->ike_sa
->get_id(this->ike_sa
));
278 /* apply for caller */
280 /* store for retransmission */
281 this->message
= request
;
283 /* if the DH group is set via use_dh_group(), we already have a DH object */
284 if (!this->diffie_hellman
)
286 diffie_hellman_group_t dh_group
;
288 dh_group
= this->connection
->get_dh_group(this->connection
);
289 this->diffie_hellman
= diffie_hellman_create(dh_group
);
290 if (this->diffie_hellman
== NULL
)
292 this->logger
->log(this->logger
, AUDIT
,
293 "DH group %s (%d) not supported, aborting",
294 mapping_find(diffie_hellman_group_m
, dh_group
), dh_group
);
299 { /* build the SA payload from proposals */
300 sa_payload_t
*sa_payload
;
301 linked_list_t
*proposal_list
;
303 proposal_list
= this->connection
->get_proposals(this->connection
);
304 sa_payload
= sa_payload_create_from_proposal_list(proposal_list
);
306 request
->add_payload(request
, (payload_t
*)sa_payload
);
309 { /* build the KE payload from the DH object */
310 ke_payload_t
*ke_payload
;
312 ke_payload
= ke_payload_create_from_diffie_hellman(this->diffie_hellman
);
314 request
->add_payload(request
, (payload_t
*)ke_payload
);
317 { /* build the NONCE payload for us (initiator) */
318 nonce_payload_t
*nonce_payload
;
319 randomizer_t
*randomizer
;
321 randomizer
= randomizer_create();
322 if (randomizer
->allocate_pseudo_random_bytes(randomizer
,
323 NONCE_SIZE
, &this->nonce_i
) != SUCCESS
)
325 randomizer
->destroy(randomizer
);
326 request
->destroy(request
);
329 randomizer
->destroy(randomizer
);
330 nonce_payload
= nonce_payload_create();
331 nonce_payload
->set_nonce(nonce_payload
, this->nonce_i
);
333 request
->add_payload(request
, (payload_t
*)nonce_payload
);
336 { /* build NAT_DETECTION notifys */
337 notify_payload_t
*notify
;
338 iterator_t
*iterator
;
341 /* N(NAT_DETECTION_SOURCE_IP)+ */
342 iterator
= charon
->interfaces
->create_address_iterator(charon
->interfaces
);
343 while (iterator
->iterate(iterator
, (void**)&host
))
345 notify
= build_natd_payload(this, NAT_DETECTION_SOURCE_IP
, host
);
346 request
->add_payload(request
, (payload_t
*)notify
);
348 iterator
->destroy(iterator
);
350 /* N(NAT_DETECTION_DESTINATION_IP) */
351 notify
= build_natd_payload(this, NAT_DETECTION_DESTINATION_IP
, other
);
352 request
->add_payload(request
, (payload_t
*)notify
);
356 this->ike_sa
->set_state(this->ike_sa
, SA_CONNECTING
);
361 * Handle all kind of notifys
363 static status_t
process_notifys(private_ike_sa_init_t
*this, notify_payload_t
*notify_payload
)
365 chunk_t notification_data
;
366 notify_type_t notify_type
= notify_payload
->get_notify_type(notify_payload
);
368 this->logger
->log(this->logger
, CONTROL
|LEVEL1
, "process notify type %s",
369 mapping_find(notify_type_m
, notify_type
));
373 case NO_PROPOSAL_CHOSEN
:
375 this->logger
->log(this->logger
, AUDIT
,
376 "received a NO_PROPOSAL_CHOSEN notify, deleting IKE_SA");
379 case INVALID_MAJOR_VERSION
:
381 this->logger
->log(this->logger
, AUDIT
,
382 "received a INVALID_MAJOR_VERSION notify, deleting IKE_SA");
385 case INVALID_KE_PAYLOAD
:
388 diffie_hellman_group_t dh_group
, old_dh_group
;
389 ike_sa_init_t
*retry
;
391 old_dh_group
= this->connection
->get_dh_group(this->connection
);
392 notify_data
= notify_payload
->get_notification_data(notify_payload
);
393 dh_group
= ntohs(*((u_int16_t
*)notify_data
.ptr
));
395 this->logger
->log(this->logger
, AUDIT
,
396 "peer didn't accept DH group %s, it requested %s",
397 mapping_find(diffie_hellman_group_m
, old_dh_group
),
398 mapping_find(diffie_hellman_group_m
, dh_group
));
399 if (!this->connection
->check_dh_group(this->connection
, dh_group
))
401 this->logger
->log(this->logger
, AUDIT
,
402 "requested DH group not acceptable, aborting");
405 retry
= ike_sa_init_create(this->ike_sa
, 0);
406 retry
->use_dh_group(retry
, dh_group
);
407 *this->next
= (transaction_t
*)retry
;
410 case NAT_DETECTION_DESTINATION_IP
:
412 this->natd_dst_seen
= TRUE
;
413 if (this->natd_dst_matched
)
417 notification_data
= notify_payload
->get_notification_data(notify_payload
);
418 if (chunk_equals(notification_data
, this->natd_dst_hash
))
420 this->natd_dst_matched
= TRUE
;
421 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, "NAT-D dst hash match");
425 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, "NAT-D dst hash mismatch");
429 case NAT_DETECTION_SOURCE_IP
:
431 this->natd_src_seen
= TRUE
;;
432 if (this->natd_src_matched
)
436 notification_data
= notify_payload
->get_notification_data(notify_payload
);
437 if (chunk_equals(notification_data
, this->natd_src_hash
))
439 this->natd_src_matched
= TRUE
;
440 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, "NAT-D src hash match");
444 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, "NAT-D src hash mismatch");
450 if (notify_type
< 16383)
452 this->logger
->log(this->logger
, AUDIT
,
453 "received %s notify error (%d), deleting IKE_SA",
454 mapping_find(notify_type_m
, notify_type
),
460 this->logger
->log(this->logger
, CONTROL
,
461 "received %s notify (%d), ignored",
462 mapping_find(notify_type_m
, notify_type
),
471 * Implementation of transaction_t.get_response.
473 static status_t
get_response(private_ike_sa_init_t
*this,
474 message_t
*request
, message_t
**result
,
475 transaction_t
**next
)
480 iterator_t
*payloads
;
481 sa_payload_t
*sa_request
= NULL
;
482 ke_payload_t
*ke_request
= NULL
;
483 nonce_payload_t
*nonce_request
= NULL
;
484 ike_sa_id_t
*ike_sa_id
;
487 /* check message type */
488 if (request
->get_exchange_type(request
) != IKE_SA_INIT
)
490 this->logger
->log(this->logger
, ERROR
,
491 "IKE_SA_INIT request of invalid type, deleting IKE_SA");
495 /* check if we already have built a response (retransmission) */
498 *result
= this->message
;
502 me
= request
->get_destination(request
);
503 other
= request
->get_source(request
);
505 /* set up response */
506 response
= message_create();
507 response
->set_source(response
, me
->clone(me
));
508 response
->set_destination(response
, other
->clone(other
));
509 response
->set_exchange_type(response
, IKE_SA_INIT
);
510 response
->set_request(response
, FALSE
);
511 response
->set_message_id(response
, this->message_id
);
512 response
->set_ike_sa_id(response
, this->ike_sa
->get_id(this->ike_sa
));
513 this->message
= response
;
516 /* this is the first message to process, find a connection for IKE_SA */
517 this->connection
= charon
->connections
->get_connection_by_hosts(
518 charon
->connections
, me
, other
);
519 if (this->connection
== NULL
)
521 notify_payload_t
*notify
= notify_payload_create();
522 notify
->set_notify_type(notify
, NO_PROPOSAL_CHOSEN
);
523 response
->add_payload(response
, (payload_t
*)notify
);
525 this->logger
->log(this->logger
, AUDIT
,
526 "no connection for hosts %s...%s found, deleting IKE_SA",
527 me
->get_address(me
), other
->get_address(other
));
530 this->ike_sa
->set_connection(this->ike_sa
, this->connection
);
532 /* Precompute NAT-D hashes for incoming NAT notify comparison */
533 ike_sa_id
= request
->get_ike_sa_id(request
);
534 this->natd_dst_hash
= generate_natd_hash(this, ike_sa_id
, me
);
535 this->natd_src_hash
= generate_natd_hash(this, ike_sa_id
, other
);
537 /* Iterate over all payloads. */
538 payloads
= request
->get_payload_iterator(request
);
539 while (payloads
->has_next(payloads
))
542 payloads
->current(payloads
, (void**)&payload
);
543 switch (payload
->get_type(payload
))
545 case SECURITY_ASSOCIATION
:
546 sa_request
= (sa_payload_t
*)payload
;
549 ke_request
= (ke_payload_t
*)payload
;
552 nonce_request
= (nonce_payload_t
*)payload
;
556 status
= process_notifys(this, (notify_payload_t
*)payload
);
557 if (status
== FAILED
)
559 payloads
->destroy(payloads
);
560 /* we return SUCCESS, returned FAILED means do next transaction */
563 if (status
== DESTROY_ME
)
565 payloads
->destroy(payloads
);
572 this->logger
->log(this->logger
, ERROR
|LEVEL1
,
573 "ignoring %s payload (%d)",
574 mapping_find(payload_type_m
, payload
->get_type(payload
)),
575 payload
->get_type(payload
));
580 payloads
->destroy(payloads
);
582 /* check if we have all payloads */
583 if (!(sa_request
&& ke_request
&& nonce_request
))
585 notify_payload_t
*notify
= notify_payload_create();
586 notify
->set_notify_type(notify
, INVALID_SYNTAX
);
587 response
->add_payload(response
, (payload_t
*)notify
);
588 this->logger
->log(this->logger
, AUDIT
,
589 "request message incomplete, deleting IKE_SA");
593 { /* process SA payload:
594 * -------------------
595 * - extract proposals
596 * - select our most preferred proposal found in extracted
597 * - if no matches, return NO_PROPOSAL_CHOSEN
598 * - add sa payload with selected proposal
600 sa_payload_t
* sa_response
;
601 linked_list_t
*proposal_list
;
602 proposal_t
*proposal
;
604 proposal_list
= sa_request
->get_proposals(sa_request
);
605 this->proposal
= this->connection
->select_proposal(this->connection
, proposal_list
);
606 while(proposal_list
->remove_last(proposal_list
, (void**)&proposal
) == SUCCESS
)
608 proposal
->destroy(proposal
);
610 proposal_list
->destroy(proposal_list
);
611 if (this->proposal
== NULL
)
613 notify_payload_t
*notify
= notify_payload_create();
614 notify
->set_notify_type(notify
, NO_PROPOSAL_CHOSEN
);
615 response
->add_payload(response
, (payload_t
*)notify
);
616 this->logger
->log(this->logger
, AUDIT
,
617 "request did not contain any acceptable proposals, deleting IKE_SA");
620 sa_response
= sa_payload_create_from_proposal(this->proposal
);
621 response
->add_payload(response
, (payload_t
*)sa_response
);
624 { /* process KE payload:
625 * --------------------
626 * - check if used group match the selected proposal
627 * - if not, stop with INVALID_KE_PAYLOAD
628 * - apply others public value to complete diffie hellman exchange
629 * - add our public value to response
631 diffie_hellman_group_t used_group
;
632 ke_payload_t
*ke_response
;
634 used_group
= ke_request
->get_dh_group_number(ke_request
);
636 if (!this->connection
->check_dh_group(this->connection
, used_group
) ||
637 (this->diffie_hellman
= diffie_hellman_create(used_group
)) == NULL
)
639 u_int16_t notify_group
;
640 chunk_t notify_chunk
;
641 notify_payload_t
*notify
;
642 iterator_t
*iterator
;
645 notify_group
= this->connection
->get_dh_group(this->connection
);
646 this->logger
->log(this->logger
, AUDIT
,
647 "request used inacceptable DH group %s, sending INVALID_KE_PAYLOAD with %s, deleting IKE_SA",
648 mapping_find(diffie_hellman_group_m
, used_group
),
649 mapping_find(diffie_hellman_group_m
, notify_group
));
651 /* remove already added payloads */
652 iterator
= response
->get_payload_iterator(response
);
653 while (iterator
->has_next(iterator
))
655 iterator
->current(iterator
, (void**)&payload
);
656 iterator
->remove(iterator
);
657 payload
->destroy(payload
);
659 iterator
->destroy(iterator
);
661 notify_group
= htons(notify_group
);
662 notify_chunk
.ptr
= (u_int8_t
*)¬ify_group
;
663 notify_chunk
.len
= sizeof(notify_group
);
664 notify
= notify_payload_create();
665 notify
->set_notify_type(notify
, INVALID_KE_PAYLOAD
);
666 notify
->set_notification_data(notify
, notify_chunk
);
667 response
->add_payload(response
, (payload_t
*)notify
);
670 this->diffie_hellman
->set_other_public_value(this->diffie_hellman
,
671 ke_request
->get_key_exchange_data(ke_request
));
674 ke_response
= ke_payload_create_from_diffie_hellman(this->diffie_hellman
);
675 response
->add_payload(response
, (payload_t
*)ke_response
);
678 { /* process nonce payload:
679 * ----------------------
680 * - get nonce from payload
681 * - generate own nonce and add to reply
683 nonce_payload_t
*nonce_response
;
685 this->nonce_i
= nonce_request
->get_nonce(nonce_request
);
687 /* build response nonce */
688 if (this->randomizer
->allocate_pseudo_random_bytes(this->randomizer
,
689 NONCE_SIZE
, &this->nonce_r
) != SUCCESS
)
691 notify_payload_t
*notify
= notify_payload_create();
692 notify
->set_notify_type(notify
, NO_PROPOSAL_CHOSEN
);
693 response
->add_payload(response
, (payload_t
*)notify
);
694 this->logger
->log(this->logger
, AUDIT
,
695 "could not get random bytes for nonce, deleting IKE_SA");
698 nonce_response
= nonce_payload_create();
699 nonce_response
->set_nonce(nonce_response
, this->nonce_r
);
700 response
->add_payload(response
, (payload_t
*)nonce_response
);
703 { /* processs NATT stuff:
704 * --------------------
705 * - check if we or other is behind NAT
706 * - enable NATT if so
707 * - build NAT detection notifys for reply
709 notify_payload_t
*notify
;
711 if ((!this->natd_src_seen
&& this->natd_dst_seen
) ||
712 (this->natd_src_seen
&& !this->natd_dst_seen
))
714 notify
= notify_payload_create();
715 notify
->set_notify_type(notify
, INVALID_SYNTAX
);
716 response
->add_payload(response
, (payload_t
*)notify
);
717 this->logger
->log(this->logger
, AUDIT
,
718 "request contained wrong number of NAT-D payloads, deleting IKE_SA");
721 if (this->natd_dst_seen
&& !this->natd_dst_matched
)
723 this->ike_sa
->enable_natt(this->ike_sa
, TRUE
);
725 if (this->natd_src_seen
&& !this->natd_src_matched
)
727 this->ike_sa
->enable_natt(this->ike_sa
, FALSE
);
729 /* build response NAT DETECTION notifys, if remote supports it */
730 if (this->natd_src_seen
|| this->natd_dst_seen
)
732 /* N(NAT_DETECTION_SOURCE_IP) */
733 notify
= build_natd_payload(this, NAT_DETECTION_SOURCE_IP
, me
);
734 response
->add_payload(response
, (payload_t
*)notify
);
736 /* N(NAT_DETECTION_DESTINATION_IP) */
737 notify
= build_natd_payload(this, NAT_DETECTION_DESTINATION_IP
, other
);
738 response
->add_payload(response
, (payload_t
*)notify
);
742 /* derive all the keys used in the IKE_SA */
743 if (this->ike_sa
->build_transforms(this->ike_sa
, this->proposal
,
744 this->diffie_hellman
,
745 this->nonce_i
, this->nonce_r
,
748 notify_payload_t
*notify
= notify_payload_create();
749 notify
->set_notify_type(notify
, NO_PROPOSAL_CHOSEN
);
750 response
->add_payload(response
, (payload_t
*)notify
);
751 this->logger
->log(this->logger
, AUDIT
,
752 "transform objects could not be created from selected proposal, deleting IKE_SA");
756 { /* create ike_auth transaction, which will store informations for us */
757 packet_t
*response_packet
;
758 chunk_t request_chunk
, response_chunk
;
759 ike_auth_t
*ike_auth
;
761 /* we normally do not generate the message. But we need the generated message
762 * for authentication in the next state, so we do it here. This is not problematic,
763 * as we don't use a crypter/signer in ike_sa_init... */
764 if (response
->generate(response
, NULL
, NULL
, &response_packet
) != SUCCESS
)
766 this->logger
->log(this->logger
, AUDIT
,
767 "error in response generation, deleting IKE_SA");
770 response_packet
->destroy(response_packet
);
771 request_chunk
= request
->get_packet_data(request
);
772 response_chunk
= response
->get_packet_data(response
);
774 /* create next transaction, for which we except a message */
775 ike_auth
= ike_auth_create(this->ike_sa
, 1);
776 ike_auth
->set_nonces(ike_auth
,
777 chunk_clone(this->nonce_i
),
778 chunk_clone(this->nonce_r
));
779 ike_auth
->set_init_messages(ike_auth
, request_chunk
, response_chunk
);
780 *next
= (transaction_t
*)ike_auth
;
783 /* everything went fine. Now we set a timeout to destroy half initiated IKE_SAs */
784 timeout
= charon
->configuration
->get_half_open_ike_sa_timeout(charon
->configuration
);
787 job_t
*job
= (job_t
*)delete_half_open_ike_sa_job_create(this->ike_sa
->get_id(this->ike_sa
));
788 charon
->event_queue
->add_relative(charon
->event_queue
, job
, timeout
);
791 this->ike_sa
->set_state(this->ike_sa
, SA_CONNECTING
);
797 * Implementation of transaction_t.conclude
799 static status_t
conclude(private_ike_sa_init_t
*this, message_t
*response
,
800 transaction_t
**next
)
802 u_int64_t responder_spi
;
803 ike_sa_id_t
*ike_sa_id
;
804 iterator_t
*payloads
;
806 sa_payload_t
*sa_payload
= NULL
;
807 ke_payload_t
*ke_payload
= NULL
;
808 nonce_payload_t
*nonce_payload
= NULL
;
812 /* check message type */
813 if (response
->get_exchange_type(response
) != IKE_SA_INIT
)
815 this->logger
->log(this->logger
, ERROR
,
816 "IKE_SA_INIT response of invalid type, deleting IKE_SA");
820 /* allow setting of next transaction in other functions */
823 this->connection
= this->ike_sa
->get_connection(this->ike_sa
);
824 me
= this->connection
->get_my_host(this->connection
);
825 other
= this->connection
->get_other_host(this->connection
);
827 /* check if SPI has been updated, but apply only if all goes ok later */
828 responder_spi
= response
->get_responder_spi(response
);
829 if (responder_spi
== 0)
831 this->logger
->log(this->logger
, ERROR
,
832 "response contained a SPI of zero, deleting IKE_SA");
836 /* Precompute NAT-D hashes for later comparison */
837 ike_sa_id
= response
->get_ike_sa_id(response
);
838 this->natd_src_hash
= generate_natd_hash(this, ike_sa_id
, other
);
839 this->natd_dst_hash
= generate_natd_hash(this, ike_sa_id
, me
);
841 /* Iterate over all payloads to collect them */
842 payloads
= response
->get_payload_iterator(response
);
843 while (payloads
->has_next(payloads
))
846 payloads
->current(payloads
, (void**)&payload
);
848 switch (payload
->get_type(payload
))
850 case SECURITY_ASSOCIATION
:
852 sa_payload
= (sa_payload_t
*)payload
;
857 ke_payload
= (ke_payload_t
*)payload
;
862 nonce_payload
= (nonce_payload_t
*)payload
;
867 status
= process_notifys(this, (notify_payload_t
*)payload
);
868 if (status
== FAILED
)
870 payloads
->destroy(payloads
);
871 /* we return SUCCESS, returned FAILED means do next transaction */
874 if (status
== DESTROY_ME
)
876 payloads
->destroy(payloads
);
883 this->logger
->log(this->logger
, ERROR
, "ignoring payload %s (%d)",
884 mapping_find(payload_type_m
, payload
->get_type(payload
)),
885 payload
->get_type(payload
));
890 payloads
->destroy(payloads
);
892 if (!(nonce_payload
&& sa_payload
&& ke_payload
))
894 this->logger
->log(this->logger
, AUDIT
, "response message incomplete, deleting IKE_SA");
898 { /* process SA payload:
899 * -------------------
900 * - get proposals from it
901 * - check if peer selected a proposal
902 * - verify it's selection againts our set
904 proposal_t
*proposal
;
905 linked_list_t
*proposal_list
;
907 /* get the list of selected proposals, the peer has to select only one proposal */
908 proposal_list
= sa_payload
->get_proposals (sa_payload
);
909 if (proposal_list
->get_count(proposal_list
) != 1)
911 this->logger
->log(this->logger
, AUDIT
,
912 "response did not contain a single proposal, deleting IKE_SA");
913 while (proposal_list
->remove_last(proposal_list
, (void**)&proposal
) == SUCCESS
)
915 proposal
->destroy(proposal
);
917 proposal_list
->destroy(proposal_list
);
921 /* we have to re-check if the others selection is valid */
922 this->proposal
= this->connection
->select_proposal(this->connection
, proposal_list
);
923 while (proposal_list
->remove_last(proposal_list
, (void**)&proposal
) == SUCCESS
)
925 proposal
->destroy(proposal
);
927 proposal_list
->destroy(proposal_list
);
929 if (this->proposal
== NULL
)
931 this->logger
->log(this->logger
, AUDIT
,
932 "peer selected a proposal we did not offer, deleting IKE_SA");
937 { /* process KE payload:
938 * -------------------
939 * - extract others public value
940 * - complete diffie-hellman exchange
942 this->diffie_hellman
->set_other_public_value(this->diffie_hellman
,
943 ke_payload
->get_key_exchange_data(ke_payload
));
946 { /* process NONCE payload:
947 * ----------------------
948 * - extract nonce used for key derivation */
949 this->nonce_r
= nonce_payload
->get_nonce(nonce_payload
);
952 { /* process NATT stuff:
953 * -------------------
954 * - check if we or other is NATted
955 * - switch to port 4500 if so
957 if ((!this->natd_dst_seen
&& this->natd_src_seen
) ||
958 (this->natd_dst_seen
&& !this->natd_src_seen
))
960 this->logger
->log(this->logger
, AUDIT
,
961 "request contained wrong number of NAT-D payloads, deleting IKE_SA");
964 if (this->natd_src_seen
&& !this->natd_src_matched
)
966 this->ike_sa
->enable_natt(this->ike_sa
, FALSE
);
968 if (this->natd_dst_seen
&& !this->natd_dst_matched
)
970 this->ike_sa
->enable_natt(this->ike_sa
, TRUE
);
972 if (this->ike_sa
->is_natt_enabled(this->ike_sa
))
974 me
->set_port(me
, IKEV2_NATT_PORT
);
975 other
->set_port(other
, IKEV2_NATT_PORT
);
976 this->logger
->log(this->logger
, CONTROL
|LEVEL1
, "switching to port %d", IKEV2_NATT_PORT
);
978 policy
= this->ike_sa
->get_policy(this->ike_sa
);
979 policy
->update_my_ts(policy
, me
);
980 policy
->update_other_ts(policy
, other
);
983 /* because we are original initiator we have to update the responder SPI to the new one */
984 ike_sa_id
= this->ike_sa
->get_id(this->ike_sa
);
985 ike_sa_id
->set_responder_spi(ike_sa_id
, responder_spi
);
987 /* derive all the keys used in the IKE_SA */
988 if (this->ike_sa
->build_transforms(this->ike_sa
, this->proposal
,
989 this->diffie_hellman
,
990 this->nonce_i
, this->nonce_r
,
993 this->logger
->log(this->logger
, AUDIT
,
994 "transform objects could not be created from selected proposal, deleting IKE_SA");
998 { /* create ike_auth transaction, which will continue IKE_SA setup */
999 chunk_t request_chunk
, response_chunk
;
1000 ike_auth_t
*ike_auth
;
1002 request_chunk
= this->message
->get_packet_data(this->message
);
1003 response_chunk
= response
->get_packet_data(response
);
1005 /* create next transaction, for which we except a message */
1006 ike_auth
= ike_auth_create(this->ike_sa
, 1);
1007 ike_auth
->set_nonces(ike_auth
,
1008 chunk_clone(this->nonce_i
),
1009 chunk_clone(this->nonce_r
));
1010 ike_auth
->set_init_messages(ike_auth
, request_chunk
, response_chunk
);
1011 *next
= (transaction_t
*)ike_auth
;
1017 static void destroy(private_ike_sa_init_t
*this)
1021 this->message
->destroy(this->message
);
1023 if (this->diffie_hellman
)
1025 this->diffie_hellman
->destroy(this->diffie_hellman
);
1029 this->proposal
->destroy(this->proposal
);
1031 chunk_free(&this->nonce_i
);
1032 chunk_free(&this->nonce_r
);
1033 this->randomizer
->destroy(this->randomizer
);
1034 this->nat_hasher
->destroy(this->nat_hasher
);
1035 chunk_free(&this->natd_src_hash
);
1036 chunk_free(&this->natd_dst_hash
);
1041 * Described in header.
1043 ike_sa_init_t
*ike_sa_init_create(ike_sa_t
*ike_sa
, u_int32_t message_id
)
1045 private_ike_sa_init_t
*this = malloc_thing(private_ike_sa_init_t
);
1047 /* transaction interface functions */
1048 this->public.transaction
.get_request
= (status_t(*)(transaction_t
*,message_t
**))get_request
;
1049 this->public.transaction
.get_response
= (status_t(*)(transaction_t
*,message_t
*,message_t
**,transaction_t
**))get_response
;
1050 this->public.transaction
.conclude
= (status_t(*)(transaction_t
*,message_t
*,transaction_t
**))conclude
;
1051 this->public.transaction
.get_message_id
= (u_int32_t(*)(transaction_t
*))get_message_id
;
1052 this->public.transaction
.requested
= (u_int32_t(*)(transaction_t
*))requested
;
1053 this->public.transaction
.destroy
= (void(*)(transaction_t
*))destroy
;
1055 /* public functions */
1056 this->public.use_dh_group
= (bool(*)(ike_sa_init_t
*,diffie_hellman_group_t
))use_dh_group
;
1059 this->ike_sa
= ike_sa
;
1060 this->message_id
= message_id
;
1061 this->message
= NULL
;
1062 this->requested
= 0;
1063 this->diffie_hellman
= NULL
;
1064 this->nonce_i
= CHUNK_INITIALIZER
;
1065 this->nonce_r
= CHUNK_INITIALIZER
;
1066 this->connection
= NULL
;
1067 this->proposal
= NULL
;
1068 this->randomizer
= randomizer_create();
1069 this->nat_hasher
= hasher_create(HASH_SHA1
);
1070 this->natd_src_hash
= CHUNK_INITIALIZER
;
1071 this->natd_dst_hash
= CHUNK_INITIALIZER
;
1072 this->natd_src_seen
= FALSE
;
1073 this->natd_dst_seen
= FALSE
;
1074 this->natd_src_matched
= FALSE
;
1075 this->natd_dst_matched
= FALSE
;
1076 this->logger
= logger_manager
->get_logger(logger_manager
, IKE_SA
);
1078 return &this->public;