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