5526a0e47a026d8dc678ee70f39d3970e1900691
[strongswan.git] / Source / 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) 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 "responder_init.h"
24
25 #include <daemon.h>
26 #include <sa/states/state.h>
27 #include <sa/states/ike_sa_init_responded.h>
28 #include <utils/allocator.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/notify_payload.h>
33 #include <transforms/diffie_hellman.h>
34
35
36 typedef struct private_responder_init_t private_responder_init_t;
37
38 /**
39 * Private data of a responder_init_t object.
40 *
41 */
42 struct private_responder_init_t {
43 /**
44 * Methods of the state_t interface.
45 */
46 responder_init_t public;
47
48 /**
49 * Assigned IKE_SA.
50 */
51 protected_ike_sa_t *ike_sa;
52
53 /**
54 * Diffie Hellman object used to compute shared secret.
55 *
56 * After processing of incoming IKE_SA_INIT-Request the shared key is
57 * passed to the next state of type ike_sa_init_responded_t.
58 */
59 diffie_hellman_t *diffie_hellman;
60
61 /**
62 * Diffie Hellman group number.
63 */
64 u_int16_t dh_group_number;
65
66 /**
67 * Priority used to get matching dh_group number.
68 */
69 u_int16_t dh_group_priority;
70
71 /**
72 * Sent nonce value.
73 *
74 * This value is passed to the next state of type ike_sa_init_responded_t.
75 */
76 chunk_t sent_nonce;
77
78 /**
79 * Received nonce value
80 *
81 * This value is passed to the next state of type ike_sa_init_responded_t.
82 */
83 chunk_t received_nonce;
84
85 /**
86 * Logger used to log data
87 *
88 * Is logger of ike_sa!
89 */
90 logger_t *logger;
91
92 /**
93 * Selected proposal from suggested ones.
94 */
95 ike_proposal_t selected_proposal;
96
97 /**
98 * Builds the IKE_SA_INIT reply message
99 *
100 * @param this calling object
101 * @param message the message will be written to this location.
102 */
103 void (*build_ike_sa_init_reply) (private_responder_init_t *this, message_t **message);
104
105 /**
106 * Builds the SA payload for this state.
107 *
108 * @param this calling object
109 * @param payload The generated SA payload object of type ke_payload_t is
110 * stored at this location.
111 */
112 void (*build_sa_payload) (private_responder_init_t *this, payload_t **payload);
113
114 /**
115 * Builds the KE payload for this state.
116 *
117 * @param this calling object
118 * @param payload The generated KE payload object of type ke_payload_t is
119 * stored at this location.
120 */
121 void (*build_ke_payload) (private_responder_init_t *this, payload_t **payload);
122
123 /**
124 * Builds the NONCE payload for this state.
125 *
126 * @param this calling object
127 * @param payload The generated NONCE payload object of type ke_payload_t is
128 * stored at this location.
129 */
130 void (*build_nonce_payload) (private_responder_init_t *this, payload_t **payload);
131
132 /**
133 * Destroy function called internally of this class after state change succeeded.
134 *
135 * This destroy function does not destroy objects which were passed to the new state.
136 *
137 * @param this calling object
138 */
139 void (*destroy_after_state_change) (private_responder_init_t *this);
140
141 /**
142 * Sends a IKE_SA_INIT reply with a notify payload.
143 *
144 * @param this calling object
145 * @param type type of notify message
146 * @param data data of notify message
147 */
148 void (*send_notify_reply) (private_responder_init_t *this,notify_message_type_t type, chunk_t data);
149
150 };
151
152 /**
153 * Implements state_t.get_state
154 */
155 static status_t process_message(private_responder_init_t *this, message_t *message)
156 {
157 ike_sa_init_responded_t *next_state;
158 chunk_t ike_sa_init_response_data;
159 chunk_t ike_sa_init_request_data;
160 exchange_type_t exchange_type;
161 host_t *source, *destination;
162 init_config_t *init_config;
163 randomizer_t *randomizer;
164 chunk_t shared_secret;
165 iterator_t *payloads;
166 message_t *response;
167 host_t *other_host;
168 host_t *my_host;
169 status_t status;
170
171
172 exchange_type = message->get_exchange_type(message);
173 if (exchange_type != IKE_SA_INIT)
174 {
175 this->logger->log(this->logger, ERROR | MORE, "Message of type %s not supported in state responder_init",mapping_find(exchange_type_m,exchange_type));
176 return DELETE_ME;
177 }
178 if (!message->get_request(message))
179 {
180 this->logger->log(this->logger, ERROR | MORE, "Only requests of type IKE_SA_INIT supported in state responder_init");
181 return DELETE_ME;
182 }
183 /* this is the first message we process, so get host infos */
184 source = message->get_source(message);
185 destination = message->get_destination(message);
186
187 status = charon->configuration_manager->get_init_config_for_host(charon->configuration_manager,destination,source,&init_config);
188 if (status != SUCCESS)
189 {
190 /* no configuration matches given host */
191 this->logger->log(this->logger, ERROR | MORE, "No INIT configuration found for given remote and local hosts");
192
193 return DELETE_ME;
194 }
195
196 this->ike_sa->set_init_config(this->ike_sa,init_config);
197
198 /* we need to clone them, since we destroy the message later */
199 my_host = destination->clone(destination);
200 other_host = source->clone(source);
201
202 this->ike_sa->set_my_host(this->ike_sa, my_host);
203 this->ike_sa->set_other_host(this->ike_sa, other_host);
204
205 /* parse incoming message */
206 status = message->parse_body(message, NULL, NULL);
207 if (status != SUCCESS)
208 {
209 this->logger->log(this->logger, ERROR | MORE, "Could not parse body of request message");
210 return DELETE_ME;
211 }
212
213 /* iterate over incoming payloads. We can be sure, the message contains only accepted payloads! */
214 payloads = message->get_payload_iterator(message);
215
216 while (payloads->has_next(payloads))
217 {
218 payload_t *payload;
219
220 /* get current payload */
221 payloads->current(payloads, (void**)&payload);
222
223 this->logger->log(this->logger, CONTROL|MORE, "Processing payload of type %s", mapping_find(payload_type_m, payload->get_type(payload)));
224 switch (payload->get_type(payload))
225 {
226 case SECURITY_ASSOCIATION:
227 {
228 sa_payload_t *sa_payload = (sa_payload_t*)payload;
229 ike_proposal_t *ike_proposals;
230 size_t proposal_count;
231
232 /* get the list of suggested proposals */
233 status = sa_payload->get_ike_proposals (sa_payload, &ike_proposals,&proposal_count);
234 if (status != SUCCESS)
235 {
236 this->logger->log(this->logger, ERROR | MORE, "SA payload does not contain IKE proposals");
237 payloads->destroy(payloads);
238 return DELETE_ME;
239 }
240
241 status = init_config->select_proposal(init_config, ike_proposals,proposal_count,&(this->selected_proposal));
242 allocator_free(ike_proposals);
243 if (status != SUCCESS)
244 {
245 this->logger->log(this->logger, ERROR | MORE, "No proposal of suggested proposals selected");
246 payloads->destroy(payloads);
247 this->send_notify_reply(this,NO_PROPOSAL_CHOSEN,CHUNK_INITIALIZER);
248 return DELETE_ME;
249 }
250
251 this->dh_group_number = this->selected_proposal.diffie_hellman_group;
252
253 status = this->ike_sa->create_transforms_from_proposal(this->ike_sa,&(this->selected_proposal));
254 if (status != SUCCESS)
255 {
256 this->logger->log(this->logger, ERROR | MORE, "Transform objects could not be created from selected proposal");
257 payloads->destroy(payloads);
258 return DELETE_ME;
259 }
260
261 this->logger->log(this->logger, CONTROL | MORE, "SA Payload processed");
262 break;
263 }
264 case KEY_EXCHANGE:
265 {
266 ke_payload_t *ke_payload = (ke_payload_t*)payload;
267 diffie_hellman_group_t group;
268 diffie_hellman_t *dh;
269
270 group = ke_payload->get_dh_group_number(ke_payload);
271
272 if (group == MODP_UNDEFINED)
273 {
274 this->logger->log(this->logger, ERROR | MORE, "Diffie hellman group set to undefined!");
275 payloads->destroy(payloads);
276 return DELETE_ME;
277 }
278 if (this->dh_group_number != group)
279 {
280 u_int16_t accepted_group;
281 chunk_t accepted_group_chunk;
282 /* group not same as selected one
283 * Maybe key exchange payload is before SA payload */
284 this->logger->log(this->logger, ERROR | MORE, "Diffie hellman group not as in selected proposal!");
285 payloads->destroy(payloads);
286
287 accepted_group = htons(this->dh_group_number);
288 accepted_group_chunk.ptr = (u_int8_t*) &(accepted_group);
289 accepted_group_chunk.len = 2;
290 this->send_notify_reply(this,INVALID_KE_PAYLOAD,accepted_group_chunk);
291 return DELETE_ME;
292 }
293
294 /* create diffie hellman object to handle DH exchange */
295 dh = diffie_hellman_create(group);
296 if (dh == NULL)
297 {
298 this->logger->log(this->logger, ERROR, "Could not generate DH object with group %d",mapping_find(diffie_hellman_group_m,group) );
299 payloads->destroy(payloads);
300 return DELETE_ME;
301 }
302 this->logger->log(this->logger, CONTROL | MORE, "Set other DH public value");
303
304 dh->set_other_public_value(dh, ke_payload->get_key_exchange_data(ke_payload));
305
306 this->diffie_hellman = dh;
307
308 this->logger->log(this->logger, CONTROL | MORE, "KE Payload processed.");
309 break;
310 }
311 case NONCE:
312 {
313 nonce_payload_t *nonce_payload = (nonce_payload_t*)payload;
314
315 allocator_free(this->received_nonce.ptr);
316 this->received_nonce = CHUNK_INITIALIZER;
317
318 this->logger->log(this->logger, CONTROL | MORE, "Get nonce value and store it");
319 nonce_payload->get_nonce(nonce_payload, &(this->received_nonce));
320
321 this->logger->log(this->logger, CONTROL | MORE, "Nonce Payload processed");
322 break;
323 }
324 case NOTIFY:
325 {
326 notify_payload_t *notify_payload = (notify_payload_t *) payload;
327
328
329 this->logger->log(this->logger, CONTROL|MORE, "Process notify type %s for protocol %s",
330 mapping_find(notify_message_type_m, notify_payload->get_notify_message_type(notify_payload)),
331 mapping_find(protocol_id_m, notify_payload->get_protocol_id(notify_payload)));
332
333 if (notify_payload->get_protocol_id(notify_payload) != IKE)
334 {
335 this->logger->log(this->logger, ERROR | MORE, "Notify not for IKE protocol.");
336 payloads->destroy(payloads);
337 return FAILED;
338 }
339 switch (notify_payload->get_notify_message_type(notify_payload))
340 {
341 default:
342 {
343 this->logger->log(this->logger, CONTROL|MORE, "Processing of notify type %s not yet implemented",
344 mapping_find(notify_message_type_m, notify_payload->get_notify_message_type(notify_payload)));
345 break;
346 }
347 }
348 }
349 default:
350 {
351 this->logger->log(this->logger, ERROR | MORE, "Payload type not supported!");
352 payloads->destroy(payloads);
353 return DELETE_ME;
354 }
355 }
356 }
357 /* iterator can be destroyed */
358 payloads->destroy(payloads);
359
360 this->logger->log(this->logger, CONTROL | MORE, "Request successfully handled. Going to create reply.");
361
362 this->logger->log(this->logger, CONTROL | MOST, "Going to create nonce.");
363
364 randomizer = this->ike_sa->get_randomizer(this->ike_sa);
365 randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE, &(this->sent_nonce));
366
367 /* store shared secret */
368 this->logger->log(this->logger, CONTROL | MOST, "Retrieve shared secret and store it.");
369 status = this->diffie_hellman->get_shared_secret(this->diffie_hellman, &shared_secret);
370 this->logger->log_chunk(this->logger, PRIVATE, "Shared secret", &shared_secret);
371
372 this->ike_sa->compute_secrets(this->ike_sa,shared_secret,this->received_nonce, this->sent_nonce);
373
374 /* not used anymore */
375 allocator_free_chunk(&shared_secret);
376
377 this->build_ike_sa_init_reply(this,&response);
378
379 /* message can now be sent (must not be destroyed) */
380 status = this->ike_sa->send_response(this->ike_sa, response);
381 if (status != SUCCESS)
382 {
383 this->logger->log(this->logger, ERROR, "Could not send response message");
384 response->destroy(response);
385 return DELETE_ME;
386 }
387
388 /* state can now be changed */
389 this->logger->log(this->logger, CONTROL|MOST, "Create next state object");
390
391 response = this->ike_sa->get_last_responded_message(this->ike_sa);
392 ike_sa_init_response_data = response->get_packet_data(response);
393 ike_sa_init_request_data = message->get_packet_data(message);
394
395 next_state = ike_sa_init_responded_create(this->ike_sa, this->received_nonce, this->sent_nonce,ike_sa_init_request_data,ike_sa_init_response_data);
396
397 /* state can now be changed */
398 this->ike_sa->set_new_state(this->ike_sa, (state_t *) next_state);
399 /* state has NOW changed :-) */
400 this->logger->log(this->logger, CONTROL|MORE, "Changed state of IKE_SA from %s to %s",mapping_find(ike_sa_state_m,RESPONDER_INIT),mapping_find(ike_sa_state_m,IKE_SA_INIT_RESPONDED) );
401
402 this->logger->log(this->logger, CONTROL|MOST, "Destroy old sate object");
403 this->destroy_after_state_change(this);
404
405 return SUCCESS;
406 }
407
408
409 /**
410 * implements private_responder_init_t.build_ike_sa_init_reply
411 */
412 static void build_ike_sa_init_reply (private_responder_init_t *this, message_t **message)
413 {
414 message_t *response;
415 payload_t *payload;
416
417 this->logger->log(this->logger, CONTROL|MOST, "Going to build message");
418 /* set up the reply */
419 this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, FALSE, &response);
420
421 /* build SA payload */
422 this->build_sa_payload(this, &payload);
423 this->logger->log(this->logger, CONTROL|MOST, "add SA payload to message");
424 response->add_payload(response, payload);
425
426 /* build KE payload */
427 this->build_ke_payload(this,&payload);
428 this->logger->log(this->logger, CONTROL|MOST, "add KE payload to message");
429 response->add_payload(response, payload);
430
431 /* build Nonce payload */
432 this->build_nonce_payload(this, &payload);
433 this->logger->log(this->logger, CONTROL|MOST, "add nonce payload to message");
434 response->add_payload(response, payload);
435
436 *message = response;
437 }
438
439 /**
440 * implements private_initiator_init_t.build_sa_payload
441 */
442 static void build_sa_payload(private_responder_init_t *this, payload_t **payload)
443 {
444 sa_payload_t* sa_payload;
445
446 this->logger->log(this->logger, CONTROL|MORE, "building sa payload");
447 sa_payload = sa_payload_create_from_ike_proposals(&(this->selected_proposal),1);
448
449 *payload = (payload_t *) sa_payload;
450 }
451
452 /**
453 * implements private_initiator_init_t.build_ke_payload
454 */
455 static void build_ke_payload(private_responder_init_t *this, payload_t **payload)
456 {
457 ke_payload_t *ke_payload;
458 chunk_t key_data;
459
460 this->logger->log(this->logger, CONTROL|MORE, "building ke payload");
461 this->diffie_hellman->get_my_public_value(this->diffie_hellman,&key_data);
462
463 ke_payload = ke_payload_create();
464 ke_payload->set_key_exchange_data(ke_payload,key_data);
465 ke_payload->set_dh_group_number(ke_payload, this->dh_group_number);
466 allocator_free_chunk(&key_data);
467
468 *payload = (payload_t *) ke_payload;
469 }
470
471 /**
472 * implements private_initiator_init_t.build_nonce_payload
473 */
474 static void build_nonce_payload(private_responder_init_t *this, payload_t **payload)
475 {
476 nonce_payload_t *nonce_payload;
477
478 this->logger->log(this->logger, CONTROL|MORE, "building nonce payload");
479 nonce_payload = nonce_payload_create();
480 nonce_payload->set_nonce(nonce_payload, this->sent_nonce);
481
482 *payload = (payload_t *) nonce_payload;
483 }
484
485
486 /**
487 * Implements state_t.get_state
488 */
489 static ike_sa_state_t get_state(private_responder_init_t *this)
490 {
491 return RESPONDER_INIT;
492 }
493
494 /**
495 * Implementation of private_initiator_init_t.send_notify_reply.
496 */
497 static void send_notify_reply (private_responder_init_t *this,notify_message_type_t type, chunk_t data)
498 {
499 notify_payload_t *payload;
500 message_t *response;
501 packet_t *packet;
502 status_t status;
503
504 this->logger->log(this->logger, CONTROL|MOST, "Going to build message with notify payload");
505 /* set up the reply */
506 this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, FALSE, &response);
507 payload = notify_payload_create_from_protocol_and_type(IKE,type);
508 if ((data.ptr != NULL) && (data.len > 0))
509 {
510 this->logger->log(this->logger, CONTROL|MOST, "Add Data to notify payload");
511 payload->set_notification_data(payload,data);
512 }
513
514 this->logger->log(this->logger, CONTROL|MOST, "Add Notify payload to message");
515 response->add_payload(response,(payload_t *) payload);
516
517 /* generate packet */
518 this->logger->log(this->logger, CONTROL|MOST, "Gnerate packet from message");
519 status = response->generate(response, NULL, NULL, &packet);
520 if (status != SUCCESS)
521 {
522 this->logger->log(this->logger, ERROR, "Could not generate packet from message");
523 return;
524 }
525
526 this->logger->log(this->logger, CONTROL|MOST, "Add packet to global send queue");
527 charon->send_queue->add(charon->send_queue, packet);
528 this->logger->log(this->logger, CONTROL|MOST, "Destroy message");
529 response->destroy(response);
530 }
531
532 /**
533 * Implements state_t.get_state
534 */
535 static void destroy(private_responder_init_t *this)
536 {
537 this->logger->log(this->logger, CONTROL | MORE, "Going to destroy responder init state object");
538
539 this->logger->log(this->logger, CONTROL | MOST, "Destroy sent nonce");
540 allocator_free_chunk(&(this->sent_nonce));
541 this->logger->log(this->logger, CONTROL | MOST, "Destroy received nonce");
542 allocator_free_chunk(&(this->received_nonce));
543
544 if (this->diffie_hellman != NULL)
545 {
546 this->logger->log(this->logger, CONTROL | MOST, "Destroy diffie_hellman_t hellman object");
547 this->diffie_hellman->destroy(this->diffie_hellman);
548 }
549 this->logger->log(this->logger, CONTROL | MOST, "Destroy object");
550 allocator_free(this);
551 }
552
553 /**
554 * Implements private_responder_init_t.destroy_after_state_change
555 */
556 static void destroy_after_state_change (private_responder_init_t *this)
557 {
558 this->logger->log(this->logger, CONTROL | MORE, "Going to destroy responder_init_t state object");
559
560 /* destroy diffie hellman object */
561 if (this->diffie_hellman != NULL)
562 {
563 this->logger->log(this->logger, CONTROL | MOST, "Destroy diffie_hellman_t object");
564 this->diffie_hellman->destroy(this->diffie_hellman);
565 }
566
567 this->logger->log(this->logger, CONTROL | MOST, "Destroy object");
568 allocator_free(this);
569 }
570
571 /*
572 * Described in header.
573 */
574 responder_init_t *responder_init_create(protected_ike_sa_t *ike_sa)
575 {
576 private_responder_init_t *this = allocator_alloc_thing(private_responder_init_t);
577
578 /* interface functions */
579 this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
580 this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
581 this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
582
583 /* private functions */
584 this->build_ike_sa_init_reply = build_ike_sa_init_reply;
585 this->build_sa_payload = build_sa_payload;
586 this->build_ke_payload = build_ke_payload;
587 this->build_nonce_payload = build_nonce_payload;
588 this->destroy_after_state_change = destroy_after_state_change;
589 this->send_notify_reply = send_notify_reply;
590
591 /* private data */
592 this->ike_sa = ike_sa;
593 this->logger = this->ike_sa->get_logger(this->ike_sa);
594 this->sent_nonce = CHUNK_INITIALIZER;
595 this->received_nonce = CHUNK_INITIALIZER;
596 this->dh_group_number = MODP_UNDEFINED;
597
598 return &(this->public);
599 }