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