(no commit message)
[strongswan.git] / Source / charon / sa / states / initiator_init.c
1 /**
2 * @file initiator_init.c
3 *
4 * @brief Start state of a IKE_SA as initiator
5 *
6 */
7
8 /*
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
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>.
16 *
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
20 * for more details.
21 */
22
23 #include "initiator_init.h"
24
25
26 #include <globals.h>
27 #include <sa/states/state.h>
28 #include <sa/states/ike_sa_init_requested.h>
29 #include <utils/allocator.h>
30 #include <transforms/diffie_hellman.h>
31 #include <encoding/payloads/sa_payload.h>
32 #include <encoding/payloads/ke_payload.h>
33 #include <encoding/payloads/nonce_payload.h>
34
35
36 /**
37 * Private data of a initiator_init_t object.
38 *
39 */
40 typedef struct private_initiator_init_s private_initiator_init_t;
41 struct private_initiator_init_s {
42 /**
43 * Methods of the state_t interface.
44 */
45 initiator_init_t public;
46
47 /**
48 * Assigned IKE_SA.
49 */
50 protected_ike_sa_t *ike_sa;
51
52 /**
53 * Diffie hellman object used to generate public DH value.
54 * This objet is passed to the next state of type ike_sa_init_requested_t.
55 */
56 diffie_hellman_t *diffie_hellman;
57
58 /**
59 * DH group number.
60 */
61 u_int16_t dh_group_number;
62
63 /**
64 * DH group priority used to get dh_group_number from configuration manager.
65 * This priority is passed to the next state of type ike_sa_init_requested_t.
66 */
67 u_int16_t dh_group_priority;
68
69 /**
70 * Sent nonce.
71 * This nonce is passed to the next state of type ike_sa_init_requested_t.
72 */
73 chunk_t sent_nonce;
74
75 /**
76 * Proposals used to initiate connection.
77 *
78 */
79 linked_list_t *proposals;
80
81 /**
82 * Logger used to log :-)
83 *
84 * Is logger of ike_sa!
85 */
86 logger_t *logger;
87
88 /**
89 * Builds the IKE_SA_INIT request message.
90 *
91 * @param this calling object
92 * @param message the created message will be stored at this location
93 * @return
94 * - SUCCESS
95 * - OUT_OF_RES
96 */
97 status_t (*build_ike_sa_init_request) (private_initiator_init_t *this, message_t **message);
98
99 /**
100 * Builds the SA payload for this state.
101 *
102 * @param this calling object
103 * @param payload The generated SA payload object of type ke_payload_t is
104 * stored at this location.
105 * @return
106 * - SUCCESS
107 * - OUT_OF_RES
108 */
109 status_t (*build_sa_payload) (private_initiator_init_t *this, payload_t **payload);
110
111 /**
112 * Builds the KE payload for this state.
113 *
114 * @param this calling object
115 * @param payload The generated KE payload object of type ke_payload_t is
116 * stored at this location.
117 * @return
118 * - SUCCESS
119 * - OUT_OF_RES
120 */
121 status_t (*build_ke_payload) (private_initiator_init_t *this, payload_t **payload);
122 /**
123 * Builds the NONCE payload for this state.
124 *
125 * @param this calling object
126 * @param payload The generated NONCE payload object of type ke_payload_t is
127 * stored at this location.
128 * @return
129 * - SUCCESS
130 * - OUT_OF_RES
131 */
132 status_t (*build_nonce_payload) (private_initiator_init_t *this, payload_t **payload);
133
134 /**
135 * Destroy function called internally of this class after state change succeeded.
136 *
137 * This destroy function does not destroy objects which were passed to the new state.
138 *
139 * @param this calling object
140 * @return SUCCESS in any case
141 */
142 status_t (*destroy_after_state_change) (private_initiator_init_t *this);
143 };
144
145 /**
146 * Implements function initiator_init_t.initiate_connection.
147 */
148 static status_t initiate_connection (private_initiator_init_t *this, char *name, state_t **new_state)
149 {
150 linked_list_iterator_t *proposal_iterator;
151 ike_sa_init_requested_t *next_state;
152 message_t *message;
153 packet_t *packet;
154 status_t status;
155
156 this->logger->log(this->logger, CONTROL, "Initializing connection %s",name);
157
158 status = global_configuration_manager->get_local_host(global_configuration_manager, name, &(this->ike_sa->me.host));
159 if (status != SUCCESS)
160 {
161 this->logger->log(this->logger, ERROR | MORE, "Could not retrieve local host configuration information for %s",name);
162 return INVALID_ARG;
163 }
164
165 status = global_configuration_manager->get_remote_host(global_configuration_manager, name, &(this->ike_sa->other.host));
166 if (status != SUCCESS)
167 {
168 this->logger->log(this->logger, ERROR | MORE, "Could not retrieve remote host configuration information for %s",name);
169 return INVALID_ARG;
170 }
171
172 status = global_configuration_manager->get_dh_group_number(global_configuration_manager, name, &(this->dh_group_number), this->dh_group_priority);
173 if (status != SUCCESS)
174 {
175 this->logger->log(this->logger, ERROR | MORE, "Could not retrieve DH group number configuration for %s",name);
176 return INVALID_ARG;
177 }
178
179 status = this->proposals->create_iterator(this->proposals, &proposal_iterator, FALSE);
180 if (status != SUCCESS)
181 {
182 this->logger->log(this->logger, ERROR, "Fatal error: Could not create iterator on list for proposals");
183 return status;
184 }
185
186 status = global_configuration_manager->get_proposals_for_host(global_configuration_manager, this->ike_sa->other.host, proposal_iterator);
187 /* not needed anymore */
188 proposal_iterator->destroy(proposal_iterator);
189 if (status != SUCCESS)
190 {
191 this->logger->log(this->logger, ERROR | MORE, "Could not retrieve Proposals for %s",name);
192 return status;
193 }
194
195 /* a diffie hellman object could allready exist caused by an failed initiate_connection call */
196 if (this->diffie_hellman == NULL)
197 {
198 this ->logger->log(this->logger, CONTROL|MOST, "create diffie hellman object");
199 this->diffie_hellman = diffie_hellman_create(this->dh_group_number);
200 }
201
202 if (this->diffie_hellman == NULL)
203 {
204 this->logger->log(this->logger, ERROR, "Object of type diffie_hellman_t could not be created!");
205 return FAILED;
206 }
207
208 if (this->sent_nonce.ptr != NULL)
209 {
210 this->logger->log(this->logger, ERROR, "Free existing sent nonce!");
211 allocator_free(this->sent_nonce.ptr);
212 this->sent_nonce = CHUNK_INITIALIZER;
213 }
214
215 this ->logger->log(this->logger, CONTROL|MOST, "Get pseudo random bytes for nonce");
216 if (this->ike_sa->randomizer->allocate_pseudo_random_bytes(this->ike_sa->randomizer, NONCE_SIZE, &(this->sent_nonce)) != SUCCESS)
217 {
218 this->logger->log(this->logger, ERROR, "Could not create nonce!");
219 return OUT_OF_RES;
220 }
221 this ->logger->log(this->logger, RAW|MOST, "Nonce",&(this->sent_nonce));
222
223
224
225 status = this->build_ike_sa_init_request (this,&message);
226 if (status != SUCCESS)
227 {
228 this->logger->log(this->logger, ERROR, "Fatal error: could not build IKE_SA_INIT request message");
229 return status;
230 }
231
232 /* generate packet */
233 this ->logger->log(this->logger, CONTROL|MOST, "generate packet from message");
234 status = message->generate(message, &packet);
235 if (status != SUCCESS)
236 {
237 this->logger->log(this->logger, ERROR, "Fatal error: could not generate packet from message");
238 message->destroy(message);
239 return status;
240 }
241
242 this ->logger->log(this->logger, CONTROL|MOST, "Add packet to global send queue");
243 status = global_send_queue->add(global_send_queue, packet);
244 if (status != SUCCESS)
245 {
246 this->logger->log(this->logger, ERROR, "Could not add packet to send queue");
247 packet->destroy(packet);
248 message->destroy(message);
249 return status;
250 }
251
252 /* state can now be changed */
253 this ->logger->log(this->logger, CONTROL|MOST, "Create next state object");
254 next_state = ike_sa_init_requested_create(this->ike_sa, this->dh_group_number, this->diffie_hellman, this->sent_nonce);
255
256 if (next_state == NULL)
257 {
258 this ->logger->log(this->logger, ERROR, "Fatal error: could not create next state object of type ike_sa_init_requested_t");
259 return FAILED;
260 }
261
262 if ( this->ike_sa->last_requested_message != NULL)
263 {
264 /* destroy message */
265 this ->logger->log(this->logger, CONTROL|MOST, "Destroy stored last requested message");
266 this->ike_sa->last_requested_message->destroy(this->ike_sa->last_requested_message);
267 }
268
269 /* message is set after state create */
270 this ->logger->log(this->logger, CONTROL|MOST, "replace last requested message with current one");
271 this->ike_sa->last_requested_message = message;
272
273 /* message counter can now be increased */
274 this ->logger->log(this->logger, CONTROL|MOST, "Increate message counter for outgoing messages");
275 this->ike_sa->message_id_out++;
276
277 *new_state = (state_t *) next_state;
278 /* state has NOW changed :-) */
279 this ->logger->log(this->logger, CONTROL|MORE, "Changed state of IKE_SA from %s to %s",mapping_find(ike_sa_state_m,INITIATOR_INIT),mapping_find(ike_sa_state_m,IKE_SA_INIT_REQUESTED) );
280
281 this ->logger->log(this->logger, CONTROL|MOST, "Destroy old sate object");
282 this->destroy_after_state_change(this);
283
284 return SUCCESS;
285 }
286
287 /**
288 * implements private_initiator_init_t.build_ike_sa_init_request
289 */
290 static status_t build_ike_sa_init_request (private_initiator_init_t *this, message_t **request)
291 {
292 status_t status;
293 payload_t *payload;
294 message_t *message;
295
296 /* going to build message */
297 this ->logger->log(this->logger, CONTROL|MOST, "Going to build message");
298 status = this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, TRUE, &message);
299 if (status != SUCCESS)
300 {
301 this->logger->log(this->logger, ERROR, "Could not build empty message");
302 return status;
303 }
304
305 /* build SA payload */
306 status = this->build_sa_payload(this, &payload);
307 if (status != SUCCESS)
308 {
309 this->logger->log(this->logger, ERROR, "Could not build SA payload");
310 message->destroy(message);
311 return status;
312 }
313
314 this ->logger->log(this->logger, CONTROL|MOST, "add SA payload to message");
315 status = message->add_payload(message, payload);
316 if (status != SUCCESS)
317 {
318 this->logger->log(this->logger, ERROR, "Could not add SA payload to message");
319 payload->destroy(payload);
320 message->destroy(message);
321 return status;
322 }
323
324 /* build KE payload */
325 status = this->build_ke_payload(this, &payload);
326 if (status != SUCCESS)
327 {
328 this->logger->log(this->logger, ERROR, "Could not build KE payload");
329 message->destroy(message);
330 return status;
331 }
332
333 this ->logger->log(this->logger, CONTROL|MOST, "add KE payload to message");
334 status = message->add_payload(message, payload);
335 if (status != SUCCESS)
336 {
337 this->logger->log(this->logger, ERROR, "Could not add KE payload to message");
338 payload->destroy(payload);
339 message->destroy(message);
340 return status;
341 }
342
343 /* build Nonce payload */
344 status = this->build_nonce_payload(this, &payload);
345 if (status != SUCCESS)
346 {
347 this->logger->log(this->logger, ERROR, "Could not build NONCE payload");
348 message->destroy(message);
349 return status;
350 }
351
352 this ->logger->log(this->logger, CONTROL|MOST, "add nonce payload to message");
353 status = message->add_payload(message, payload);
354 if (status != SUCCESS)
355 {
356 this->logger->log(this->logger, ERROR, "Could not add nonce payload to message");
357 payload->destroy(payload);
358 message->destroy(message);
359 return status;
360 }
361
362 *request = message;
363 return SUCCESS;
364 }
365
366 /**
367 * implements private_initiator_init_t.build_sa_payload
368 */
369 static status_t build_sa_payload(private_initiator_init_t *this, payload_t **payload)
370 {
371 sa_payload_t* sa_payload;
372 linked_list_iterator_t *proposal_iterator;
373 status_t status;
374
375 /* SA payload takes proposals from this->ike_sa_init_data.proposals and writes them to the created sa_payload */
376
377 this->logger->log(this->logger, CONTROL|MORE, "building sa payload");
378 status = this->proposals->create_iterator(this->proposals, &proposal_iterator, FALSE);
379 if (status != SUCCESS)
380 {
381 this->logger->log(this->logger, ERROR, "Fatal error: Could not create iterator on list for proposals");
382 return status;
383 }
384
385 sa_payload = sa_payload_create();
386 if (sa_payload == NULL)
387 {
388 this->logger->log(this->logger, ERROR, "Fatal error: Could not create SA payload object");
389 return OUT_OF_RES;
390 }
391
392 while (proposal_iterator->has_next(proposal_iterator))
393 {
394 proposal_substructure_t *current_proposal;
395 proposal_substructure_t *current_proposal_clone;
396 status = proposal_iterator->current(proposal_iterator,(void **) &current_proposal);
397 if (status != SUCCESS)
398 {
399 this->logger->log(this->logger, ERROR, "Could not get current proposal needed to copy");
400 proposal_iterator->destroy(proposal_iterator);
401 sa_payload->destroy(sa_payload);
402 return status;
403 }
404 status = current_proposal->clone(current_proposal,&current_proposal_clone);
405 if (status != SUCCESS)
406 {
407 this->logger->log(this->logger, ERROR, "Could not clone current proposal");
408 proposal_iterator->destroy(proposal_iterator);
409 sa_payload->destroy(sa_payload);
410 return status;
411 }
412
413 status = sa_payload->add_proposal_substructure(sa_payload,current_proposal_clone);
414 if (status != SUCCESS)
415 {
416 this->logger->log(this->logger, ERROR, "Could not add cloned proposal to SA payload");
417 proposal_iterator->destroy(proposal_iterator);
418 sa_payload->destroy(sa_payload);
419 return status;
420 }
421
422 }
423 proposal_iterator->destroy(proposal_iterator);
424
425 this->logger->log(this->logger, CONTROL|MORE, "sa payload builded");
426
427 *payload = (payload_t *) sa_payload;
428 return SUCCESS;
429 }
430
431 /**
432 * implements private_initiator_init_t.build_ke_payload
433 */
434 static status_t build_ke_payload(private_initiator_init_t *this, payload_t **payload)
435 {
436 ke_payload_t *ke_payload;
437 chunk_t key_data;
438 status_t status;
439
440 this->logger->log(this->logger, CONTROL|MORE, "building ke payload");
441
442
443 this ->logger->log(this->logger, CONTROL|MORE, "get public dh value to send in ke payload");
444 status = this->diffie_hellman->get_my_public_value(this->diffie_hellman,&key_data);
445 if (status != SUCCESS)
446 {
447 this->logger->log(this->logger, ERROR, "Could not get my DH public value");
448 return status;
449 }
450
451 ke_payload = ke_payload_create();
452 if (ke_payload == NULL)
453 {
454 this->logger->log(this->logger, ERROR, "Could not create KE payload");
455 allocator_free_chunk(key_data);
456 return OUT_OF_RES;
457 }
458 ke_payload->set_dh_group_number(ke_payload, this->dh_group_number);
459 if (ke_payload->set_key_exchange_data(ke_payload, key_data) != SUCCESS)
460 {
461 this->logger->log(this->logger, ERROR, "Could not set key exchange data of KE payload");
462 ke_payload->destroy(ke_payload);
463 allocator_free_chunk(key_data);
464 return OUT_OF_RES;
465 }
466 allocator_free_chunk(key_data);
467
468 this->logger->log(this->logger, CONTROL|MORE, "ke payload builded");
469
470 *payload = (payload_t *) ke_payload;
471 return SUCCESS;
472 }
473
474 /**
475 * implements private_initiator_init_t.build_nonce_payload
476 */
477 static status_t build_nonce_payload(private_initiator_init_t *this, payload_t **payload)
478 {
479 nonce_payload_t *nonce_payload;
480 status_t status;
481
482 this->logger->log(this->logger, CONTROL|MORE, "building nonce payload");
483
484 nonce_payload = nonce_payload_create();
485 if (nonce_payload == NULL)
486 {
487 this->logger->log(this->logger, ERROR, "Fatal error: could not create nonce payload object");
488 return OUT_OF_RES;
489 }
490
491 status = nonce_payload->set_nonce(nonce_payload, this->sent_nonce);
492
493 if (status != SUCCESS)
494 {
495 this->logger->log(this->logger, ERROR, "Fatal error: could not set nonce data of payload");
496 nonce_payload->destroy(nonce_payload);
497 return status;
498 }
499
500 *payload = (payload_t *) nonce_payload;
501
502 this->logger->log(this->logger, CONTROL|MORE, "nonce payload builded");
503
504 return SUCCESS;
505 }
506
507 /**
508 * Implements state_t.get_state
509 */
510 static status_t process_message(private_initiator_init_t *this, message_t *message, state_t **new_state)
511 {
512 *new_state = (state_t *) this;
513 this->logger->log(this->logger, ERROR|MORE, "In state INITIATOR_INIT no message is processed");
514 return FAILED;
515 }
516
517 /**
518 * Implements state_t.get_state
519 */
520 static ike_sa_state_t get_state(private_initiator_init_t *this)
521 {
522 return INITIATOR_INIT;
523 }
524
525 /**
526 * Implements state_t.get_state
527 */
528 static status_t destroy(private_initiator_init_t *this)
529 {
530 this->logger->log(this->logger, CONTROL | MORE, "Going to destroy initiator_init_t state object");
531
532 /* destroy stored proposal */
533 this->logger->log(this->logger, CONTROL | MOST, "Destroy stored proposals");
534 while (this->proposals->get_count(this->proposals) > 0)
535 {
536 proposal_substructure_t *current_proposal;
537 this->proposals->remove_first(this->proposals,(void **)&current_proposal);
538 current_proposal->destroy(current_proposal);
539 }
540 this->proposals->destroy(this->proposals);
541
542 /* destroy diffie hellman object */
543 if (this->diffie_hellman != NULL)
544 {
545 this->logger->log(this->logger, CONTROL | MOST, "Destroy diffie_hellman_t object");
546 this->diffie_hellman->destroy(this->diffie_hellman);
547 }
548 if (this->sent_nonce.ptr != NULL)
549 {
550 this->logger->log(this->logger, CONTROL | MOST, "Free memory of sent nonce");
551 allocator_free(this->sent_nonce.ptr);
552 }
553
554 allocator_free(this);
555 return SUCCESS;
556 }
557
558 /**
559 * Implements private_initiator_init_t.destroy_after_state_change
560 */
561 static status_t destroy_after_state_change (private_initiator_init_t *this)
562 {
563 this->logger->log(this->logger, CONTROL | MORE, "Going to destroy initiator_init_t state object");
564
565 /* destroy stored proposal */
566 this->logger->log(this->logger, CONTROL | MOST, "Destroy stored proposals");
567 while (this->proposals->get_count(this->proposals) > 0)
568 {
569 proposal_substructure_t *current_proposal;
570 this->proposals->remove_first(this->proposals,(void **)&current_proposal);
571 current_proposal->destroy(current_proposal);
572 }
573 this->proposals->destroy(this->proposals);
574 allocator_free(this);
575 return SUCCESS;
576 }
577
578 /*
579 * Described in header.
580 */
581 initiator_init_t *initiator_init_create(protected_ike_sa_t *ike_sa)
582 {
583 private_initiator_init_t *this = allocator_alloc_thing(private_initiator_init_t);
584
585 if (this == NULL)
586 {
587 return NULL;
588 }
589
590 /* interface functions */
591 this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *,state_t **)) process_message;
592 this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
593 this->public.state_interface.destroy = (status_t (*) (state_t *)) destroy;
594
595 /* public functions */
596 this->public.initiate_connection = (status_t (*)(initiator_init_t *, char *, state_t **)) initiate_connection;
597
598 /* private functions */
599 this->destroy_after_state_change = destroy_after_state_change;
600 this->build_ike_sa_init_request = build_ike_sa_init_request;
601 this->build_nonce_payload = build_nonce_payload;
602 this->build_sa_payload = build_sa_payload;
603 this->build_ke_payload = build_ke_payload;
604
605 /* private data */
606 this->ike_sa = ike_sa;
607 this->dh_group_priority = 1;
608 this->logger = this->ike_sa->logger;
609 this->proposals = linked_list_create();
610 this->sent_nonce = CHUNK_INITIALIZER;
611 if (this->proposals == NULL)
612 {
613 allocator_free(this);
614 return NULL;
615 }
616
617 return &(this->public);
618 }