- retransmitting of requests implemented
[strongswan.git] / Source / charon / sa / states / ike_sa_init_requested.c
1 /**
2 * @file ike_sa_init_requested.c
3 *
4 * @brief Implementation of ike_sa_init_requested_t.
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 "ike_sa_init_requested.h"
24
25 #include <daemon.h>
26 #include <utils/allocator.h>
27 #include <encoding/payloads/sa_payload.h>
28 #include <encoding/payloads/ke_payload.h>
29 #include <encoding/payloads/nonce_payload.h>
30 #include <encoding/payloads/notify_payload.h>
31 #include <encoding/payloads/id_payload.h>
32 #include <encoding/payloads/auth_payload.h>
33 #include <encoding/payloads/ts_payload.h>
34 #include <transforms/diffie_hellman.h>
35 #include <sa/states/ike_auth_requested.h>
36 #include <sa/states/initiator_init.h>
37
38
39 typedef struct private_ike_sa_init_requested_t private_ike_sa_init_requested_t;
40
41 /**
42 * Private data of a ike_sa_init_requested_t object.
43 *
44 */
45 struct private_ike_sa_init_requested_t {
46 /**
47 * methods of the state_t interface
48 */
49 ike_sa_init_requested_t public;
50
51 /**
52 * Assigned IKE_SA
53 */
54 protected_ike_sa_t *ike_sa;
55
56 /**
57 * Diffie Hellman object used to compute shared secret
58 */
59 diffie_hellman_t *diffie_hellman;
60
61 /**
62 * Shared secret of successful exchange
63 */
64 chunk_t shared_secret;
65
66 /**
67 * Sent nonce value
68 */
69 chunk_t sent_nonce;
70
71 /**
72 * Received nonce
73 */
74 chunk_t received_nonce;
75
76 /**
77 * DH group priority used to get dh_group_number from configuration manager.
78 *
79 * Currently unused but usable if informational messages of unsupported dh group number are processed.
80 */
81 u_int16_t dh_group_priority;
82
83 /**
84 * Logger used to log data
85 *
86 * Is logger of ike_sa!
87 */
88 logger_t *logger;
89
90 /**
91 * Builds the IKE_SA_AUTH request message.
92 *
93 * @param this calling object
94 * @param message the created message will be stored at this location
95 */
96 void (*build_ike_auth_request) (private_ike_sa_init_requested_t *this, message_t **message);
97
98 /**
99 * Builds the id payload for this state.
100 *
101 * @param this calling object
102 * @param payload The generated payload object of type id_payload_t is
103 * stored at this location.
104 */
105 void (*build_id_payload) (private_ike_sa_init_requested_t *this, payload_t **payload);
106
107 /**
108 * Builds the id payload for this state.
109 *
110 * @param this calling object
111 * @param payload The generated payload object of type auth_payload_t is
112 * stored at this location.
113 */
114 void (*build_auth_payload) (private_ike_sa_init_requested_t *this, payload_t **payload);
115
116 /**
117 * Builds the SA payload for this state.
118 *
119 * @param this calling object
120 * @param payload The generated payload object of type sa_payload_t is
121 * stored at this location.
122 */
123 void (*build_sa_payload) (private_ike_sa_init_requested_t *this, payload_t **payload);
124
125 /**
126 * Builds the TSi payload for this state.
127 *
128 * @param this calling object
129 * @param payload The generated payload object of type ts_payload_t is
130 * stored at this location.
131 */
132 void (*build_tsi_payload) (private_ike_sa_init_requested_t *this, payload_t **payload);
133
134 /**
135 * Builds the TSr payload for this state.
136 *
137 * @param this calling object
138 * @param payload The generated payload object of type ts_payload_t is
139 * stored at this location.
140 */
141 void (*build_tsr_payload) (private_ike_sa_init_requested_t *this, payload_t **payload);
142
143 /**
144 * Destroy function called internally of this class after state change succeeded.
145 *
146 * This destroy function does not destroy objects which were passed to the new state.
147 *
148 * @param this calling object
149 */
150 void (*destroy_after_state_change) (private_ike_sa_init_requested_t *this);
151 };
152
153 /**
154 * Implements state_t.get_state
155 */
156 static status_t process_message(private_ike_sa_init_requested_t *this, message_t *ike_sa_init_reply)
157 {
158 ike_auth_requested_t *next_state;
159 exchange_type_t exchange_type;
160 init_config_t *init_config;
161 u_int64_t responder_spi;
162 ike_sa_id_t *ike_sa_id;
163 iterator_t *payloads;
164 message_t *request;
165 status_t status;
166
167 /*
168 * In this state a reply message of type IKE_SA_INIT is expected:
169 *
170 * <-- HDR, SAr1, KEr, Nr, [CERTREQ]
171 * or
172 * <-- HDR, N
173 */
174 exchange_type = ike_sa_init_reply->get_exchange_type(ike_sa_init_reply);
175 if (exchange_type != IKE_SA_INIT)
176 {
177 this->logger->log(this->logger, ERROR | MORE, "Message of type %s not supported in state ike_sa_init_requested",mapping_find(exchange_type_m,exchange_type));
178 return FAILED;
179 }
180
181 if (ike_sa_init_reply->get_request(ike_sa_init_reply))
182 {
183 this->logger->log(this->logger, ERROR | MORE, "Only responses of type IKE_SA_INIT supported in state ike_sa_init_requested");
184 return FAILED;
185 }
186
187 /* parse incoming message */
188 status = ike_sa_init_reply->parse_body(ike_sa_init_reply, NULL, NULL);
189 if (status != SUCCESS)
190 {
191 this->logger->log(this->logger, ERROR | MORE, "Parsing of body returned error: %s",mapping_find(status_m,status));
192 return status;
193 }
194
195 /* get configuration */
196 init_config = this->ike_sa->get_init_config(this->ike_sa);
197
198
199 if (responder_spi == 0)
200 {
201 this->logger->log(this->logger, ERROR | MORE, "Responder SPI still zero");
202 return FAILED;
203 }
204 /* because I am original initiator i have to update the responder SPI to the new one */
205 responder_spi = ike_sa_init_reply->get_responder_spi(ike_sa_init_reply);
206 ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public));
207 ike_sa_id->set_responder_spi(ike_sa_id,responder_spi);
208
209 /* Iterate over all payloads.
210 *
211 * The message is allready checked for the right payload types.
212 */
213 payloads = ike_sa_init_reply->get_payload_iterator(ike_sa_init_reply);
214 while (payloads->has_next(payloads))
215 {
216 payload_t *payload;
217 payloads->current(payloads, (void**)&payload);
218
219 this->logger->log(this->logger, CONTROL|MORE, "Processing payload %s", mapping_find(payload_type_m, payload->get_type(payload)));
220 switch (payload->get_type(payload))
221 {
222 case NOTIFY:
223 {
224 notify_payload_t *notify_payload = (notify_payload_t *) payload;
225
226
227 this->logger->log(this->logger, CONTROL|MORE, "Process notify type %s for protocol %s",
228 mapping_find(notify_message_type_m, notify_payload->get_notify_message_type(notify_payload)),
229 mapping_find(protocol_id_m, notify_payload->get_protocol_id(notify_payload)));
230
231 if (notify_payload->get_protocol_id(notify_payload) != IKE)
232 {
233 this->logger->log(this->logger, ERROR | MORE, "Notify reply not for IKE protocol.");
234 payloads->destroy(payloads);
235 return FAILED;
236 }
237 switch (notify_payload->get_notify_message_type(notify_payload))
238 {
239 case NO_PROPOSAL_CHOSEN:
240 {
241 this->logger->log(this->logger, ERROR, "Peer didn't choose a proposal!!!");
242 payloads->destroy(payloads);
243 return DELETE_ME;
244 }
245 case INVALID_KE_PAYLOAD:
246 {
247 initiator_init_t *initiator_init_state;
248 u_int16_t new_dh_group_priority;
249
250 this->logger->log(this->logger, ERROR, "Selected DH group is not the one in the proposal selected by the responder!");
251 payloads->destroy(payloads);
252 /* Going to change state back to initiator_init_t */
253 this->logger->log(this->logger, CONTROL|MOST, "Create next state object");
254 initiator_init_state = initiator_init_create(this->ike_sa);
255
256 /* buffer of sent and received messages has to get reseted */
257 this->ike_sa->reset_message_buffers(this->ike_sa);
258
259 /* state can now be changed */
260 this->ike_sa->set_new_state(this->ike_sa,(state_t *) initiator_init_state);
261
262 /* state has NOW changed :-) */
263 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) );
264
265 this->logger->log(this->logger, CONTROL|MOST, "Destroy old sate object");
266 this->logger->log(this->logger, CONTROL|MOST, "Going to retry initialization of connection");
267 new_dh_group_priority = this->dh_group_priority + 1;
268
269 this->public.state_interface.destroy(&(this->public.state_interface));
270 return (initiator_init_state->retry_initiate_connection (initiator_init_state,new_dh_group_priority));
271 }
272 default:
273 {
274 /*
275 * If an unrecognized Notify type is received, the IKE_SA gets destroyed.
276 *
277 */
278
279 this->logger->log(this->logger, ERROR, "Notify type %s not recognized in state ike_sa_init_requested.",
280 mapping_find(notify_message_type_m,notify_payload->get_notify_message_type(notify_payload)));
281 payloads->destroy(payloads);
282 return DELETE_ME;
283 }
284 }
285
286 /**
287 * TODO check for notify of type
288 *
289 * and change to state INITIATOR_INIT;
290 *
291 * call destroy after state change not destroy_after_state_change!!!
292 */
293 }
294 case SECURITY_ASSOCIATION:
295 {
296 sa_payload_t *sa_payload = (sa_payload_t*)payload;
297 ike_proposal_t *ike_proposals;
298 ike_proposal_t selected_proposal;
299 size_t proposal_count;
300
301
302 /* get the list of selected proposals */
303 status = sa_payload->get_ike_proposals (sa_payload, &ike_proposals,&proposal_count);
304 if (status != SUCCESS)
305 {
306 this->logger->log(this->logger, ERROR | MORE, "SA payload does not contain IKE proposals");
307 payloads->destroy(payloads);
308 return status;
309 }
310 /* the peer has to select only one proposal */
311 if (proposal_count != 1)
312 {
313 this->logger->log(this->logger, ERROR | MORE, "More then 1 proposal (%d) selected!",proposal_count);
314 allocator_free(ike_proposals);
315 payloads->destroy(payloads);
316 return status;
317 }
318
319 /* now let the configuration-manager check the selected proposals*/
320 this->logger->log(this->logger, CONTROL | MOST, "Check selected proposal");
321 status = init_config->select_proposal (init_config,ike_proposals,1,&selected_proposal);
322 allocator_free(ike_proposals);
323 if (status != SUCCESS)
324 {
325 this->logger->log(this->logger, ERROR | MORE, "Selected proposal not a suggested one! Peer is trying to trick me!");
326 payloads->destroy(payloads);
327 return status;
328 }
329
330 status = this->ike_sa->create_transforms_from_proposal(this->ike_sa,&selected_proposal);
331 if (status != SUCCESS)
332 {
333 this->logger->log(this->logger, ERROR | MORE, "Transform objects could not be created from selected proposal");
334 payloads->destroy(payloads);
335 return status;
336 }
337 /* ok, we have what we need for sa_payload */
338 break;
339 }
340 case KEY_EXCHANGE:
341 {
342 ke_payload_t *ke_payload = (ke_payload_t*)payload;
343 this->diffie_hellman->set_other_public_value(this->diffie_hellman, ke_payload->get_key_exchange_data(ke_payload));
344 /* shared secret is computed AFTER processing of all payloads... */
345 break;
346 }
347 case NONCE:
348 {
349 nonce_payload_t *nonce_payload = (nonce_payload_t*)payload;
350
351 allocator_free(this->received_nonce.ptr);
352
353 this->received_nonce = CHUNK_INITIALIZER;
354
355 nonce_payload->get_nonce(nonce_payload, &(this->received_nonce));
356 break;
357 }
358 default:
359 {
360 this->logger->log(this->logger, ERROR, "Payload type %s not supported in state ike_sa_init_requested!", mapping_find(payload_type_m, payload->get_type(payload)));
361 payloads->destroy(payloads);
362 return FAILED;
363 }
364
365 }
366
367 }
368 payloads->destroy(payloads);
369
370 allocator_free(this->shared_secret.ptr);
371 this->shared_secret = CHUNK_INITIALIZER;
372
373 /* store shared secret
374 * status of dh objectt does not have to get checked cause other key is set
375 */
376 this->logger->log(this->logger, CONTROL | MOST, "Retrieve shared secret and store it");
377 status = this->diffie_hellman->get_shared_secret(this->diffie_hellman, &(this->shared_secret));
378 this->logger->log_chunk(this->logger, PRIVATE, "Shared secret", &this->shared_secret);
379
380 this->logger->log(this->logger, CONTROL | MOST, "Going to derive all secrets from shared secret");
381 this->ike_sa->compute_secrets(this->ike_sa,this->shared_secret,this->sent_nonce, this->received_nonce);
382
383 /* build the complete IKE_AUTH request */
384 this->build_ike_auth_request (this,&request);
385
386 /* message can now be sent (must not be destroyed) */
387 status = this->ike_sa->send_request(this->ike_sa, request);
388 if (status != SUCCESS)
389 {
390 this->logger->log(this->logger, ERROR, "Could not send request message");
391 request->destroy(request);
392 return DELETE_ME;
393 }
394 this->ike_sa->set_last_replied_message_id(this->ike_sa,request->get_message_id(request));
395
396 /* state can now be changed */
397 this->logger->log(this->logger, CONTROL|MOST, "Create next state object");
398 next_state = ike_auth_requested_create(this->ike_sa);
399
400 /* state can now be changed */
401 this->ike_sa->set_new_state(this->ike_sa,(state_t *) next_state);
402
403 /* state has NOW changed :-) */
404 this->logger->log(this->logger, CONTROL|MORE, "Changed state of IKE_SA from %s to %s", mapping_find(ike_sa_state_m,IKE_SA_INIT_REQUESTED),mapping_find(ike_sa_state_m,IKE_AUTH_REQUESTED) );
405
406 this->logger->log(this->logger, CONTROL|MOST, "Destroy old sate object");
407 this->destroy_after_state_change(this);
408 return SUCCESS;
409 }
410
411 /**
412 * implements private_ike_sa_init_requested_t.build_ike_auth_request
413 */
414 static void build_ike_auth_request (private_ike_sa_init_requested_t *this, message_t **request)
415 {
416 payload_t *payload;
417 message_t *message;
418
419 /* going to build message */
420 this->logger->log(this->logger, CONTROL|MOST, "Going to build empty message");
421 this->ike_sa->build_message(this->ike_sa, IKE_AUTH, TRUE, &message);
422
423 /* build id payload */
424 this->build_id_payload(this, &payload);
425 this->logger->log(this->logger, CONTROL|MOST, "add ID payload to message");
426 message->add_payload(message, payload);
427
428 /* build auth payload */
429 this->build_auth_payload(this, &payload);
430 this->logger->log(this->logger, CONTROL|MOST, "add AUTH payload to message");
431 message->add_payload(message, payload);
432
433 /* build sa payload */
434 this->build_sa_payload(this, &payload);
435 this->logger->log(this->logger, CONTROL|MOST, "add SA payload to message");
436 message->add_payload(message, payload);
437
438 /* build tsi payload */
439 this->build_tsi_payload(this, &payload);
440 this->logger->log(this->logger, CONTROL|MOST, "add TSi payload to message");
441 message->add_payload(message, payload);
442
443 /* build tsr payload */
444 this->build_tsr_payload(this, &payload);
445 this->logger->log(this->logger, CONTROL|MOST, "add TSr payload to message");
446 message->add_payload(message, payload);
447
448 *request = message;
449 }
450
451 /**
452 * Implementation of private_ike_sa_init_requested_t.build_id_payload.
453 */
454 static void build_id_payload (private_ike_sa_init_requested_t *this, payload_t **payload)
455 {
456 sa_config_t *sa_config;
457 id_payload_t *id_payload;
458 identification_t *identification;
459
460 sa_config = this->ike_sa->get_sa_config(this->ike_sa);
461 /* identification_t object gets NOT cloned here */
462 identification = sa_config->get_my_id(sa_config);
463 id_payload = id_payload_create_from_identification(TRUE,identification);
464
465 *payload = (payload_t *) id_payload;
466 }
467
468 /**
469 * Implementation of private_ike_sa_init_requested_t.build_auth_payload.
470 */
471 static void build_auth_payload (private_ike_sa_init_requested_t *this, payload_t **payload)
472 {
473 auth_payload_t *auth_payload;
474 sa_config_t *sa_config;
475
476 sa_config = this->ike_sa->get_sa_config(this->ike_sa);
477 auth_payload = auth_payload_create();
478 auth_payload->set_auth_method(auth_payload,sa_config->get_auth_method(sa_config));
479 /*
480 * TODO generate AUTH DATA
481 */
482
483 *payload = (payload_t *) auth_payload;
484 }
485
486 /**
487 * Implementation of private_ike_sa_init_requested_t.build_sa_payload.
488 */
489 static void build_sa_payload (private_ike_sa_init_requested_t *this, payload_t **payload)
490 {
491 child_proposal_t *proposals;
492 sa_payload_t *sa_payload;
493 sa_config_t *sa_config;
494 size_t proposal_count;
495 /*
496 * TODO: get SPIs from kernel
497 */
498 u_int8_t esp_spi[4] = {0x01,0x01,0x01,0x01};
499 u_int8_t ah_spi[4] = {0x01,0x01,0x01,0x01};
500
501 sa_config = this->ike_sa->get_sa_config(this->ike_sa);
502 proposal_count = sa_config->get_proposals(sa_config,ah_spi,esp_spi,&proposals);
503 sa_payload = sa_payload_create_from_child_proposals(proposals, proposal_count);
504 allocator_free(proposals);
505
506 *payload = (payload_t *) sa_payload;
507 }
508
509 /**
510 * Implementation of private_ike_sa_init_requested_t.build_tsi_payload.
511 */
512 static void build_tsi_payload (private_ike_sa_init_requested_t *this, payload_t **payload)
513 {
514 traffic_selector_t **traffic_selectors;
515 size_t traffic_selectors_count;
516 ts_payload_t *ts_payload;
517 sa_config_t *sa_config;
518
519 sa_config = this->ike_sa->get_sa_config(this->ike_sa);
520 traffic_selectors_count = sa_config->get_traffic_selectors_initiator(sa_config,&traffic_selectors);
521 ts_payload = ts_payload_create_from_traffic_selectors(TRUE,traffic_selectors, traffic_selectors_count);
522
523 /* cleanup traffic selectors */
524 while(traffic_selectors_count--)
525 {
526 traffic_selector_t *ts = *traffic_selectors + traffic_selectors_count;
527 ts->destroy(ts);
528 }
529 allocator_free(traffic_selectors);
530
531 *payload = (payload_t *) ts_payload;
532 }
533
534 /**
535 * Implementation of private_ike_sa_init_requested_t.build_tsr_payload.
536 */
537 static void build_tsr_payload (private_ike_sa_init_requested_t *this, payload_t **payload)
538 {
539 traffic_selector_t **traffic_selectors;
540 size_t traffic_selectors_count;
541 ts_payload_t *ts_payload;
542 sa_config_t *sa_config;
543
544 sa_config = this->ike_sa->get_sa_config(this->ike_sa);
545 traffic_selectors_count = sa_config->get_traffic_selectors_responder(sa_config,&traffic_selectors);
546 ts_payload = ts_payload_create_from_traffic_selectors(FALSE,traffic_selectors, traffic_selectors_count);
547
548 /* cleanup traffic selectors */
549 while(traffic_selectors_count--)
550 {
551 traffic_selector_t *ts = *traffic_selectors + traffic_selectors_count;
552 ts->destroy(ts);
553 }
554 allocator_free(traffic_selectors);
555
556 *payload = (payload_t *) ts_payload;
557 }
558
559
560 /**
561 * Implements state_t.get_state
562 */
563 static ike_sa_state_t get_state(private_ike_sa_init_requested_t *this)
564 {
565 return IKE_SA_INIT_REQUESTED;
566 }
567
568 /**
569 * Implements private_ike_sa_init_requested_t.destroy_after_state_change
570 */
571 static void destroy_after_state_change (private_ike_sa_init_requested_t *this)
572 {
573 this->logger->log(this->logger, CONTROL | MORE, "Going to destroy state of type ike_sa_init_requested_t after state change.");
574
575 this->logger->log(this->logger, CONTROL | MOST, "Destroy diffie hellman object");
576 this->diffie_hellman->destroy(this->diffie_hellman);
577 this->logger->log(this->logger, CONTROL | MOST, "Destroy sent nonce");
578 allocator_free(this->sent_nonce.ptr);
579 this->logger->log(this->logger, CONTROL | MOST, "Destroy received nonce");
580 allocator_free(this->received_nonce.ptr);
581 this->logger->log(this->logger, CONTROL | MOST, "Destroy shared secret (secrets allready derived)");
582 allocator_free_chunk(&(this->shared_secret));
583 this->logger->log(this->logger, CONTROL | MOST, "Destroy object itself");
584 allocator_free(this);
585 }
586
587 /**
588 * Implements state_t.get_state
589 */
590 static void destroy(private_ike_sa_init_requested_t *this)
591 {
592 this->logger->log(this->logger, CONTROL | MORE, "Going to destroy state of type ike_sa_init_requested_t");
593
594 this->logger->log(this->logger, CONTROL | MOST, "Destroy diffie hellman object");
595 this->diffie_hellman->destroy(this->diffie_hellman);
596 this->logger->log(this->logger, CONTROL | MOST, "Destroy sent nonce");
597 allocator_free(this->sent_nonce.ptr);
598 this->logger->log(this->logger, CONTROL | MOST, "Destroy received nonce");
599 allocator_free(this->received_nonce.ptr);
600 this->logger->log(this->logger, CONTROL | MOST, "Destroy shared secret (secrets allready derived)");
601 allocator_free_chunk(&(this->shared_secret));
602 this->logger->log(this->logger, CONTROL | MOST, "Destroy object itself");
603 allocator_free(this);
604 }
605
606 /*
607 * Described in header.
608 */
609 ike_sa_init_requested_t *ike_sa_init_requested_create(protected_ike_sa_t *ike_sa, u_int16_t dh_group_priority, diffie_hellman_t *diffie_hellman, chunk_t sent_nonce)
610 {
611 private_ike_sa_init_requested_t *this = allocator_alloc_thing(private_ike_sa_init_requested_t);
612
613 /* interface functions */
614 this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
615 this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
616 this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
617
618 /* private functions */
619 this->build_ike_auth_request = build_ike_auth_request;
620 this->build_id_payload = build_id_payload;
621 this->build_auth_payload = build_auth_payload;
622 this->build_sa_payload = build_sa_payload;
623 this->build_tsi_payload = build_tsi_payload;
624 this->build_tsr_payload = build_tsr_payload;
625 this->destroy_after_state_change = destroy_after_state_change;
626
627 /* private data */
628 this->ike_sa = ike_sa;
629 this->received_nonce = CHUNK_INITIALIZER;
630 this->shared_secret = CHUNK_INITIALIZER;
631 this->logger = this->ike_sa->get_logger(this->ike_sa);
632 this->diffie_hellman = diffie_hellman;
633 this->sent_nonce = sent_nonce;
634 this->dh_group_priority = dh_group_priority;
635
636 return &(this->public);
637 }