support of cert payloads
[strongswan.git] / src / charon / sa / states / responder_init.c
1 /**
2 * @file responder_init.c
3 *
4 * @brief Implementation of responder_init_t.
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 "responder_init.h"
25
26 #include <daemon.h>
27 #include <sa/states/state.h>
28 #include <sa/states/ike_sa_init_responded.h>
29 #include <encoding/payloads/sa_payload.h>
30 #include <encoding/payloads/ke_payload.h>
31 #include <encoding/payloads/nonce_payload.h>
32 #include <encoding/payloads/certreq_payload.h>
33 #include <encoding/payloads/notify_payload.h>
34 #include <crypto/diffie_hellman.h>
35 #include <queues/jobs/send_keepalive_job.h>
36
37
38 typedef struct private_responder_init_t private_responder_init_t;
39
40 /**
41 * Private data of a responder_init_t object.
42 *
43 */
44 struct private_responder_init_t {
45 /**
46 * Methods of the state_t interface.
47 */
48 responder_init_t public;
49
50 /**
51 * Assigned IKE_SA.
52 */
53 protected_ike_sa_t *ike_sa;
54
55 /**
56 * Diffie Hellman object used to compute shared secret.
57 */
58 diffie_hellman_t *diffie_hellman;
59
60 /**
61 * Diffie Hellman group number from selected IKE proposal.
62 */
63 u_int16_t dh_group_number;
64
65 /**
66 * Priority used to get matching dh_group number.
67 */
68 u_int16_t dh_group_priority;
69
70 /**
71 * Sent nonce value.
72 *
73 * This value is passed to the next state of type IKE_SA_INIT_RESPONDED.
74 */
75 chunk_t sent_nonce;
76
77 /**
78 * Received nonce value
79 *
80 * This value is passed to the next state of type IKE_SA_INIT_RESPONDED.
81 */
82 chunk_t received_nonce;
83
84 /**
85 * Selected proposal
86 */
87 proposal_t *proposal;
88
89 /**
90 * Logger used to log data .
91 *
92 * Is logger of ike_sa!
93 */
94 logger_t *logger;
95
96 /**
97 * Precomputed NAT-D hash for initiator.
98 */
99 chunk_t natd_hash_i;
100
101 /**
102 * Flag indicating that an initiator NAT-D hash matched.
103 */
104 bool natd_hash_i_matched;
105
106 /**
107 * NAT-D payload count for NAT_DETECTION_SOURCE_IP.
108 */
109 int natd_seen_i;
110
111 /**
112 * Precomputed NAT-D hash of responder.
113 */
114 chunk_t natd_hash_r;
115
116 /**
117 * Flag indicating that a responder NAT-D hash matched.
118 */
119 bool natd_hash_r_matched;
120
121 /**
122 * NAT-D payload count for NAT_DETECTION_DESTINATION_IP.
123 */
124 int natd_seen_r;
125
126
127 /**
128 * Handles received SA payload and builds the SA payload for the response.
129 *
130 * @param this calling object
131 * @param sa_request The received SA payload
132 * @param msg the SA payload is added to this message_t object.
133 * @return
134 * - DESTROY_ME
135 * - SUCCESS
136 */
137 status_t (*build_sa_payload) (private_responder_init_t *this,sa_payload_t *sa_request, message_t *msg);
138
139 /**
140 * Handles received KE payload and builds the KE payload for the response.
141 *
142 * @param this calling object
143 * @param ke_request The received KE payload
144 * @param msg the KE payload is added to this message_t object.
145 * @return
146 * - DESTROY_ME
147 * - SUCCESS
148 */
149 status_t (*build_ke_payload) (private_responder_init_t *this,ke_payload_t *ke_request, message_t *msg);
150
151 /**
152 * Handles received NONCE payload and builds the NONCE payload for the response.
153 *
154 * @param this calling object
155 * @param nonce_request The received NONCE payload
156 * @param msg the NONCE payload is added to this message_t object.
157 * @return
158 * - DESTROY_ME
159 * - SUCCESS
160 */
161 status_t (*build_nonce_payload) (private_responder_init_t *this,nonce_payload_t *nonce_request, message_t *msg);
162
163 /**
164 * Build CERTREQ payload for the response.
165 *
166 * @param this calling object
167 * @param msg the CERTREQ payload is added to this message_t object
168 * @return
169 * - SUCCESS
170 * - FAILED
171 */
172 status_t (*build_certreq_payload) (private_responder_init_t *this, message_t *msg);
173
174
175 /**
176 * Builds the NAT-T Notify(NAT_DETECTION_SOURCE_IP) and
177 * Notify(NAT_DETECTION_DESTINATION_IP) payloads for this state.
178 *
179 * @param this calling object
180 * @param msg message_t object to add the Notify payloads
181 */
182 void (*build_natd_payload) (private_responder_init_t *this, message_t *msg, notify_message_type_t type, host_t *host);
183
184 /**
185 * Builds the NAT-T Notify(NAT_DETECTION_SOURCE_IP) and
186 * Notify(NAT_DETECTION_DESTINATION_IP) payloads for this state.
187 *
188 * @param this calling object
189 * @param msg message_t object to add the Notify payloads
190 */
191 void (*build_natd_payloads) (private_responder_init_t *this, message_t *msg);
192
193 /**
194 * Sends a IKE_SA_INIT reply containing a notify payload.
195 *
196 * @param this calling object
197 * @param notify_payload notify_payload to process
198 */
199 status_t (*process_notify_payload) (private_responder_init_t *this, notify_payload_t *notify_payload);
200
201 /**
202 * Destroy function called internally of this class after change
203 * to state IKE_SA_INIT_RESPONDED succeeded.
204 *
205 * This destroy function does not destroy objects which were passed to the new state.
206 *
207 * @param this calling object
208 */
209 void (*destroy_after_state_change) (private_responder_init_t *this);
210
211 };
212
213 /**
214 * Implementation of state_t.process_message.
215 */
216 static status_t process_message(private_responder_init_t *this, message_t *message)
217 {
218 ike_sa_init_responded_t *next_state;
219 chunk_t ike_sa_init_response_data;
220 chunk_t ike_sa_init_request_data;
221 sa_payload_t *sa_request = NULL;
222 ke_payload_t *ke_request = NULL;
223 nonce_payload_t *nonce_request = NULL;
224 host_t *source, *destination;
225 connection_t *connection;
226 iterator_t *payloads;
227 message_t *response;
228 status_t status;
229
230 if (message->get_exchange_type(message) != IKE_SA_INIT)
231 {
232 this->logger->log(this->logger, ERROR | LEVEL1, "message of type %s not supported in state responder_init",
233 mapping_find(exchange_type_m,message->get_exchange_type(message)));
234 return DESTROY_ME;
235 }
236 if (!message->get_request(message))
237 {
238 this->logger->log(this->logger, ERROR | LEVEL1, "IKE_SA_INIT responses not allowed in state ike_sa_init_responded");
239 return DESTROY_ME;
240 }
241
242 /* this is the first message to process, so get host infos */
243 source = message->get_source(message);
244 destination = message->get_destination(message);
245
246 connection = charon->connections->get_connection_by_hosts(charon->connections, destination, source);
247 if (connection == NULL)
248 {
249 /* no configuration matches given hosts */
250 this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request does not match any available connection, deleting IKE_SA");
251 /* TODO: inform requestor */
252 return DESTROY_ME;
253 }
254 this->ike_sa->set_connection(this->ike_sa, connection);
255 status = this->ike_sa->update_connection_hosts(this->ike_sa,
256 destination, source);
257 if (status != SUCCESS)
258 {
259 return status;
260 }
261
262 /* parse incoming message */
263 status = message->parse_body(message, NULL, NULL);
264 if (status != SUCCESS)
265 {
266 if (status == NOT_SUPPORTED)
267 {
268 this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request contains unsupported payload with critical flag set, "
269 "deleting IKE_SA");
270 this->ike_sa->send_notify(this->ike_sa, IKE_SA_INIT, UNSUPPORTED_CRITICAL_PAYLOAD, CHUNK_INITIALIZER);
271 }
272 else
273 {
274 this->logger->log(this->logger, AUDIT, "unable to parse IKE_SA_INIT request, deleting IKE_SA");
275 }
276 return DESTROY_ME;
277 }
278
279 /*
280 * Precompute NAT-D hashes.
281 * Even though there SHOULD only be a single payload of Notify type
282 * NAT_DETECTION_DESTINATION_IP we precompute both hashes.
283 */
284 this->natd_hash_i = this->ike_sa->generate_natd_hash(this->ike_sa,
285 message->get_initiator_spi(message),
286 message->get_responder_spi(message),
287 message->get_source(message));
288 this->natd_hash_i_matched = FALSE;
289 this->natd_seen_i = 0;
290 this->natd_hash_r = this->ike_sa->generate_natd_hash(this->ike_sa,
291 message->get_initiator_spi(message),
292 message->get_responder_spi(message),
293 message->get_destination(message));
294 this->natd_hash_r_matched = FALSE;
295 this->natd_seen_r = 0;
296 this->ike_sa->set_my_host_behind_nat(this->ike_sa, FALSE);
297 this->ike_sa->set_other_host_behind_nat(this->ike_sa, FALSE);
298
299 /* Iterate over all payloads.
300 *
301 * The message is already checked for the right payload types.
302 */
303 payloads = message->get_payload_iterator(message);
304 while (payloads->has_next(payloads))
305 {
306 payload_t *payload;
307
308 payloads->current(payloads, (void**)&payload);
309
310 switch (payload->get_type(payload))
311 {
312 case SECURITY_ASSOCIATION:
313 {
314 sa_request = (sa_payload_t*)payload;
315 break;
316 }
317 case KEY_EXCHANGE:
318 {
319 ke_request = (ke_payload_t*)payload;
320 break;
321 }
322 case NONCE:
323 {
324 nonce_request = (nonce_payload_t*)payload;
325 break;
326 }
327 case NOTIFY:
328 {
329 notify_payload_t *notify_payload = (notify_payload_t *) payload;
330 status = this->process_notify_payload(this, notify_payload);
331 if (status != SUCCESS)
332 {
333 payloads->destroy(payloads);
334 return status;
335 }
336 break;
337 }
338 default:
339 {
340 this->logger->log(this->logger, ERROR|LEVEL1, "ignoring payload %s (%d)",
341 mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
342 break;
343 }
344 }
345 }
346 payloads->destroy(payloads);
347
348 /* check if we have all payloads */
349 if (!(sa_request && ke_request && nonce_request))
350 {
351 this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain all required payloads. Deleting IKE_SA");
352 return DESTROY_ME;
353 }
354
355 /* NAT-D */
356 if ((!this->natd_seen_i && this->natd_seen_r > 0)
357 || (this->natd_seen_i > 0 && !this->natd_seen_r))
358 {
359 this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request contained wrong number of NAT-D payloads. Deleting IKE_SA");
360 return DESTROY_ME;
361 }
362 if (this->natd_seen_r > 1)
363 {
364 this->logger->log(this->logger, AUDIT, "warning: IKE_SA_INIT request contained multiple Notify(NAT_DETECTION_DESTINATION_IP) payloads.");
365 }
366 if (this->natd_seen_i > 0 && !this->natd_hash_i_matched)
367 {
368 this->logger->log(this->logger, AUDIT, "remote host is behind NAT, using NAT-Traversal");
369 this->ike_sa->set_other_host_behind_nat(this->ike_sa, TRUE);
370 }
371 if (this->natd_seen_r > 0 && !this->natd_hash_r_matched)
372 {
373 this->logger->log(this->logger, AUDIT, "local host is behind NAT, using NAT-Traversal");
374 this->ike_sa->set_my_host_behind_nat(this->ike_sa, TRUE);
375 charon->event_queue->add_relative(charon->event_queue,
376 (job_t*)send_keepalive_job_create(this->ike_sa->public.get_id((ike_sa_t*)this->ike_sa)),
377 charon->configuration->get_keepalive_interval(charon->configuration));
378 }
379 if (!this->ike_sa->public.is_any_host_behind_nat((ike_sa_t*)this->ike_sa))
380 {
381 this->logger->log(this->logger, AUDIT, "no NAT detected, not using NAT-Traversal");
382 }
383
384 this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, FALSE, &response);
385
386 status = this->build_sa_payload(this, sa_request, response);
387 if (status != SUCCESS)
388 goto destroy_response;
389
390 status = this->build_ke_payload(this, ke_request, response);
391 if (status != SUCCESS)
392 goto destroy_response;
393
394 status = this->build_nonce_payload(this, nonce_request, response);
395 if (status != SUCCESS)
396 goto destroy_response;
397
398 status = this->build_certreq_payload(this, response);
399 if (status != SUCCESS)
400 goto destroy_response;
401
402 /* build Notify(NAT-D) payloads */
403 this->build_natd_payloads(this, response);
404
405 /* derive all the keys used in the IKE_SA */
406 status = this->ike_sa->build_transforms(this->ike_sa, this->proposal, this->diffie_hellman, this->received_nonce, this->sent_nonce);
407 if (status != SUCCESS)
408 {
409 this->logger->log(this->logger, AUDIT, "transform objects could not be created from selected proposal, deleting IKE_SA");
410 return DESTROY_ME;
411 }
412
413 /* message can now be sent (must not be destroyed) */
414 status = this->ike_sa->send_response(this->ike_sa, response);
415 if (status != SUCCESS)
416 {
417 this->logger->log(this->logger, AUDIT, "unable to send IKE_SA_INIT response, deleting IKE_SA");
418 response->destroy(response);
419 return DESTROY_ME;
420 }
421
422 /* state can now be changed */
423 this->logger->log(this->logger, CONTROL|LEVEL2, "create next state object of type IKE_SA_INIT_RESPONDED");
424
425 response = this->ike_sa->get_last_responded_message(this->ike_sa);
426 ike_sa_init_response_data = response->get_packet_data(response);
427 ike_sa_init_request_data = message->get_packet_data(message);
428
429 next_state = ike_sa_init_responded_create(this->ike_sa, this->received_nonce, this->sent_nonce,ike_sa_init_request_data,
430 ike_sa_init_response_data);
431
432 /* state can now be changed */
433 this->ike_sa->set_new_state(this->ike_sa, (state_t *) next_state);
434 this->destroy_after_state_change(this);
435 return SUCCESS;
436
437 destroy_response:
438 response->destroy(response);
439 return status;
440
441 }
442
443 /**
444 * Implementation of private_initiator_init_t.build_sa_payload.
445 */
446 static status_t build_sa_payload(private_responder_init_t *this,sa_payload_t *sa_request, message_t *msg)
447 {
448 proposal_t *proposal;
449 linked_list_t *proposal_list;
450 connection_t *connection;
451 sa_payload_t* sa_payload;
452 algorithm_t *algo;
453
454 connection = this->ike_sa->get_connection(this->ike_sa);
455
456 this->logger->log(this->logger, CONTROL | LEVEL2, "process received SA payload");
457
458 /* get the list of suggested proposals */
459 proposal_list = sa_request->get_proposals (sa_request);
460
461 /* select proposal */
462 this->proposal = connection->select_proposal(connection, proposal_list);
463 while(proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
464 {
465 proposal->destroy(proposal);
466 }
467 proposal_list->destroy(proposal_list);
468 if (this->proposal == NULL)
469 {
470 this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain any acceptable proposals, deleting IKE_SA");
471 this->ike_sa->send_notify(this->ike_sa, IKE_SA_INIT, NO_PROPOSAL_CHOSEN, CHUNK_INITIALIZER);
472 return DESTROY_ME;
473 }
474 /* get selected DH group to force policy, this is very restrictive!? */
475 if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, &algo))
476 {
477 this->dh_group_number = algo->algorithm;
478 }
479
480 this->logger->log(this->logger, CONTROL | LEVEL2, "SA Payload processed");
481
482 this->logger->log(this->logger, CONTROL|LEVEL2, "building SA payload");
483 sa_payload = sa_payload_create_from_proposal(this->proposal);
484 this->logger->log(this->logger, CONTROL|LEVEL2, "add SA payload to message");
485 msg->add_payload(msg, (payload_t *) sa_payload);
486
487 return SUCCESS;
488 }
489
490 /**
491 * Implementation of private_initiator_init_t.build_ke_payload.
492 */
493 static status_t build_ke_payload(private_responder_init_t *this,ke_payload_t *ke_request, message_t *msg)
494 {
495 diffie_hellman_group_t group;
496 ke_payload_t *ke_payload;
497 diffie_hellman_t *dh;
498 chunk_t key_data;
499
500 this->logger->log(this->logger, CONTROL | LEVEL2, "process received KE payload");
501 group = ke_request->get_dh_group_number(ke_request);
502
503 if (group == MODP_NONE)
504 {
505 this->logger->log(this->logger, AUDIT, "no Diffie-Hellman group to select, deleting IKE_SA");
506 return DESTROY_ME;
507 }
508
509 if (this->dh_group_number != group)
510 {
511 u_int16_t accepted_group;
512 chunk_t accepted_group_chunk;
513 /* group not same as selected one
514 * Maybe key exchange payload is before SA payload */
515 this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain an acceptable Diffie-Hellman group, deleting IKE_SA");
516
517 accepted_group = htons(this->dh_group_number);
518 accepted_group_chunk.ptr = (u_int8_t*) &(accepted_group);
519 accepted_group_chunk.len = 2;
520 this->ike_sa->send_notify(this->ike_sa,IKE_SA_INIT,INVALID_KE_PAYLOAD,accepted_group_chunk);
521 return DESTROY_ME;
522 }
523
524 /* create diffie hellman object to handle DH exchange */
525 dh = diffie_hellman_create(group);
526 if (dh == NULL)
527 {
528 this->logger->log(this->logger, AUDIT, "could not generate DH object with group %d, deleting IKE_SA",
529 mapping_find(diffie_hellman_group_m,group) );
530 return DESTROY_ME;
531 }
532 this->logger->log(this->logger, CONTROL | LEVEL2, "set other DH public value");
533
534 dh->set_other_public_value(dh, ke_request->get_key_exchange_data(ke_request));
535
536 this->diffie_hellman = dh;
537
538 this->logger->log(this->logger, CONTROL | LEVEL2, "KE payload processed.");
539
540 this->logger->log(this->logger, CONTROL|LEVEL2, "building KE payload");
541 this->diffie_hellman->get_my_public_value(this->diffie_hellman,&key_data);
542
543 ke_payload = ke_payload_create();
544 ke_payload->set_key_exchange_data(ke_payload,key_data);
545 ke_payload->set_dh_group_number(ke_payload, this->dh_group_number);
546 chunk_free(&key_data);
547
548 this->logger->log(this->logger, CONTROL|LEVEL2, "add KE payload to message");
549 msg->add_payload(msg, (payload_t *) ke_payload);
550
551 return SUCCESS;
552 }
553
554 /**
555 * Implementation of private_responder_init_t.build_nonce_payload.
556 */
557 static status_t build_nonce_payload(private_responder_init_t *this,nonce_payload_t *nonce_request, message_t *msg)
558 {
559 nonce_payload_t *nonce_payload;
560 randomizer_t *randomizer;
561 status_t status;
562
563 this->logger->log(this->logger, CONTROL | LEVEL2, "process received NONCE payload");
564 free(this->received_nonce.ptr);
565 this->received_nonce = CHUNK_INITIALIZER;
566
567 this->logger->log(this->logger, CONTROL | LEVEL2, "get NONCE value and store it");
568 this->received_nonce = nonce_request->get_nonce(nonce_request);
569
570 this->logger->log(this->logger, CONTROL | LEVEL2, "create new NONCE value.");
571
572 randomizer = this->ike_sa->get_randomizer(this->ike_sa);
573 status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE, &(this->sent_nonce));
574 if (status != SUCCESS)
575 {
576 return status;
577 }
578
579 this->logger->log(this->logger, CONTROL|LEVEL2, "building NONCE payload");
580 nonce_payload = nonce_payload_create();
581 nonce_payload->set_nonce(nonce_payload, this->sent_nonce);
582
583 this->logger->log(this->logger, CONTROL|LEVEL2, "add NONCE payload to message");
584 msg->add_payload(msg, (payload_t *) nonce_payload);
585
586 return SUCCESS;
587 }
588
589 /**
590 * Implementation of private_responder_init_t.build_certreq_payload.
591 */
592 static status_t build_certreq_payload (private_responder_init_t *this, message_t *msg)
593 {
594 if (FALSE)
595 {
596 certreq_payload_t *certreq_payload;
597
598 this->logger->log(this->logger, CONTROL|LEVEL2, "add CERTREQ payload to message");
599 msg->add_payload(msg, (payload_t *) certreq_payload);
600 }
601 return SUCCESS;
602 }
603
604 /**
605 * Implementation of private_initiator_init_t.build_natd_payload.
606 */
607 static void build_natd_payload(private_responder_init_t *this, message_t *msg, notify_message_type_t type, host_t *host)
608 {
609 chunk_t hash;
610 this->logger->log(this->logger, CONTROL|LEVEL1, "building Notify(NAT-D) payload");
611 notify_payload_t *notify_payload;
612 notify_payload = notify_payload_create();
613 /*notify_payload->set_protocol_id(notify_payload, NULL);*/
614 /*notify_payload->set_spi(notify_payload, NULL);*/
615 notify_payload->set_notify_message_type(notify_payload, type);
616 hash = this->ike_sa->generate_natd_hash(this->ike_sa,
617 msg->get_initiator_spi(msg),
618 msg->get_responder_spi(msg),
619 host);
620 notify_payload->set_notification_data(notify_payload, hash);
621 chunk_free(&hash);
622 this->logger->log(this->logger, CONTROL|LEVEL2, "add Notify(NAT-D) payload to message");
623 msg->add_payload(msg, (payload_t *) notify_payload);
624 }
625
626 /**
627 * Implementation of private_initiator_init_t.build_natd_payloads.
628 */
629 static void build_natd_payloads(private_responder_init_t *this, message_t *msg)
630 {
631 connection_t *connection;
632 connection = this->ike_sa->get_connection(this->ike_sa);
633 this->build_natd_payload(this, msg, NAT_DETECTION_SOURCE_IP,
634 connection->get_my_host(connection));
635 this->build_natd_payload(this, msg, NAT_DETECTION_DESTINATION_IP,
636 connection->get_other_host(connection));
637 }
638
639 /**
640 * Implementation of private_responder_init_t.process_notify_payload.
641 */
642 static status_t process_notify_payload(private_responder_init_t *this, notify_payload_t *notify_payload)
643 {
644 chunk_t notification_data;
645 notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload);
646
647 this->logger->log(this->logger, CONTROL|LEVEL1, "process notify type %s",
648 mapping_find(notify_message_type_m, notify_message_type));
649
650 switch (notify_message_type)
651 {
652 case NAT_DETECTION_DESTINATION_IP:
653 {
654 this->natd_seen_r++;
655 if (this->natd_hash_r_matched)
656 return SUCCESS;
657
658 notification_data = notify_payload->get_notification_data(notify_payload);
659 if (chunk_equals(notification_data, this->natd_hash_r))
660 {
661 this->natd_hash_r_matched = TRUE;
662 this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash match");
663 }
664 else
665 {
666 this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash mismatch");
667 }
668
669 return SUCCESS;
670 }
671 case NAT_DETECTION_SOURCE_IP:
672 {
673 this->natd_seen_i++;
674 if (this->natd_hash_i_matched)
675 return SUCCESS;
676
677 notification_data = notify_payload->get_notification_data(notify_payload);
678 if (chunk_equals(notification_data, this->natd_hash_i))
679 {
680 this->natd_hash_i_matched = TRUE;
681 this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash match");
682 }
683 else
684 {
685 this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash mismatch");
686 }
687
688 return SUCCESS;
689 }
690 default:
691 {
692 this->logger->log(this->logger, CONTROL, "IKE_SA_INIT request contained a notify (%d), ignored.",
693 notify_message_type);
694 return SUCCESS;
695 }
696 }
697 }
698
699 /**
700 * Implementation of state_t.get_state.
701 */
702 static ike_sa_state_t get_state(private_responder_init_t *this)
703 {
704 return RESPONDER_INIT;
705 }
706
707 /**
708 * Implementation of state_t.destroy.
709 */
710 static void destroy(private_responder_init_t *this)
711 {
712 this->logger->log(this->logger, CONTROL | LEVEL1, "going to destroy responder init state object");
713
714 this->logger->log(this->logger, CONTROL | LEVEL2, "destroy nonces");
715 chunk_free(&(this->sent_nonce));
716 this->logger->log(this->logger, CONTROL | LEVEL2, "destroy received nonce");
717 chunk_free(&(this->received_nonce));
718
719 chunk_free(&(this->natd_hash_i));
720 chunk_free(&(this->natd_hash_r));
721
722 if (this->diffie_hellman != NULL)
723 {
724 this->logger->log(this->logger, CONTROL | LEVEL2, "destroy diffie_hellman_t hellman object");
725 this->diffie_hellman->destroy(this->diffie_hellman);
726 }
727 if (this->proposal)
728 {
729 this->proposal->destroy(this->proposal);
730 }
731 this->logger->log(this->logger, CONTROL | LEVEL2, "destroy object");
732 free(this);
733 }
734
735 /**
736 * Implementation of private_responder_init_t.destroy_after_state_change
737 */
738 static void destroy_after_state_change (private_responder_init_t *this)
739 {
740 this->logger->log(this->logger, CONTROL | LEVEL1, "Going to destroy responder_init_t state object");
741
742 chunk_free(&(this->natd_hash_i));
743 chunk_free(&(this->natd_hash_r));
744
745 /* destroy diffie hellman object */
746 if (this->diffie_hellman != NULL)
747 {
748 this->logger->log(this->logger, CONTROL | LEVEL2, "destroy diffie_hellman_t object");
749 this->diffie_hellman->destroy(this->diffie_hellman);
750 }
751 if (this->proposal)
752 {
753 this->proposal->destroy(this->proposal);
754 }
755
756 this->logger->log(this->logger, CONTROL | LEVEL2, "destroy object");
757 free(this);
758 }
759
760 /*
761 * Described in header.
762 */
763 responder_init_t *responder_init_create(protected_ike_sa_t *ike_sa)
764 {
765 private_responder_init_t *this = malloc_thing(private_responder_init_t);
766
767 /* interface functions */
768 this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
769 this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
770 this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
771
772 /* private functions */
773 this->build_sa_payload = build_sa_payload;
774 this->build_ke_payload = build_ke_payload;
775 this->build_nonce_payload = build_nonce_payload;
776 this->build_certreq_payload = build_certreq_payload;
777 this->destroy_after_state_change = destroy_after_state_change;
778 this->process_notify_payload = process_notify_payload;
779 this->build_natd_payload = build_natd_payload;
780 this->build_natd_payloads = build_natd_payloads;
781
782 /* private data */
783 this->ike_sa = ike_sa;
784 this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
785 this->sent_nonce = CHUNK_INITIALIZER;
786 this->received_nonce = CHUNK_INITIALIZER;
787 this->dh_group_number = MODP_NONE;
788 this->diffie_hellman = NULL;
789 this->proposal = NULL;
790 this->natd_hash_i = CHUNK_INITIALIZER;
791 this->natd_hash_i_matched = FALSE;
792 this->natd_seen_i = 0;
793 this->natd_hash_r = CHUNK_INITIALIZER;
794 this->natd_hash_r_matched = FALSE;
795 this->natd_seen_r = 0;
796
797 return &(this->public);
798 }