2 * @file responder_init.c
4 * @brief Implementation of responder_init_t.
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 #include "responder_init.h"
26 #include <sa/states/state.h>
27 #include <sa/states/ike_sa_init_responded.h>
28 #include <encoding/payloads/sa_payload.h>
29 #include <encoding/payloads/ke_payload.h>
30 #include <encoding/payloads/nonce_payload.h>
31 #include <encoding/payloads/notify_payload.h>
32 #include <crypto/diffie_hellman.h>
35 typedef struct private_responder_init_t private_responder_init_t
;
38 * Private data of a responder_init_t object.
41 struct private_responder_init_t
{
43 * Methods of the state_t interface.
45 responder_init_t
public;
50 protected_ike_sa_t
*ike_sa
;
53 * Diffie Hellman object used to compute shared secret.
55 diffie_hellman_t
*diffie_hellman
;
58 * Diffie Hellman group number from selected IKE proposal.
60 u_int16_t dh_group_number
;
63 * Priority used to get matching dh_group number.
65 u_int16_t dh_group_priority
;
70 * This value is passed to the next state of type IKE_SA_INIT_RESPONDED.
75 * Received nonce value
77 * This value is passed to the next state of type IKE_SA_INIT_RESPONDED.
79 chunk_t received_nonce
;
87 * Logger used to log data .
89 * Is logger of ike_sa!
94 * Handles received SA payload and builds the SA payload for the response.
96 * @param this calling object
97 * @param sa_request The received SA payload
98 * @param response the SA payload is added to this response message_t object.
103 status_t (*build_sa_payload
) (private_responder_init_t
*this,sa_payload_t
*sa_request
, message_t
*response
);
106 * Handles received KE payload and builds the KE payload for the response.
108 * @param this calling object
109 * @param ke_request The received KE payload
110 * @param response the KE payload is added to this response message_t object.
114 status_t (*build_ke_payload
) (private_responder_init_t
*this,ke_payload_t
*ke_request
, message_t
*response
);
117 * Handles received NONCE payload and builds the NONCE payload for the response.
119 * @param this calling object
120 * @param nonce_request The received NONCE payload
121 * @param response the NONCE payload is added to this response message_t object.
125 status_t (*build_nonce_payload
) (private_responder_init_t
*this,nonce_payload_t
*nonce_request
, message_t
*response
);
128 * Sends a IKE_SA_INIT reply containing a notify payload.
130 * @param this calling object
131 * @param notify_payload notify_payload to process
133 status_t (*process_notify_payload
) (private_responder_init_t
*this, notify_payload_t
*notify_payload
);
136 * Destroy function called internally of this class after change
137 * to state IKE_SA_INIT_RESPONDED succeeded.
139 * This destroy function does not destroy objects which were passed to the new state.
141 * @param this calling object
143 void (*destroy_after_state_change
) (private_responder_init_t
*this);
148 * Implementation of state_t.process_message.
150 static status_t
process_message(private_responder_init_t
*this, message_t
*message
)
152 ike_sa_init_responded_t
*next_state
;
153 chunk_t ike_sa_init_response_data
;
154 chunk_t ike_sa_init_request_data
;
155 sa_payload_t
*sa_request
= NULL
;
156 ke_payload_t
*ke_request
= NULL
;
157 nonce_payload_t
*nonce_request
= NULL
;
158 host_t
*source
, *destination
;
159 connection_t
*connection
;
160 iterator_t
*payloads
;
164 if (message
->get_exchange_type(message
) != IKE_SA_INIT
)
166 this->logger
->log(this->logger
, ERROR
| LEVEL1
, "Message of type %s not supported in state responder_init",mapping_find(exchange_type_m
,message
->get_exchange_type(message
)));
169 if (!message
->get_request(message
))
171 this->logger
->log(this->logger
, ERROR
| LEVEL1
, "IKE_SA_INIT responses not allowed state ike_sa_init_responded");
175 /* this is the first message to process, so get host infos */
176 source
= message
->get_source(message
);
177 destination
= message
->get_destination(message
);
179 connection
= charon
->connections
->get_connection_by_hosts(charon
->connections
, destination
, source
);
180 if (connection
== NULL
)
182 /* no configuration matches given hosts */
183 this->logger
->log(this->logger
, AUDIT
, "IKE_SA_INIT request does not match any available connection. Deleting IKE_SA");
184 /* TODO: inform requestor */
187 this->ike_sa
->set_connection(this->ike_sa
,connection
);
189 /* parse incoming message */
190 status
= message
->parse_body(message
, NULL
, NULL
);
191 if (status
!= SUCCESS
)
193 if (status
== NOT_SUPPORTED
)
195 this->logger
->log(this->logger
, AUDIT
, "IKE_SA_INIT request contains unsupported payload with critical flag set. "
197 this->ike_sa
->send_notify(this->ike_sa
, IKE_SA_INIT
, UNSUPPORTED_CRITICAL_PAYLOAD
, CHUNK_INITIALIZER
);
201 this->logger
->log(this->logger
, AUDIT
, "Unable to parse IKE_SA_INIT request. Deleting IKE_SA");
206 payloads
= message
->get_payload_iterator(message
);
207 while (payloads
->has_next(payloads
))
211 payloads
->current(payloads
, (void**)&payload
);
213 switch (payload
->get_type(payload
))
215 case SECURITY_ASSOCIATION
:
217 sa_request
= (sa_payload_t
*)payload
;
222 ke_request
= (ke_payload_t
*)payload
;
227 nonce_request
= (nonce_payload_t
*)payload
;
232 notify_payload_t
*notify_payload
= (notify_payload_t
*) payload
;
233 status
= this->process_notify_payload(this, notify_payload
);
234 if (status
!= SUCCESS
)
236 payloads
->destroy(payloads
);
242 this->logger
->log(this->logger
, ERROR
|LEVEL1
, "Ignoring payload %s (%d)",
243 mapping_find(payload_type_m
, payload
->get_type(payload
)), payload
->get_type(payload
));
248 payloads
->destroy(payloads
);
250 /* check if we have all payloads */
251 if (!(sa_request
&& ke_request
&& nonce_request
))
253 this->logger
->log(this->logger
, AUDIT
, "IKE_SA_INIT request did not contain all required payloads. Deleting IKE_SA");
257 this->ike_sa
->build_message(this->ike_sa
, IKE_SA_INIT
, FALSE
, &response
);
259 status
= this->build_sa_payload(this, sa_request
, response
);
260 if (status
!= SUCCESS
)
262 response
->destroy(response
);
266 status
= this->build_ke_payload(this, ke_request
, response
);
267 if (status
!= SUCCESS
)
269 response
->destroy(response
);
273 status
= this->build_nonce_payload(this, nonce_request
, response
);
274 if (status
!= SUCCESS
)
276 response
->destroy(response
);
280 /* derive all the keys used in the IKE_SA */
281 status
= this->ike_sa
->build_transforms(this->ike_sa
, this->proposal
, this->diffie_hellman
, this->received_nonce
, this->sent_nonce
);
282 if (status
!= SUCCESS
)
284 this->logger
->log(this->logger
, AUDIT
, "Transform objects could not be created from selected proposal. Deleting IKE_SA");
288 /* message can now be sent (must not be destroyed) */
289 status
= this->ike_sa
->send_response(this->ike_sa
, response
);
290 if (status
!= SUCCESS
)
292 this->logger
->log(this->logger
, AUDIT
, "Unable to send IKE_SA_INIT response. Deleting IKE_SA");
293 response
->destroy(response
);
297 /* state can now be changed */
298 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "Create next state object of type IKE_SA_INIT_RESPONDED");
300 response
= this->ike_sa
->get_last_responded_message(this->ike_sa
);
301 ike_sa_init_response_data
= response
->get_packet_data(response
);
302 ike_sa_init_request_data
= message
->get_packet_data(message
);
304 next_state
= ike_sa_init_responded_create(this->ike_sa
, this->received_nonce
, this->sent_nonce
,ike_sa_init_request_data
,
305 ike_sa_init_response_data
);
307 /* state can now be changed */
308 this->ike_sa
->set_new_state(this->ike_sa
, (state_t
*) next_state
);
309 this->destroy_after_state_change(this);
315 * Implementation of private_initiator_init_t.build_sa_payload.
317 static status_t
build_sa_payload(private_responder_init_t
*this,sa_payload_t
*sa_request
, message_t
*response
)
319 proposal_t
*proposal
;
320 linked_list_t
*proposal_list
;
321 connection_t
*connection
;
322 sa_payload_t
* sa_payload
;
325 connection
= this->ike_sa
->get_connection(this->ike_sa
);
327 this->logger
->log(this->logger
, CONTROL
| LEVEL2
, "Process received SA payload");
329 /* get the list of suggested proposals */
330 proposal_list
= sa_request
->get_proposals (sa_request
);
332 /* select proposal */
333 this->proposal
= connection
->select_proposal(connection
, proposal_list
);
334 while(proposal_list
->remove_last(proposal_list
, (void**)&proposal
) == SUCCESS
)
336 proposal
->destroy(proposal
);
338 proposal_list
->destroy(proposal_list
);
339 if (this->proposal
== NULL
)
341 this->logger
->log(this->logger
, AUDIT
, "IKE_SA_INIT request did not contain any acceptable proposals. Deleting IKE_SA");
342 this->ike_sa
->send_notify(this->ike_sa
, IKE_SA_INIT
, NO_PROPOSAL_CHOSEN
, CHUNK_INITIALIZER
);
345 /* get selected DH group to force policy, this is very restrictive!? */
346 this->proposal
->get_algorithm(this->proposal
, PROTO_IKE
, DIFFIE_HELLMAN_GROUP
, &algo
);
347 this->dh_group_number
= algo
->algorithm
;
349 this->logger
->log(this->logger
, CONTROL
| LEVEL2
, "SA Payload processed");
351 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "Building SA payload");
352 sa_payload
= sa_payload_create_from_proposal(this->proposal
);
353 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "add SA payload to message");
354 response
->add_payload(response
,(payload_t
*) sa_payload
);
360 * Implementation of private_initiator_init_t.build_ke_payload.
362 static status_t
build_ke_payload(private_responder_init_t
*this,ke_payload_t
*ke_request
, message_t
*response
)
364 diffie_hellman_group_t group
;
365 ke_payload_t
*ke_payload
;
366 diffie_hellman_t
*dh
;
369 this->logger
->log(this->logger
, CONTROL
| LEVEL2
, "Process received KE payload");
370 group
= ke_request
->get_dh_group_number(ke_request
);
372 if (group
== MODP_UNDEFINED
)
374 this->logger
->log(this->logger
, AUDIT
, "No diffie hellman group to select. Deleting IKE_SA");
378 if (this->dh_group_number
!= group
)
380 u_int16_t accepted_group
;
381 chunk_t accepted_group_chunk
;
382 /* group not same as selected one
383 * Maybe key exchange payload is before SA payload */
384 this->logger
->log(this->logger
, AUDIT
, "IKE_SA_INIT request did not contain a acceptable diffie hellman group. Deleting IKE_SA");
386 accepted_group
= htons(this->dh_group_number
);
387 accepted_group_chunk
.ptr
= (u_int8_t
*) &(accepted_group
);
388 accepted_group_chunk
.len
= 2;
389 this->ike_sa
->send_notify(this->ike_sa
,IKE_SA_INIT
,INVALID_KE_PAYLOAD
,accepted_group_chunk
);
393 /* create diffie hellman object to handle DH exchange */
394 dh
= diffie_hellman_create(group
);
397 this->logger
->log(this->logger
, AUDIT
, "Could not generate DH object with group %d. Deleting IKE_SA",
398 mapping_find(diffie_hellman_group_m
,group
) );
401 this->logger
->log(this->logger
, CONTROL
| LEVEL2
, "Set other DH public value");
403 dh
->set_other_public_value(dh
, ke_request
->get_key_exchange_data(ke_request
));
405 this->diffie_hellman
= dh
;
407 this->logger
->log(this->logger
, CONTROL
| LEVEL2
, "KE Payload processed.");
409 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "Building KE payload");
410 this->diffie_hellman
->get_my_public_value(this->diffie_hellman
,&key_data
);
412 ke_payload
= ke_payload_create();
413 ke_payload
->set_key_exchange_data(ke_payload
,key_data
);
414 ke_payload
->set_dh_group_number(ke_payload
, this->dh_group_number
);
415 chunk_free(&key_data
);
417 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "Add KE payload to message");
418 response
->add_payload(response
,(payload_t
*) ke_payload
);
424 * Implementation of private_responder_init_t.build_nonce_payload.
426 static status_t
build_nonce_payload(private_responder_init_t
*this,nonce_payload_t
*nonce_request
, message_t
*response
)
428 nonce_payload_t
*nonce_payload
;
429 randomizer_t
*randomizer
;
432 this->logger
->log(this->logger
, CONTROL
| LEVEL2
, "Process received NONCE payload");
433 free(this->received_nonce
.ptr
);
434 this->received_nonce
= CHUNK_INITIALIZER
;
436 this->logger
->log(this->logger
, CONTROL
| LEVEL2
, "Get NONCE value and store it");
437 this->received_nonce
= nonce_request
->get_nonce(nonce_request
);
439 this->logger
->log(this->logger
, CONTROL
| LEVEL2
, "Create new NONCE value.");
441 randomizer
= this->ike_sa
->get_randomizer(this->ike_sa
);
442 status
= randomizer
->allocate_pseudo_random_bytes(randomizer
, NONCE_SIZE
, &(this->sent_nonce
));
443 if (status
!= SUCCESS
)
448 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "Building NONCE payload");
449 nonce_payload
= nonce_payload_create();
450 nonce_payload
->set_nonce(nonce_payload
, this->sent_nonce
);
452 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "Add NONCE payload to message");
453 response
->add_payload(response
,(payload_t
*) nonce_payload
);
459 * Implementation of private_responder_init_t.process_notify_payload.
461 static status_t
process_notify_payload(private_responder_init_t
*this, notify_payload_t
*notify_payload
)
463 notify_message_type_t notify_message_type
= notify_payload
->get_notify_message_type(notify_payload
);
465 this->logger
->log(this->logger
, CONTROL
|LEVEL1
, "Process notify type %s",
466 mapping_find(notify_message_type_m
, notify_message_type
));
468 if (notify_payload
->get_protocol_id(notify_payload
) != PROTO_IKE
)
470 this->logger
->log(this->logger
, ERROR
| LEVEL1
, "Notify reply not for IKE protocol.");
473 switch (notify_message_type
)
477 this->logger
->log(this->logger
, CONTROL
, "IKE_SA_INIT request contained a notify (%d), ignored.",
478 notify_message_type
);
485 * Implementation of state_t.get_state.
487 static ike_sa_state_t
get_state(private_responder_init_t
*this)
489 return RESPONDER_INIT
;
493 * Implementation of state_t.destroy.
495 static void destroy(private_responder_init_t
*this)
497 this->logger
->log(this->logger
, CONTROL
| LEVEL1
, "Going to destroy responder init state object");
499 this->logger
->log(this->logger
, CONTROL
| LEVEL2
, "Destroy sent nonce");
500 chunk_free(&(this->sent_nonce
));
501 this->logger
->log(this->logger
, CONTROL
| LEVEL2
, "Destroy received nonce");
502 chunk_free(&(this->received_nonce
));
504 if (this->diffie_hellman
!= NULL
)
506 this->logger
->log(this->logger
, CONTROL
| LEVEL2
, "Destroy diffie_hellman_t hellman object");
507 this->diffie_hellman
->destroy(this->diffie_hellman
);
511 this->proposal
->destroy(this->proposal
);
513 this->logger
->log(this->logger
, CONTROL
| LEVEL2
, "Destroy object");
518 * Implementation of private_responder_init_t.destroy_after_state_change
520 static void destroy_after_state_change (private_responder_init_t
*this)
522 this->logger
->log(this->logger
, CONTROL
| LEVEL1
, "Going to destroy responder_init_t state object");
524 /* destroy diffie hellman object */
525 if (this->diffie_hellman
!= NULL
)
527 this->logger
->log(this->logger
, CONTROL
| LEVEL2
, "Destroy diffie_hellman_t object");
528 this->diffie_hellman
->destroy(this->diffie_hellman
);
532 this->proposal
->destroy(this->proposal
);
535 this->logger
->log(this->logger
, CONTROL
| LEVEL2
, "Destroy object");
540 * Described in header.
542 responder_init_t
*responder_init_create(protected_ike_sa_t
*ike_sa
)
544 private_responder_init_t
*this = malloc_thing(private_responder_init_t
);
546 /* interface functions */
547 this->public.state_interface
.process_message
= (status_t (*) (state_t
*,message_t
*)) process_message
;
548 this->public.state_interface
.get_state
= (ike_sa_state_t (*) (state_t
*)) get_state
;
549 this->public.state_interface
.destroy
= (void (*) (state_t
*)) destroy
;
551 /* private functions */
552 this->build_sa_payload
= build_sa_payload
;
553 this->build_ke_payload
= build_ke_payload
;
554 this->build_nonce_payload
= build_nonce_payload
;
555 this->destroy_after_state_change
= destroy_after_state_change
;
556 this->process_notify_payload
= process_notify_payload
;
559 this->ike_sa
= ike_sa
;
560 this->logger
= logger_manager
->get_logger(logger_manager
, IKE_SA
);
561 this->sent_nonce
= CHUNK_INITIALIZER
;
562 this->received_nonce
= CHUNK_INITIALIZER
;
563 this->dh_group_number
= MODP_UNDEFINED
;
564 this->diffie_hellman
= NULL
;
565 this->proposal
= NULL
;
567 return &(this->public);