4 * @brief Class ike_sa_t. An object of this type is managed by an
5 * ike_sa_manager_t object and represents an IKE_SA
10 * Copyright (C) 2005 Jan Hutter, Martin Willi
11 * Hochschule fuer Technik Rapperswil
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>.
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
28 #include <definitions.h>
29 #include <utils/allocator.h>
30 #include <utils/linked_list.h>
31 #include <utils/logger_manager.h>
32 #include <utils/randomizer.h>
33 #include <transforms/diffie_hellman.h>
34 #include <transforms/prf_plus.h>
35 #include <encoding/payloads/sa_payload.h>
36 #include <encoding/payloads/nonce_payload.h>
37 #include <encoding/payloads/ke_payload.h>
38 #include <encoding/payloads/transform_substructure.h>
39 #include <encoding/payloads/transform_attribute.h>
40 #include <sa/states/initiator_init.h>
41 #include <sa/states/responder_init.h>
42 #include <queues/jobs/delete_ike_sa_job.h>
48 * @brief implements function process_message of protected_ike_sa_t
50 static status_t
process_message (protected_ike_sa_t
*this, message_t
*message
)
53 exchange_type_t exchange_type
;
58 /* we must process each request or response from remote host */
60 /* find out type of message (request or response) */
61 is_request
= message
->get_request(message
);
62 exchange_type
= message
->get_exchange_type(message
);
64 this->logger
->log(this->logger
, CONTROL
|MORE
, "Process %s message of exchange type %s",(is_request
) ?
"REQUEST" : "RESPONSE",mapping_find(exchange_type_m
,exchange_type
));
66 message_id
= message
->get_message_id(message
);
69 * It has to be checked, if the message has to be resent cause of lost packets!
71 if (is_request
&& ( message_id
== (this->message_id_in
- 1)))
73 /* message can be resent ! */
74 this->logger
->log(this->logger
, CONTROL
|MORE
, "Resent message detected. Send stored reply");
75 return (this->resend_last_reply(this));
78 /* Now, the message id is checked for request AND reply */
81 /* In a request, the message has to be this->message_id_in (other case is already handled) */
82 if (message_id
!= this->message_id_in
)
84 this->logger
->log(this->logger
, ERROR
| MORE
, "Message request with message id %d received, but %d expected",message_id
,this->message_id_in
);
90 /* In a reply, the message has to be this->message_id_out -1 cause it is the reply to the last sent message*/
91 if (message_id
!= (this->message_id_out
- 1))
93 this->logger
->log(this->logger
, ERROR
| MORE
, "Message reply with message id %d received, but %d expected",message_id
,this->message_id_in
);
98 /* now the message is processed by the current state object */
99 status
= this->current_state
->process_message(this->current_state
,message
,&new_state
);
101 if (status
== SUCCESS
)
103 this->current_state
= new_state
;
109 * @brief Implements function build_message of protected_ike_sa_t.
111 static status_t
build_message(protected_ike_sa_t
*this, exchange_type_t type
, bool request
, message_t
**message
)
114 message_t
*new_message
;
115 host_t
*source
, *destination
;
117 this ->logger
->log(this->logger
, CONTROL
|MORE
, "build empty message");
118 new_message
= message_create();
119 if (new_message
== NULL
)
121 this->logger
->log(this->logger
, ERROR
, "Fatal error: could not create empty message object");
125 status
= this->me
.host
->clone(this->me
.host
, &source
);
126 if (status
!= SUCCESS
)
128 this->logger
->log(this->logger
, ERROR
, "Fatal error: could not clone my host information");
129 new_message
->destroy(new_message
);
132 status
= this->other
.host
->clone(this->other
.host
, &destination
);
133 if (status
!= SUCCESS
)
135 this->logger
->log(this->logger
, ERROR
, "Fatal error: could not clone other host information");
136 source
->destroy(source
);
137 new_message
->destroy(new_message
);
141 new_message
->set_source(new_message
, source
);
142 new_message
->set_destination(new_message
, destination
);
144 new_message
->set_exchange_type(new_message
, type
);
145 new_message
->set_request(new_message
, request
);
147 new_message
->set_message_id(new_message
, (request
) ?
this->message_id_out
: this->message_id_in
);
149 status
= new_message
->set_ike_sa_id(new_message
, this->ike_sa_id
);
150 if (status
!= SUCCESS
)
152 this->logger
->log(this->logger
, ERROR
, "Fatal error: could not set ike_sa_id of message");
153 new_message
->destroy(new_message
);
157 *message
= new_message
;
163 * @brief implements function process_configuration of protected_ike_sa_t
165 static status_t
initialize_connection(protected_ike_sa_t
*this, char *name
)
167 /* work is done in state object of type INITIATOR_INIT */
168 initiator_init_t
*current_state
;
172 if (this->current_state
->get_state(this->current_state
) != INITIATOR_INIT
)
177 current_state
= (initiator_init_t
*) this->current_state
;
179 status
= current_state
->initiate_connection(current_state
,name
,&new_state
);
181 if (status
== SUCCESS
)
183 this->current_state
= new_state
;
187 this->create_delete_job(this);
193 * @brief implements function protected_ike_sa_t.get_id
195 static ike_sa_id_t
* get_id(protected_ike_sa_t
*this)
197 return this->ike_sa_id
;
200 static status_t
compute_secrets (protected_ike_sa_t
*this,chunk_t dh_shared_secret
,chunk_t initiator_nonce
, chunk_t responder_nonce
)
202 chunk_t concatenated_nonces
;
204 chunk_t prf_plus_seed
;
206 u_int64_t initiator_spi
;
207 u_int64_t responder_spi
;
208 prf_plus_t
*prf_plus
;
212 * TODO check length for specific prf's
214 concatenated_nonces
.len
= (initiator_nonce
.len
+ responder_nonce
.len
);
215 concatenated_nonces
.ptr
= allocator_alloc(concatenated_nonces
.len
);
216 if (concatenated_nonces
.ptr
== NULL
)
218 this->logger
->log(this->logger
, ERROR
, "Fatal errror: Could not allocate memory for concatenated nonces");
221 /* first is initiator */
222 memcpy(concatenated_nonces
.ptr
,initiator_nonce
.ptr
,initiator_nonce
.len
);
223 /* second is responder */
224 memcpy(concatenated_nonces
.ptr
+ initiator_nonce
.len
,responder_nonce
.ptr
,responder_nonce
.len
);
226 this->logger
->log_chunk(this->logger
, RAW
, "Nonce data", &concatenated_nonces
);
229 /* status of set_key is not checked */
230 status
= this->prf
->set_key(this->prf
,concatenated_nonces
);
232 status
= this->prf
->allocate_bytes(this->prf
,dh_shared_secret
,&skeyseed
);
233 if (status
!= SUCCESS
)
235 allocator_free_chunk(&concatenated_nonces
);
236 this->logger
->log(this->logger
, ERROR
, "Fatal errror: Could not allocate bytes for skeyseed");
239 allocator_free_chunk(&concatenated_nonces
);
241 prf_plus_seed
.len
= (initiator_nonce
.len
+ responder_nonce
.len
+ 16);
242 prf_plus_seed
.ptr
= allocator_alloc(prf_plus_seed
.len
);
243 if (prf_plus_seed
.ptr
== NULL
)
245 this->logger
->log(this->logger
, ERROR
, "Fatal errror: Could not allocate memory for prf+ seed");
246 allocator_free_chunk(&skeyseed
);
250 /* first is initiator */
251 memcpy(prf_plus_seed
.ptr
,initiator_nonce
.ptr
,initiator_nonce
.len
);
252 /* second is responder */
253 memcpy(prf_plus_seed
.ptr
+ initiator_nonce
.len
,responder_nonce
.ptr
,responder_nonce
.len
);
254 /* third is initiator spi */
255 initiator_spi
= this->ike_sa_id
->get_initiator_spi(this->ike_sa_id
);
256 memcpy(prf_plus_seed
.ptr
+ initiator_nonce
.len
+ responder_nonce
.len
,&initiator_spi
,8);
257 /* fourth is responder spi */
258 responder_spi
= this->ike_sa_id
->get_responder_spi(this->ike_sa_id
);
259 memcpy(prf_plus_seed
.ptr
+ initiator_nonce
.len
+ responder_nonce
.len
+ 8,&responder_spi
,8);
261 this->logger
->log_chunk(this->logger
, PRIVATE
, "Keyseed", &skeyseed
);
262 this->logger
->log_chunk(this->logger
, PRIVATE
, "PRF+ Seed", &prf_plus_seed
);
264 this->logger
->log(this->logger
, CONTROL
| MOST
, "Set new key of prf object");
265 status
= this->prf
->set_key(this->prf
,skeyseed
);
266 allocator_free_chunk(&skeyseed
);
267 if (status
!= SUCCESS
)
269 this->logger
->log(this->logger
, ERROR
, "Fatal errror: Could not allocate memory for prf+ seed");
270 allocator_free_chunk(&prf_plus_seed
);
274 this->logger
->log(this->logger
, CONTROL
| MOST
, "Create new prf+ object");
275 prf_plus
= prf_plus_create(this->prf
, prf_plus_seed
);
276 allocator_free_chunk(&prf_plus_seed
);
277 if (prf_plus
== NULL
)
279 this->logger
->log(this->logger
, ERROR
, "Fatal errror: prf+ object could not be created");
283 prf_plus
->allocate_bytes(prf_plus
,100,&secrets_raw
);
285 this->logger
->log_chunk(this->logger
, PRIVATE
, "Secrets", &secrets_raw
);
287 allocator_free_chunk(&secrets_raw
);
289 prf_plus
->destroy(prf_plus
);
295 * @brief implements function resend_last_reply of protected_ike_sa_t
297 status_t
resend_last_reply (protected_ike_sa_t
*this)
302 status
= this->last_responded_message
->generate(this->last_responded_message
, &packet
);
303 if (status
!= SUCCESS
)
305 this->logger
->log(this->logger
, ERROR
, "Could not generate message to resent");
309 status
= global_send_queue
->add(global_send_queue
, packet
);
310 if (status
!= SUCCESS
)
312 this->logger
->log(this->logger
, ERROR
, "Could not add packet to send queue");
313 packet
->destroy(packet
);
319 status_t
create_delete_job (protected_ike_sa_t
*this)
324 this->logger
->log(this->logger
, CONTROL
| MORE
, "Going to create job to delete this IKE_SA");
326 delete_job
= (job_t
*) delete_ike_sa_job_create(this->ike_sa_id
);
327 if (delete_job
== NULL
)
329 this->logger
->log(this->logger
, ERROR
, "Job to delete IKE SA could not be created");
333 status
= global_job_queue
->add(global_job_queue
,delete_job
);
334 if (status
!= SUCCESS
)
336 this->logger
->log(this->logger
, ERROR
, "%s Job to delete IKE SA could not be added to job queue",mapping_find(status_m
,status
));
337 delete_job
->destroy_all(delete_job
);
344 * @brief implements function destroy of protected_ike_sa_t
346 static status_t
destroy (protected_ike_sa_t
*this)
349 this->logger
->log(this->logger
, CONTROL
| MORE
, "Going to destroy IKE_SA");
351 /* destroy child sa's */
352 this->logger
->log(this->logger
, CONTROL
| MOST
, "Destroy all child_sa's");
353 while (this->child_sas
->get_count(this->child_sas
) > 0)
356 if (this->child_sas
->remove_first(this->child_sas
,&child_sa
) != SUCCESS
)
360 /* destroy child sa */
362 this->child_sas
->destroy(this->child_sas
);
364 this->logger
->log(this->logger
, CONTROL
| MOST
, "Destroy secrets");
365 if (this->secrets
.d_key
.ptr
!= NULL
)
367 allocator_free(this->secrets
.d_key
.ptr
);
369 if (this->secrets
.ai_key
.ptr
!= NULL
)
371 allocator_free(this->secrets
.ai_key
.ptr
);
373 if (this->secrets
.ar_key
.ptr
!= NULL
)
375 allocator_free(this->secrets
.ar_key
.ptr
);
377 if (this->secrets
.ei_key
.ptr
!= NULL
)
379 allocator_free(this->secrets
.ei_key
.ptr
);
381 if (this->secrets
.er_key
.ptr
!= NULL
)
383 allocator_free(this->secrets
.er_key
.ptr
);
385 if (this->secrets
.pi_key
.ptr
!= NULL
)
387 allocator_free(this->secrets
.pi_key
.ptr
);
389 if (this->secrets
.pr_key
.ptr
!= NULL
)
391 allocator_free(this->secrets
.pr_key
.ptr
);
394 if ( this->crypter_initiator
!= NULL
)
396 this->logger
->log(this->logger
, CONTROL
| MOST
, "Destroy initiator crypter");
397 this->crypter_initiator
->destroy(this->crypter_initiator
);
400 if ( this->crypter_responder
!= NULL
)
402 this->logger
->log(this->logger
, CONTROL
| MOST
, "Destroy responder crypter");
403 this->crypter_responder
->destroy(this->crypter_responder
);
406 if ( this->signer_initiator
!= NULL
)
408 this->logger
->log(this->logger
, CONTROL
| MOST
, "Destroy initiator signer");
409 this->signer_initiator
->destroy(this->signer_initiator
);
412 if (this->signer_responder
!= NULL
)
414 this->logger
->log(this->logger
, CONTROL
| MOST
, "Destroy responder signer");
415 this->signer_responder
->destroy(this->signer_responder
);
418 if (this->prf
!= NULL
)
420 this->logger
->log(this->logger
, CONTROL
| MOST
, "Destroy prf");
421 this->prf
->destroy(this->prf
);
424 /* destroy ike_sa_id */
425 this->logger
->log(this->logger
, CONTROL
| MOST
, "Destroy assigned ike_sa_id");
426 this->ike_sa_id
->destroy(this->ike_sa_id
);
428 /* destroy stored requested message */
429 if (this->last_requested_message
!= NULL
)
431 this->logger
->log(this->logger
, CONTROL
| MOST
, "Destroy last requested message");
432 this->last_requested_message
->destroy(this->last_requested_message
);
435 /* destroy stored responded messages */
436 if (this->last_responded_message
!= NULL
)
438 this->logger
->log(this->logger
, CONTROL
| MOST
, "Destroy last responded message");
439 this->last_responded_message
->destroy(this->last_responded_message
);
442 this->logger
->log(this->logger
, CONTROL
| MOST
, "Destroy randomizer");
443 this->randomizer
->destroy(this->randomizer
);
445 if (this->me
.host
!= NULL
)
447 this->logger
->log(this->logger
, CONTROL
| MOST
, "Destroy host informations of me");
448 this->me
.host
->destroy(this->me
.host
);
451 if (this->other
.host
!= NULL
)
453 this->logger
->log(this->logger
, CONTROL
| MOST
, "Destroy host informations of other");
454 this->other
.host
->destroy(this->other
.host
);
457 this->logger
->log(this->logger
, CONTROL
| MOST
, "Destroy current state object");
458 this->current_state
->destroy(this->current_state
);
460 this->logger
->log(this->logger
, CONTROL
| MOST
, "Destroy logger of IKE_SA");
462 global_logger_manager
->destroy_logger(global_logger_manager
, this->logger
);
464 allocator_free(this);
469 * Described in Header
471 ike_sa_t
* ike_sa_create(ike_sa_id_t
*ike_sa_id
)
473 protected_ike_sa_t
*this = allocator_alloc_thing(protected_ike_sa_t
);
479 /* Public functions */
480 this->public.process_message
= (status_t(*)(ike_sa_t
*, message_t
*)) process_message
;
481 this->public.initialize_connection
= (status_t(*)(ike_sa_t
*, char*)) initialize_connection
;
482 this->public.get_id
= (ike_sa_id_t
*(*)(ike_sa_t
*)) get_id
;
483 this->public.destroy
= (status_t(*)(ike_sa_t
*))destroy
;
485 /* private functions */
486 this->build_message
= build_message
;
487 this->resend_last_reply
= resend_last_reply
;
488 this->create_delete_job
= create_delete_job
;
489 this->compute_secrets
= compute_secrets
;
491 /* initialize private fields */
492 this->logger
= global_logger_manager
->create_logger(global_logger_manager
, IKE_SA
, NULL
);
493 if (this->logger
== NULL
)
495 allocator_free(this);
498 if (ike_sa_id
->clone(ike_sa_id
,&(this->ike_sa_id
)) != SUCCESS
)
500 this->logger
->log(this->logger
, ERROR
, "Fatal error: Could not clone ike_sa_id");
501 global_logger_manager
->destroy_logger(global_logger_manager
,this->logger
);
502 allocator_free(this);
505 this->child_sas
= linked_list_create();
506 if (this->child_sas
== NULL
)
508 this->logger
->log(this->logger
, ERROR
, "Fatal error: Could not create list for child_sa's");
509 this->ike_sa_id
->destroy(this->ike_sa_id
);
510 global_logger_manager
->destroy_logger(global_logger_manager
,this->logger
);
511 allocator_free(this);
514 this->randomizer
= randomizer_create();
515 if (this->randomizer
== NULL
)
517 this->logger
->log(this->logger
, ERROR
, "Fatal error: Could not create list for child_sa's");
518 this->child_sas
->destroy(this->child_sas
);
519 this->ike_sa_id
->destroy(this->ike_sa_id
);
520 global_logger_manager
->destroy_logger(global_logger_manager
,this->logger
);
521 allocator_free(this);
524 this->me
.host
= NULL
;
525 this->other
.host
= NULL
;
526 this->last_requested_message
= NULL
;
527 this->last_responded_message
= NULL
;
528 this->message_id_out
= 0;
529 this->message_id_in
= 0;
530 this->secrets
.d_key
.ptr
= NULL
;
531 this->secrets
.d_key
.len
= 0;
532 this->secrets
.ai_key
.ptr
= NULL
;
533 this->secrets
.ai_key
.len
= 0;
534 this->secrets
.ar_key
.ptr
= NULL
;
535 this->secrets
.ar_key
.len
= 0;
536 this->secrets
.ei_key
.ptr
= NULL
;
537 this->secrets
.ei_key
.len
= 0;
538 this->secrets
.er_key
.ptr
= NULL
;
539 this->secrets
.er_key
.len
= 0;
540 this->secrets
.pi_key
.ptr
= NULL
;
541 this->secrets
.pi_key
.len
= 0;
542 this->secrets
.pr_key
.ptr
= NULL
;
543 this->secrets
.pr_key
.len
= 0;
544 this->crypter_initiator
= NULL
;
545 this->crypter_responder
= NULL
;
546 this->signer_initiator
= NULL
;
547 this->signer_responder
= NULL
;
553 /* at creation time, IKE_SA is in a initiator state */
554 if (ike_sa_id
->is_initiator(ike_sa_id
))
556 this->current_state
= (state_t
*) initiator_init_create(this);
560 this->current_state
= (state_t
*) responder_init_create(this);
563 if (this->current_state
== NULL
)
565 this->logger
->log(this->logger
, ERROR
, "Fatal error: Could not create state object");
566 this->child_sas
->destroy(this->child_sas
);
567 this->ike_sa_id
->destroy(this->ike_sa_id
);
568 global_logger_manager
->destroy_logger(global_logger_manager
,this->logger
);
569 this->randomizer
->destroy(this->randomizer
);
570 allocator_free(this);
574 return &(this->public);