7a7866970e14be1601e3f7ed56783569d0cf0a58
[strongswan.git] / src / charon / sa / transactions / ike_sa_init.c
1 /**
2 * @file ike_sa_init.c
3 *
4 * @brief Implementation of ike_sa_init_t transaction.
5 *
6 */
7
8 /*
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
13 *
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>.
18 *
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
22 * for more details.
23 */
24
25 #include "ike_sa_init.h"
26
27 #include <string.h>
28
29 #include <daemon.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>
38
39
40 typedef struct private_ike_sa_init_t private_ike_sa_init_t;
41
42 /**
43 * Private members of a ike_sa_init_t object..
44 */
45 struct private_ike_sa_init_t {
46
47 /**
48 * Public methods and transaction_t interface.
49 */
50 ike_sa_init_t public;
51
52 /**
53 * Assigned IKE_SA.
54 */
55 ike_sa_t *ike_sa;
56
57 /**
58 * Message sent by our peer, if already generated
59 */
60 message_t *message;
61
62 /**
63 * Message ID this transaction uses
64 */
65 u_int32_t message_id;
66
67 /**
68 * Times we did send the request
69 */
70 u_int32_t requested;
71
72 /**
73 * Next transaction followed to this one. May be IKE_AUTH,
74 * or a IKE_SA_INIT retry
75 */
76 transaction_t **next;
77
78 /**
79 * Diffie hellman object used to generate public DH value.
80 */
81 diffie_hellman_t *diffie_hellman;
82
83 /**
84 * initiator chosen nonce
85 */
86 chunk_t nonce_i;
87
88 /**
89 * responder chosen nonce
90 */
91 chunk_t nonce_r;
92
93 /**
94 * connection definition used for initiation
95 */
96 connection_t *connection;
97
98 /**
99 * policy definition forwarded to ike_auth transaction
100 */
101 policy_t *policy;
102
103 /**
104 * Negotiated proposal used for IKE_SA
105 */
106 proposal_t *proposal;
107
108 /**
109 * Reqid to pass to IKE_AUTH, used for created CHILD_SA
110 */
111 u_int32_t reqid;
112
113 /**
114 * Randomizer to generate nonces
115 */
116 randomizer_t *randomizer;
117
118 /**
119 * Hasher used to build NAT detection hashes
120 */
121 hasher_t *nat_hasher;
122
123 /**
124 * Precomputed NAT hash for source address
125 */
126 chunk_t natd_src_hash;
127
128 /**
129 * Precomputed NAT hash for destination address
130 */
131 chunk_t natd_dst_hash;
132
133 /**
134 * Did we process any NAT detection notifys for a source address?
135 */
136 bool natd_src_seen;
137
138 /**
139 * Did we process any NAT detection notifys for a destination address?
140 */
141 bool natd_dst_seen;
142
143 /**
144 * Have we found a matching source address NAT hash?
145 */
146 bool natd_src_matched;
147
148 /**
149 * Have we found a matching destination address NAT hash?
150 */
151 bool natd_dst_matched;
152
153 /**
154 * Assigned logger.
155 */
156 logger_t *logger;
157 };
158
159 /**
160 * Implementation of ike_sa_init_t.use_dh_group.
161 */
162 static bool use_dh_group(private_ike_sa_init_t *this, diffie_hellman_group_t dh_group)
163 {
164 if (this->connection->check_dh_group(this->connection, dh_group))
165 {
166 this->diffie_hellman = diffie_hellman_create(dh_group);
167 if (this->diffie_hellman)
168 {
169 return TRUE;
170 }
171 }
172 return FALSE;
173 }
174
175 /**
176 * Implementation of ike_sa_init_t.set_config.
177 */
178 static void set_config(private_ike_sa_init_t *this,
179 connection_t *connection, policy_t *policy)
180 {
181 this->connection = connection;
182 this->policy = policy;
183 }
184
185 /**
186 * Implementation of ike_sa_init_t.set_reqid.
187 */
188 static void set_reqid(private_ike_sa_init_t *this, u_int32_t reqid)
189 {
190 this->reqid = reqid;
191 }
192
193 /**
194 * Implementation of transaction_t.get_message_id.
195 */
196 static u_int32_t get_message_id(private_ike_sa_init_t *this)
197 {
198 return this->message_id;
199 }
200
201 /**
202 * Implementation of transaction_t.requested.
203 */
204 static u_int32_t requested(private_ike_sa_init_t *this)
205 {
206 return this->requested++;
207 }
208
209 /**
210 * Build NAT detection hash for a host
211 */
212 static chunk_t generate_natd_hash(private_ike_sa_init_t *this,
213 ike_sa_id_t * ike_sa_id, host_t *host)
214 {
215 chunk_t natd_chunk, spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk;
216 chunk_t natd_hash;
217 u_int64_t spi_i, spi_r;
218 u_int16_t port;
219
220 /* prepare all requred chunks */
221 spi_i = ike_sa_id->get_initiator_spi(ike_sa_id);
222 spi_r = ike_sa_id->get_responder_spi(ike_sa_id);
223 spi_i_chunk.ptr = (void*)&spi_i;
224 spi_i_chunk.len = sizeof(spi_i);
225 spi_r_chunk.ptr = (void*)&spi_r;
226 spi_r_chunk.len = sizeof(spi_r);
227 port = htons(host->get_port(host));
228 port_chunk.ptr = (void*)&port;
229 port_chunk.len = sizeof(port);
230 addr_chunk = host->get_address(host);
231
232 /* natd_hash = SHA1( spi_i | spi_r | address | port ) */
233 natd_chunk = chunk_cat("cccc", spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk);
234 this->nat_hasher->allocate_hash(this->nat_hasher, natd_chunk, &natd_hash);
235 this->logger->log_chunk(this->logger, RAW, "natd_chunk", natd_chunk);
236 this->logger->log_chunk(this->logger, RAW, "natd_hash", natd_hash);
237
238 chunk_free(&natd_chunk);
239 return natd_hash;
240 }
241
242 /**
243 * Build a NAT detection notify payload.
244 */
245 static notify_payload_t *build_natd_payload(private_ike_sa_init_t *this,
246 notify_type_t type, host_t *host)
247 {
248 chunk_t hash;
249 notify_payload_t *notify;
250 ike_sa_id_t *ike_sa_id;
251
252 ike_sa_id = this->ike_sa->get_id(this->ike_sa);
253 notify = notify_payload_create();
254 notify->set_notify_type(notify, type);
255 hash = generate_natd_hash(this, ike_sa_id, host);
256 notify->set_notification_data(notify, hash);
257 chunk_free(&hash);
258
259 return notify;
260 }
261
262 /**
263 * destroy a list of proposals
264 */
265 static void destroy_proposal_list(linked_list_t *list)
266 {
267 proposal_t *proposal;
268
269 while (list->remove_last(list, (void**)&proposal) == SUCCESS)
270 {
271 proposal->destroy(proposal);
272 }
273 list->destroy(list);
274 }
275
276 /**
277 * Implementation of transaction_t.get_request.
278 */
279 static status_t get_request(private_ike_sa_init_t *this, message_t **result)
280 {
281 message_t *request;
282 host_t *me, *other;
283 identification_t *my_id, *other_id;
284
285 /* check if we already have built a message (retransmission) */
286 if (this->message)
287 {
288 *result = this->message;
289 return SUCCESS;
290 }
291
292 me = this->connection->get_my_host(this->connection);
293 other = this->connection->get_other_host(this->connection);
294
295 /* we already set up the IDs. Mine is already fully qualified, other
296 * will be updated in the ike_auth transaction */
297 my_id = this->policy->get_my_id(this->policy);
298 other_id = this->policy->get_other_id(this->policy);
299 this->ike_sa->set_my_id(this->ike_sa, my_id->clone(my_id));
300 this->ike_sa->set_other_id(this->ike_sa, other_id->clone(other_id));
301
302 /* build the request */
303 request = message_create();
304 request->set_source(request, me->clone(me));
305 request->set_destination(request, other->clone(other));
306 request->set_exchange_type(request, IKE_SA_INIT);
307 request->set_request(request, TRUE);
308 request->set_message_id(request, this->message_id);
309 request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
310 /* apply for caller */
311 *result = request;
312 /* store for retransmission */
313 this->message = request;
314
315 /* if the DH group is set via use_dh_group(), we already have a DH object */
316 if (!this->diffie_hellman)
317 {
318 diffie_hellman_group_t dh_group;
319
320 dh_group = this->connection->get_dh_group(this->connection);
321 this->diffie_hellman = diffie_hellman_create(dh_group);
322 if (this->diffie_hellman == NULL)
323 {
324 this->logger->log(this->logger, AUDIT,
325 "DH group %s (%d) not supported, aborting",
326 mapping_find(diffie_hellman_group_m, dh_group), dh_group);
327 return DESTROY_ME;
328 }
329 }
330
331 { /* build the SA payload from proposals */
332 sa_payload_t *sa_payload;
333 linked_list_t *proposal_list;
334
335 proposal_list = this->connection->get_proposals(this->connection);
336 sa_payload = sa_payload_create_from_proposal_list(proposal_list);
337 destroy_proposal_list(proposal_list);
338
339 request->add_payload(request, (payload_t*)sa_payload);
340 }
341
342 { /* build the KE payload from the DH object */
343 ke_payload_t *ke_payload;
344
345 ke_payload = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
346
347 request->add_payload(request, (payload_t*)ke_payload);
348 }
349
350 { /* build the NONCE payload for us (initiator) */
351 nonce_payload_t *nonce_payload;
352
353 if (this->randomizer->allocate_pseudo_random_bytes(this->randomizer,
354 NONCE_SIZE, &this->nonce_i) != SUCCESS)
355 {
356 return DESTROY_ME;
357 }
358 nonce_payload = nonce_payload_create();
359 nonce_payload->set_nonce(nonce_payload, this->nonce_i);
360
361 request->add_payload(request, (payload_t*)nonce_payload);
362 }
363
364 { /* build NAT_DETECTION notifys */
365 notify_payload_t *notify;
366 linked_list_t *list;
367 host_t *host;
368
369 /* N(NAT_DETECTION_SOURCE_IP)+ */
370 list = charon->socket->create_local_address_list(charon->socket);
371 while (list->remove_first(list, (void**)&host) == SUCCESS)
372 {
373 /* TODO: should we only include NAT payloads for addresses
374 * of used address family? */
375 notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
376 host->destroy(host);
377 request->add_payload(request, (payload_t*)notify);
378 }
379 list->destroy(list);
380
381 /* N(NAT_DETECTION_DESTINATION_IP) */
382 notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, other);
383 request->add_payload(request, (payload_t*)notify);
384 }
385
386 this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
387 return SUCCESS;
388 }
389
390 /**
391 * Handle all kind of notifys
392 */
393 static status_t process_notifys(private_ike_sa_init_t *this, notify_payload_t *notify_payload)
394 {
395 chunk_t notification_data;
396 notify_type_t notify_type = notify_payload->get_notify_type(notify_payload);
397
398 this->logger->log(this->logger, CONTROL|LEVEL1, "process notify type %s",
399 mapping_find(notify_type_m, notify_type));
400
401 switch (notify_type)
402 {
403 case NO_PROPOSAL_CHOSEN:
404 {
405 this->logger->log(this->logger, AUDIT,
406 "received a NO_PROPOSAL_CHOSEN notify, deleting IKE_SA");
407 return DESTROY_ME;
408 }
409 case INVALID_MAJOR_VERSION:
410 {
411 this->logger->log(this->logger, AUDIT,
412 "received a INVALID_MAJOR_VERSION notify, deleting IKE_SA");
413 return DESTROY_ME;
414 }
415 case INVALID_KE_PAYLOAD:
416 {
417 chunk_t notify_data;
418 diffie_hellman_group_t dh_group, old_dh_group;
419 ike_sa_init_t *retry;
420
421 old_dh_group = this->connection->get_dh_group(this->connection);
422 notify_data = notify_payload->get_notification_data(notify_payload);
423 dh_group = ntohs(*((u_int16_t*)notify_data.ptr));
424
425 this->logger->log(this->logger, AUDIT,
426 "peer didn't accept DH group %s, it requested %s",
427 mapping_find(diffie_hellman_group_m, old_dh_group),
428 mapping_find(diffie_hellman_group_m, dh_group));
429 if (!this->connection->check_dh_group(this->connection, dh_group))
430 {
431 this->logger->log(this->logger, AUDIT,
432 "requested DH group not acceptable, aborting");
433 return DESTROY_ME;
434 }
435 retry = ike_sa_init_create(this->ike_sa);
436 retry->set_config(retry, this->connection, this->policy);
437 this->connection = NULL;
438 this->policy = NULL;
439 retry->use_dh_group(retry, dh_group);
440 *this->next = (transaction_t*)retry;
441 return FAILED;
442 }
443 case NAT_DETECTION_DESTINATION_IP:
444 {
445 this->natd_dst_seen = TRUE;
446 if (this->natd_dst_matched)
447 {
448 return SUCCESS;
449 }
450 notification_data = notify_payload->get_notification_data(notify_payload);
451 if (chunk_equals(notification_data, this->natd_dst_hash))
452 {
453 this->natd_dst_matched = TRUE;
454 this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D dst hash match");
455 }
456 else
457 {
458 this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D dst hash mismatch");
459 }
460 return SUCCESS;
461 }
462 case NAT_DETECTION_SOURCE_IP:
463 {
464 this->natd_src_seen = TRUE;;
465 if (this->natd_src_matched)
466 {
467 return SUCCESS;
468 }
469 notification_data = notify_payload->get_notification_data(notify_payload);
470 if (chunk_equals(notification_data, this->natd_src_hash))
471 {
472 this->natd_src_matched = TRUE;
473 this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D src hash match");
474 }
475 else
476 {
477 this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D src hash mismatch");
478 }
479 return SUCCESS;
480 }
481 default:
482 {
483 if (notify_type < 16383)
484 {
485 this->logger->log(this->logger, AUDIT,
486 "received %s notify error (%d), deleting IKE_SA",
487 mapping_find(notify_type_m, notify_type),
488 notify_type);
489 return DESTROY_ME;
490 }
491 else
492 {
493 this->logger->log(this->logger, CONTROL,
494 "received %s notify (%d), ignored",
495 mapping_find(notify_type_m, notify_type),
496 notify_type);
497 return SUCCESS;
498 }
499 }
500 }
501 }
502
503 /**
504 * Implementation of transaction_t.get_response.
505 */
506 static status_t get_response(private_ike_sa_init_t *this,
507 message_t *request, message_t **result,
508 transaction_t **next)
509 {
510 host_t *me, *other;
511 message_t *response;
512 status_t status;
513 iterator_t *payloads;
514 sa_payload_t *sa_request = NULL;
515 ke_payload_t *ke_request = NULL;
516 nonce_payload_t *nonce_request = NULL;
517 ike_sa_id_t *ike_sa_id;
518 u_int32_t timeout;
519
520 /* check if we already have built a response (retransmission) */
521 if (this->message)
522 {
523 *result = this->message;
524 return SUCCESS;
525 }
526
527 me = request->get_destination(request);
528 other = request->get_source(request);
529 this->message_id = request->get_message_id(request);
530
531 /* set up response */
532 response = message_create();
533 response->set_source(response, me->clone(me));
534 response->set_destination(response, other->clone(other));
535 response->set_exchange_type(response, IKE_SA_INIT);
536 response->set_request(response, FALSE);
537 response->set_message_id(response, this->message_id);
538 response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
539 this->message = response;
540 *result = response;
541
542 /* check message type */
543 if (request->get_exchange_type(request) != IKE_SA_INIT)
544 {
545 this->logger->log(this->logger, ERROR,
546 "IKE_SA_INIT request of invalid type, deleting IKE_SA");
547 return DESTROY_ME;
548 }
549
550 /* this is the first message to process, find a connection for IKE_SA */
551 this->connection = charon->connections->get_connection_by_hosts(
552 charon->connections, me, other);
553 if (this->connection == NULL)
554 {
555 notify_payload_t *notify = notify_payload_create();
556 notify->set_notify_type(notify, NO_PROPOSAL_CHOSEN);
557 response->add_payload(response, (payload_t*)notify);
558
559 this->logger->log(this->logger, AUDIT,
560 "no connection for hosts %s...%s found, deleting IKE_SA",
561 me->get_string(me), other->get_string(other));
562 return DESTROY_ME;
563 }
564 this->ike_sa->set_name(this->ike_sa,
565 this->connection->get_name(this->connection));
566
567 /* Precompute NAT-D hashes for incoming NAT notify comparison */
568 ike_sa_id = request->get_ike_sa_id(request);
569 this->natd_dst_hash = generate_natd_hash(this, ike_sa_id, me);
570 this->natd_src_hash = generate_natd_hash(this, ike_sa_id, other);
571
572 /* Iterate over all payloads. */
573 payloads = request->get_payload_iterator(request);
574 while (payloads->has_next(payloads))
575 {
576 payload_t *payload;
577 payloads->current(payloads, (void**)&payload);
578 switch (payload->get_type(payload))
579 {
580 case SECURITY_ASSOCIATION:
581 sa_request = (sa_payload_t*)payload;
582 break;
583 case KEY_EXCHANGE:
584 ke_request = (ke_payload_t*)payload;
585 break;
586 case NONCE:
587 nonce_request = (nonce_payload_t*)payload;
588 break;
589 case NOTIFY:
590 {
591 status = process_notifys(this, (notify_payload_t*)payload);
592 if (status == FAILED)
593 {
594 payloads->destroy(payloads);
595 /* we return SUCCESS, returned FAILED means do next transaction */
596 return SUCCESS;
597 }
598 if (status == DESTROY_ME)
599 {
600 payloads->destroy(payloads);
601 return DESTROY_ME;
602 }
603 break;
604 }
605 default:
606 {
607 this->logger->log(this->logger, ERROR|LEVEL1,
608 "ignoring %s payload (%d)",
609 mapping_find(payload_type_m, payload->get_type(payload)),
610 payload->get_type(payload));
611 break;
612 }
613 }
614 }
615 payloads->destroy(payloads);
616
617 /* check if we have all payloads */
618 if (!(sa_request && ke_request && nonce_request))
619 {
620 notify_payload_t *notify = notify_payload_create();
621 notify->set_notify_type(notify, INVALID_SYNTAX);
622 response->add_payload(response, (payload_t*)notify);
623 this->logger->log(this->logger, AUDIT,
624 "request message incomplete, deleting IKE_SA");
625 return DESTROY_ME;
626 }
627
628 { /* process SA payload:
629 * -------------------
630 * - extract proposals
631 * - select our most preferred proposal found in extracted
632 * - if no matches, return NO_PROPOSAL_CHOSEN
633 * - add sa payload with selected proposal
634 */
635 sa_payload_t* sa_response;
636 linked_list_t *proposal_list;
637
638 proposal_list = sa_request->get_proposals(sa_request);
639 this->proposal = this->connection->select_proposal(this->connection, proposal_list);
640 destroy_proposal_list(proposal_list);
641 if (this->proposal == NULL)
642 {
643 notify_payload_t *notify = notify_payload_create();
644 notify->set_notify_type(notify, NO_PROPOSAL_CHOSEN);
645 response->add_payload(response, (payload_t*)notify);
646 this->logger->log(this->logger, AUDIT,
647 "request did not contain any acceptable proposals, deleting IKE_SA");
648 return DESTROY_ME;
649 }
650 sa_response = sa_payload_create_from_proposal(this->proposal);
651 response->add_payload(response, (payload_t *)sa_response);
652 }
653
654 { /* process KE payload:
655 * --------------------
656 * - check if used group match the selected proposal
657 * - if not, stop with INVALID_KE_PAYLOAD
658 * - apply others public value to complete diffie hellman exchange
659 * - add our public value to response
660 */
661 diffie_hellman_group_t used_group;
662 ke_payload_t *ke_response;
663
664 used_group = ke_request->get_dh_group_number(ke_request);
665
666 if (!this->connection->check_dh_group(this->connection, used_group) ||
667 (this->diffie_hellman = diffie_hellman_create(used_group)) == NULL)
668 {
669 u_int16_t notify_group;
670 chunk_t notify_chunk;
671 notify_payload_t *notify;
672 iterator_t *iterator;
673 payload_t *payload;
674
675 notify_group = this->connection->get_dh_group(this->connection);
676 this->logger->log(this->logger, AUDIT,
677 "request used inacceptable DH group %s, sending INVALID_KE_PAYLOAD with %s, deleting IKE_SA",
678 mapping_find(diffie_hellman_group_m, used_group),
679 mapping_find(diffie_hellman_group_m, notify_group));
680
681 /* remove already added payloads */
682 iterator = response->get_payload_iterator(response);
683 while (iterator->has_next(iterator))
684 {
685 iterator->current(iterator, (void**)&payload);
686 iterator->remove(iterator);
687 payload->destroy(payload);
688 }
689 iterator->destroy(iterator);
690
691 notify_group = htons(notify_group);
692 notify_chunk.ptr = (u_int8_t*)&notify_group;
693 notify_chunk.len = sizeof(notify_group);
694 notify = notify_payload_create();
695 notify->set_notify_type(notify, INVALID_KE_PAYLOAD);
696 notify->set_notification_data(notify, notify_chunk);
697 response->add_payload(response, (payload_t*)notify);
698 return DESTROY_ME;
699 }
700 this->diffie_hellman->set_other_public_value(this->diffie_hellman,
701 ke_request->get_key_exchange_data(ke_request));
702
703 /* build response */
704 ke_response = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
705 response->add_payload(response, (payload_t*)ke_response);
706 }
707
708 { /* process nonce payload:
709 * ----------------------
710 * - get nonce from payload
711 * - generate own nonce and add to reply
712 */
713 nonce_payload_t *nonce_response;
714
715 this->nonce_i = nonce_request->get_nonce(nonce_request);
716
717 /* build response nonce */
718 if (this->randomizer->allocate_pseudo_random_bytes(this->randomizer,
719 NONCE_SIZE, &this->nonce_r) != SUCCESS)
720 {
721 notify_payload_t *notify = notify_payload_create();
722 notify->set_notify_type(notify, NO_PROPOSAL_CHOSEN);
723 response->add_payload(response, (payload_t*)notify);
724 this->logger->log(this->logger, AUDIT,
725 "could not get random bytes for nonce, deleting IKE_SA");
726 return DESTROY_ME;
727 }
728 nonce_response = nonce_payload_create();
729 nonce_response->set_nonce(nonce_response, this->nonce_r);
730 response->add_payload(response, (payload_t *)nonce_response);
731 }
732
733 { /* processs NATT stuff:
734 * --------------------
735 * - check if we or other is behind NAT
736 * - enable NATT if so
737 * - build NAT detection notifys for reply
738 */
739 notify_payload_t *notify;
740
741 if ((!this->natd_src_seen && this->natd_dst_seen) ||
742 (this->natd_src_seen && !this->natd_dst_seen))
743 {
744 notify = notify_payload_create();
745 notify->set_notify_type(notify, INVALID_SYNTAX);
746 response->add_payload(response, (payload_t*)notify);
747 this->logger->log(this->logger, AUDIT,
748 "request contained wrong number of NAT-D payloads, deleting IKE_SA");
749 return DESTROY_ME;
750 }
751 if (this->natd_dst_seen && !this->natd_dst_matched)
752 {
753 this->ike_sa->enable_natt(this->ike_sa, TRUE);
754 }
755 if (this->natd_src_seen && !this->natd_src_matched)
756 {
757 this->ike_sa->enable_natt(this->ike_sa, FALSE);
758 }
759 /* build response NAT DETECTION notifys, if remote supports it */
760 if (this->natd_src_seen || this->natd_dst_seen)
761 {
762 /* N(NAT_DETECTION_SOURCE_IP) */
763 notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, me);
764 response->add_payload(response, (payload_t*)notify);
765
766 /* N(NAT_DETECTION_DESTINATION_IP) */
767 notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, other);
768 response->add_payload(response, (payload_t*)notify);
769 }
770 }
771
772 /* derive all the keys used in the IKE_SA */
773 if (this->ike_sa->derive_keys(this->ike_sa, this->proposal,
774 this->diffie_hellman,
775 this->nonce_i, this->nonce_r,
776 FALSE, NULL, NULL) != SUCCESS)
777 {
778 notify_payload_t *notify = notify_payload_create();
779 notify->set_notify_type(notify, NO_PROPOSAL_CHOSEN);
780 response->add_payload(response, (payload_t*)notify);
781 this->logger->log(this->logger, AUDIT,
782 "transform objects could not be created from selected proposal, deleting IKE_SA");
783 return DESTROY_ME;
784 }
785
786 this->ike_sa->set_lifetimes(this->ike_sa,
787 this->connection->get_soft_lifetime(this->connection),
788 this->connection->get_hard_lifetime(this->connection));
789
790 { /* create ike_auth transaction, which will store informations for us */
791 packet_t *response_packet;
792 chunk_t request_chunk, response_chunk;
793 ike_auth_t *ike_auth;
794
795 /* we normally do not generate the message. But we need the generated message
796 * for authentication in the next state, so we do it here. This is not problematic,
797 * as we don't use a crypter/signer in ike_sa_init... */
798 if (response->generate(response, NULL, NULL, &response_packet) != SUCCESS)
799 {
800 this->logger->log(this->logger, AUDIT,
801 "error in response generation, deleting IKE_SA");
802 return DESTROY_ME;
803 }
804 response_packet->destroy(response_packet);
805 request_chunk = request->get_packet_data(request);
806 response_chunk = response->get_packet_data(response);
807
808 /* create next transaction, for which we except a message */
809 ike_auth = ike_auth_create(this->ike_sa);
810 ike_auth->set_config(ike_auth, this->connection, this->policy);
811 ike_auth->set_reqid(ike_auth, this->reqid);
812 this->connection = NULL;
813 this->policy = NULL;
814 ike_auth->set_nonces(ike_auth,
815 chunk_clone(this->nonce_i),
816 chunk_clone(this->nonce_r));
817 ike_auth->set_init_messages(ike_auth, request_chunk, response_chunk);
818 *next = (transaction_t*)ike_auth;
819 }
820
821 /* everything went fine. Now we set a timeout to destroy half initiated IKE_SAs */
822 timeout = charon->configuration->get_half_open_ike_sa_timeout(charon->configuration);
823 if (timeout)
824 {
825 job_t *job = (job_t*)delete_ike_sa_job_create(
826 this->ike_sa->get_id(this->ike_sa), FALSE);
827 charon->event_queue->add_relative(charon->event_queue, job, timeout);
828 }
829 /* set new state */
830 this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
831
832 return SUCCESS;
833 }
834
835
836 /**
837 * Implementation of transaction_t.conclude
838 */
839 static status_t conclude(private_ike_sa_init_t *this, message_t *response,
840 transaction_t **next)
841 {
842 u_int64_t responder_spi;
843 ike_sa_id_t *ike_sa_id;
844 iterator_t *payloads;
845 host_t *me, *other;
846 sa_payload_t *sa_payload = NULL;
847 ke_payload_t *ke_payload = NULL;
848 nonce_payload_t *nonce_payload = NULL;
849 status_t status;
850
851 /* check message type */
852 if (response->get_exchange_type(response) != IKE_SA_INIT)
853 {
854 this->logger->log(this->logger, ERROR,
855 "IKE_SA_INIT response of invalid type, deleting IKE_SA");
856 return DESTROY_ME;
857 }
858
859 /* allow setting of next transaction in other functions */
860 this->next = next;
861
862 me = this->connection->get_my_host(this->connection);
863 other = this->connection->get_other_host(this->connection);
864
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)
868 {
869 this->logger->log(this->logger, ERROR,
870 "response contained a SPI of zero, deleting IKE_SA");
871 return DESTROY_ME;
872 }
873
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);
878
879 /* Iterate over all payloads to collect them */
880 payloads = response->get_payload_iterator(response);
881 while (payloads->has_next(payloads))
882 {
883 payload_t *payload;
884 payloads->current(payloads, (void**)&payload);
885
886 switch (payload->get_type(payload))
887 {
888 case SECURITY_ASSOCIATION:
889 {
890 sa_payload = (sa_payload_t*)payload;
891 break;
892 }
893 case KEY_EXCHANGE:
894 {
895 ke_payload = (ke_payload_t*)payload;
896 break;
897 }
898 case NONCE:
899 {
900 nonce_payload = (nonce_payload_t*)payload;
901 break;
902 }
903 case NOTIFY:
904 {
905 status = process_notifys(this, (notify_payload_t*)payload);
906 if (status == FAILED)
907 {
908 payloads->destroy(payloads);
909 /* we return SUCCESS, returned FAILED means do next transaction */
910 return SUCCESS;
911 }
912 if (status == DESTROY_ME)
913 {
914 payloads->destroy(payloads);
915 return status;
916 }
917 break;
918 }
919 default:
920 {
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));
924 break;
925 }
926 }
927 }
928 payloads->destroy(payloads);
929
930 if (!(nonce_payload && sa_payload && ke_payload))
931 {
932 this->logger->log(this->logger, AUDIT, "response message incomplete, deleting IKE_SA");
933 return DESTROY_ME;
934 }
935
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
941 */
942 proposal_t *proposal;
943 linked_list_t *proposal_list;
944
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)
948 {
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)
952 {
953 proposal->destroy(proposal);
954 }
955 proposal_list->destroy(proposal_list);
956 return DESTROY_ME;
957 }
958
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);
962
963 if (this->proposal == NULL)
964 {
965 this->logger->log(this->logger, AUDIT,
966 "peer selected a proposal we did not offer, deleting IKE_SA");
967 return DESTROY_ME;
968 }
969 }
970
971 { /* process KE payload:
972 * -------------------
973 * - extract others public value
974 * - complete diffie-hellman exchange
975 */
976 this->diffie_hellman->set_other_public_value(this->diffie_hellman,
977 ke_payload->get_key_exchange_data(ke_payload));
978 }
979
980 { /* process NONCE payload:
981 * ----------------------
982 * - extract nonce used for key derivation */
983 this->nonce_r = nonce_payload->get_nonce(nonce_payload);
984 }
985
986 { /* process NATT stuff:
987 * -------------------
988 * - check if we or other is NATted
989 * - switch to port 4500 if so
990 */
991 if ((!this->natd_dst_seen && this->natd_src_seen) ||
992 (this->natd_dst_seen && !this->natd_src_seen))
993 {
994 this->logger->log(this->logger, AUDIT,
995 "request contained wrong number of NAT-D payloads, deleting IKE_SA");
996 return DESTROY_ME;
997 }
998 if (this->natd_src_seen && !this->natd_src_matched)
999 {
1000 this->ike_sa->enable_natt(this->ike_sa, FALSE);
1001 }
1002 if (this->natd_dst_seen && !this->natd_dst_matched)
1003 {
1004 this->ike_sa->enable_natt(this->ike_sa, TRUE);
1005 }
1006 if (this->ike_sa->is_natt_enabled(this->ike_sa))
1007 {
1008 me = this->ike_sa->get_my_host(this->ike_sa);
1009 me->set_port(me, IKEV2_NATT_PORT);
1010 other = this->ike_sa->get_other_host(this->ike_sa);
1011 other->set_port(other, IKEV2_NATT_PORT);
1012
1013 this->logger->log(this->logger, CONTROL|LEVEL1, "switching to port %d", IKEV2_NATT_PORT);
1014 }
1015 }
1016
1017 /* because we are original initiator we have to update the responder SPI to the new one */
1018 ike_sa_id = this->ike_sa->get_id(this->ike_sa);
1019 ike_sa_id->set_responder_spi(ike_sa_id, responder_spi);
1020
1021 /* derive all the keys used in the IKE_SA */
1022 if (this->ike_sa->derive_keys(this->ike_sa, this->proposal,
1023 this->diffie_hellman,
1024 this->nonce_i, this->nonce_r,
1025 TRUE, NULL, NULL) != SUCCESS)
1026 {
1027 this->logger->log(this->logger, AUDIT,
1028 "transform objects could not be created from selected proposal, deleting IKE_SA");
1029 return DESTROY_ME;
1030 }
1031
1032 this->ike_sa->set_lifetimes(this->ike_sa,
1033 this->connection->get_soft_lifetime(this->connection),
1034 this->connection->get_hard_lifetime(this->connection));
1035
1036 { /* create ike_auth transaction, which will continue IKE_SA setup */
1037 chunk_t request_chunk, response_chunk;
1038 ike_auth_t *ike_auth;
1039
1040 request_chunk = this->message->get_packet_data(this->message);
1041 response_chunk = response->get_packet_data(response);
1042
1043 /* create next transaction, for which we except a message */
1044 ike_auth = ike_auth_create(this->ike_sa);
1045 ike_auth->set_config(ike_auth, this->connection, this->policy);
1046 ike_auth->set_reqid(ike_auth, this->reqid);
1047 this->connection = NULL;
1048 this->policy = NULL;
1049 ike_auth->set_nonces(ike_auth,
1050 chunk_clone(this->nonce_i),
1051 chunk_clone(this->nonce_r));
1052 ike_auth->set_init_messages(ike_auth, request_chunk, response_chunk);
1053 *next = (transaction_t*)ike_auth;
1054 }
1055
1056 return SUCCESS;
1057 }
1058
1059 static void destroy(private_ike_sa_init_t *this)
1060 {
1061 DESTROY_IF(this->message);
1062 DESTROY_IF(this->diffie_hellman);
1063 DESTROY_IF(this->proposal);
1064 DESTROY_IF(this->connection);
1065 DESTROY_IF(this->policy);
1066 chunk_free(&this->nonce_i);
1067 chunk_free(&this->nonce_r);
1068 this->randomizer->destroy(this->randomizer);
1069 this->nat_hasher->destroy(this->nat_hasher);
1070 chunk_free(&this->natd_src_hash);
1071 chunk_free(&this->natd_dst_hash);
1072 free(this);
1073 }
1074
1075 /*
1076 * Described in header.
1077 */
1078 ike_sa_init_t *ike_sa_init_create(ike_sa_t *ike_sa)
1079 {
1080 private_ike_sa_init_t *this = malloc_thing(private_ike_sa_init_t);
1081
1082 /* transaction interface functions */
1083 this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
1084 this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
1085 this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
1086 this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
1087 this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
1088 this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
1089
1090 /* public functions */
1091 this->public.set_config = (void(*)(ike_sa_init_t*,connection_t*,policy_t*))set_config;
1092 this->public.set_reqid = (void(*)(ike_sa_init_t*,u_int32_t))set_reqid;
1093 this->public.use_dh_group = (bool(*)(ike_sa_init_t*,diffie_hellman_group_t))use_dh_group;
1094
1095 /* private data */
1096 this->ike_sa = ike_sa;
1097 this->message_id = 0;
1098 this->message = NULL;
1099 this->requested = 0;
1100 this->diffie_hellman = NULL;
1101 this->nonce_i = CHUNK_INITIALIZER;
1102 this->nonce_r = CHUNK_INITIALIZER;
1103 this->connection = NULL;
1104 this->policy = NULL;
1105 this->proposal = NULL;
1106 this->reqid = 0;
1107 this->randomizer = randomizer_create();
1108 this->nat_hasher = hasher_create(HASH_SHA1);
1109 this->natd_src_hash = CHUNK_INITIALIZER;
1110 this->natd_dst_hash = CHUNK_INITIALIZER;
1111 this->natd_src_seen = FALSE;
1112 this->natd_dst_seen = FALSE;
1113 this->natd_src_matched = FALSE;
1114 this->natd_dst_matched = FALSE;
1115 this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
1116
1117 return &this->public;
1118 }