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