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