5ea4588a1f48268ed6b520358e724b74bf4abc59
[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 diffie_hellman_t *diffie_hellman;
57
58 /**
59 * Diffie Hellman group number from selected IKE proposal.
60 */
61 u_int16_t dh_group_number;
62
63 /**
64 * Priority used to get matching dh_group number.
65 */
66 u_int16_t dh_group_priority;
67
68 /**
69 * Sent nonce value.
70 *
71 * This value is passed to the next state of type IKE_SA_INIT_RESPONDED.
72 */
73 chunk_t sent_nonce;
74
75 /**
76 * Received nonce value
77 *
78 * This value is passed to the next state of type IKE_SA_INIT_RESPONDED.
79 */
80 chunk_t received_nonce;
81
82 /**
83 * Logger used to log data .
84 *
85 * Is logger of ike_sa!
86 */
87 logger_t *logger;
88
89 /**
90 * Handles received SA payload and builds the SA payload for the response.
91 *
92 * @param this calling object
93 * @param sa_request The received SA payload
94 * @param response the SA payload is added to this response message_t object.
95 * @return
96 * - DELETE_ME
97 * - SUCCESS
98 */
99 status_t (*build_sa_payload) (private_responder_init_t *this,sa_payload_t *sa_request, message_t *response);
100
101 /**
102 * Handles received KE payload and builds the KE payload for the response.
103 *
104 * @param this calling object
105 * @param ke_request The received KE payload
106 * @param response the KE payload is added to this response message_t object.
107 * - DELETE_ME
108 * - SUCCESS
109 */
110 status_t (*build_ke_payload) (private_responder_init_t *this,ke_payload_t *ke_request, message_t *response);
111
112 /**
113 * Handles received NONCE payload and builds the NONCE payload for the response.
114 *
115 * @param this calling object
116 * @param nonce_request The received NONCE payload
117 * @param response the NONCE payload is added to this response message_t object.
118 * - DELETE_ME
119 * - SUCCESS
120 */
121 status_t (*build_nonce_payload) (private_responder_init_t *this,nonce_payload_t *nonce_request, message_t *response);
122
123 /**
124 * Sends a IKE_SA_INIT reply containing a notify payload.
125 *
126 * @param this calling object
127 * @param notify_payload notify_payload to process
128 */
129 status_t (*process_notify_payload) (private_responder_init_t *this, notify_payload_t *notify_payload);
130
131 /**
132 * Destroy function called internally of this class after change
133 * to state IKE_SA_INIT_RESPONDED 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
143 /**
144 * Implementation of state_t.process_message.
145 */
146 static status_t process_message(private_responder_init_t *this, message_t *message)
147 {
148 ike_sa_init_responded_t *next_state;
149 chunk_t ike_sa_init_response_data;
150 chunk_t ike_sa_init_request_data;
151 sa_payload_t *sa_request = NULL;
152 ke_payload_t *ke_request = NULL;
153 nonce_payload_t *nonce_request = NULL;
154 host_t *source, *destination;
155 init_config_t *init_config;
156 chunk_t shared_secret;
157 iterator_t *payloads;
158 message_t *response;
159 status_t status;
160
161 if (message->get_exchange_type(message) != IKE_SA_INIT)
162 {
163 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)));
164 return DELETE_ME;
165 }
166 if (!message->get_request(message))
167 {
168 this->logger->log(this->logger, ERROR | LEVEL1, "IKE_SA_INIT responses not allowed state ike_sa_init_responded");
169 return DELETE_ME;
170 }
171
172 /* this is the first message to process, so get host infos */
173 source = message->get_source(message);
174 destination = message->get_destination(message);
175
176 status = charon->configuration_manager->get_init_config_for_host(charon->configuration_manager,destination,source,&init_config);
177 if (status != SUCCESS)
178 {
179 /* no configuration matches given host */
180 this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request does not match any available configuration. Deleting IKE_SA");
181 this->ike_sa->send_notify(this->ike_sa, IKE_SA_INIT, NO_PROPOSAL_CHOSEN, CHUNK_INITIALIZER);
182 return DELETE_ME;
183 }
184 this->ike_sa->set_init_config(this->ike_sa,init_config);
185
186 this->ike_sa->set_my_host(this->ike_sa, destination->clone(destination));
187 this->ike_sa->set_other_host(this->ike_sa, source->clone(source));
188
189 /* parse incoming message */
190 status = message->parse_body(message, NULL, NULL);
191 if (status != SUCCESS)
192 {
193 if (status == NOT_SUPPORTED)
194 {
195 this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request contains unsupported payload with critical flag set. "
196 "Deleting IKE_SA");
197 this->ike_sa->send_notify(this->ike_sa, IKE_SA_INIT, UNSUPPORTED_CRITICAL_PAYLOAD, CHUNK_INITIALIZER);
198 }
199 else
200 {
201 this->logger->log(this->logger, AUDIT, "Unable to parse IKE_SA_INIT request. Deleting IKE_SA");
202 }
203 return DELETE_ME;
204 }
205
206 payloads = message->get_payload_iterator(message);
207 while (payloads->has_next(payloads))
208 {
209 payload_t *payload;
210
211 payloads->current(payloads, (void**)&payload);
212
213 switch (payload->get_type(payload))
214 {
215 case SECURITY_ASSOCIATION:
216 {
217 sa_request = (sa_payload_t*)payload;
218 break;
219 }
220 case KEY_EXCHANGE:
221 {
222 ke_request = (ke_payload_t*)payload;
223 break;
224 }
225 case NONCE:
226 {
227 nonce_request = (nonce_payload_t*)payload;
228 break;
229 }
230 case NOTIFY:
231 {
232 notify_payload_t *notify_payload = (notify_payload_t *) payload;
233 status = this->process_notify_payload(this, notify_payload);
234 if (status != SUCCESS)
235 {
236 payloads->destroy(payloads);
237 return status;
238 }
239 }
240 default:
241 {
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));
244 break;
245 }
246 }
247 }
248 payloads->destroy(payloads);
249
250 /* check if we have all payloads */
251 if (!(sa_request && ke_request && nonce_request))
252 {
253 this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain all required payloads. Deleting IKE_SA");
254 return DELETE_ME;
255 }
256
257 this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, FALSE, &response);
258
259 status = this->build_sa_payload(this, sa_request, response);
260 if (status != SUCCESS)
261 {
262 response->destroy(response);
263 return status;
264 }
265
266 status = this->build_ke_payload(this, ke_request, response);
267 if (status != SUCCESS)
268 {
269 response->destroy(response);
270 return status;
271 }
272
273 status = this->build_nonce_payload(this, nonce_request, response);
274 if (status != SUCCESS)
275 {
276 response->destroy(response);
277 return status;
278 }
279
280 /* store shared secret */
281 this->logger->log(this->logger, CONTROL | LEVEL2, "Retrieve shared secret and store it");
282 status = this->diffie_hellman->get_shared_secret(this->diffie_hellman, &shared_secret);
283 this->logger->log_chunk(this->logger, PRIVATE, "Shared Diffie Hellman secret", &shared_secret);
284
285 this->ike_sa->compute_secrets(this->ike_sa,shared_secret,this->received_nonce, this->sent_nonce);
286
287 /* not used anymore */
288 allocator_free_chunk(&shared_secret);
289
290 /* message can now be sent (must not be destroyed) */
291 status = this->ike_sa->send_response(this->ike_sa, response);
292 if (status != SUCCESS)
293 {
294 this->logger->log(this->logger, AUDIT, "Unable to send IKE_SA_INIT response. Deleting IKE_SA");
295 response->destroy(response);
296 return DELETE_ME;
297 }
298
299 /* state can now be changed */
300 this->logger->log(this->logger, CONTROL|LEVEL2, "Create next state object of type IKE_SA_INIT_RESPONDED");
301
302 response = this->ike_sa->get_last_responded_message(this->ike_sa);
303 ike_sa_init_response_data = response->get_packet_data(response);
304 ike_sa_init_request_data = message->get_packet_data(message);
305
306 next_state = ike_sa_init_responded_create(this->ike_sa, this->received_nonce, this->sent_nonce,ike_sa_init_request_data,
307 ike_sa_init_response_data);
308
309 /* state can now be changed */
310 this->ike_sa->set_new_state(this->ike_sa, (state_t *) next_state);
311 this->destroy_after_state_change(this);
312
313 return SUCCESS;
314 }
315
316 /**
317 * Implementation of private_initiator_init_t.build_sa_payload.
318 */
319 static status_t build_sa_payload(private_responder_init_t *this,sa_payload_t *sa_request, message_t *response)
320 {
321 ike_proposal_t selected_proposal;
322 ike_proposal_t *ike_proposals;
323 init_config_t *init_config;
324 sa_payload_t* sa_payload;
325 size_t proposal_count;
326 status_t status;
327
328 init_config = this->ike_sa->get_init_config(this->ike_sa);
329
330 this->logger->log(this->logger, CONTROL | LEVEL2, "Process received SA payload");
331 /* get the list of suggested proposals */
332 status = sa_request->get_ike_proposals (sa_request, &ike_proposals,&proposal_count);
333 if (status != SUCCESS)
334 {
335 this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain any proposals. Deleting IKE_SA");
336 this->ike_sa->send_notify(this->ike_sa, IKE_SA_INIT, NO_PROPOSAL_CHOSEN, CHUNK_INITIALIZER);
337 return DELETE_ME;
338 }
339
340 status = init_config->select_proposal(init_config, ike_proposals,proposal_count,&(selected_proposal));
341 allocator_free(ike_proposals);
342 if (status != SUCCESS)
343 {
344 this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain any acceptable proposals. Deleting IKE_SA");
345 this->ike_sa->send_notify(this->ike_sa, IKE_SA_INIT, NO_PROPOSAL_CHOSEN, CHUNK_INITIALIZER);
346 return DELETE_ME;
347 }
348
349 this->dh_group_number = selected_proposal.diffie_hellman_group;
350
351 status = this->ike_sa->create_transforms_from_proposal(this->ike_sa,&(selected_proposal));
352 if (status != SUCCESS)
353 {
354 this->logger->log(this->logger, AUDIT, "Transform objects could not be created from selected proposal. Deleting IKE_SA");
355 return DELETE_ME;
356 }
357
358 this->logger->log(this->logger, CONTROL | LEVEL2, "SA Payload processed");
359
360 this->logger->log(this->logger, CONTROL|LEVEL2, "Building SA payload");
361 sa_payload = sa_payload_create_from_ike_proposals(&(selected_proposal),1);
362 this->logger->log(this->logger, CONTROL|LEVEL2, "add SA payload to message");
363 response->add_payload(response,(payload_t *) sa_payload);
364
365 return SUCCESS;
366 }
367
368 /**
369 * Implementation of private_initiator_init_t.build_ke_payload.
370 */
371 static status_t build_ke_payload(private_responder_init_t *this,ke_payload_t *ke_request, message_t *response)
372 {
373 diffie_hellman_group_t group;
374 ke_payload_t *ke_payload;
375 diffie_hellman_t *dh;
376 chunk_t key_data;
377
378 this->logger->log(this->logger, CONTROL | LEVEL2, "Process received KE payload");
379 group = ke_request->get_dh_group_number(ke_request);
380
381 if (group == MODP_UNDEFINED)
382 {
383 this->logger->log(this->logger, AUDIT, "No diffie hellman group to select. Deleting IKE_SA");
384 return DELETE_ME;
385 }
386 if (this->dh_group_number != group)
387 {
388 u_int16_t accepted_group;
389 chunk_t accepted_group_chunk;
390 /* group not same as selected one
391 * Maybe key exchange payload is before SA payload */
392 this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain a acceptable diffie hellman group. Deleting IKE_SA");
393
394 accepted_group = htons(this->dh_group_number);
395 accepted_group_chunk.ptr = (u_int8_t*) &(accepted_group);
396 accepted_group_chunk.len = 2;
397 this->ike_sa->send_notify(this->ike_sa,IKE_SA_INIT,INVALID_KE_PAYLOAD,accepted_group_chunk);
398 return DELETE_ME;
399 }
400
401 /* create diffie hellman object to handle DH exchange */
402 dh = diffie_hellman_create(group);
403 if (dh == NULL)
404 {
405 this->logger->log(this->logger, AUDIT, "Could not generate DH object with group %d. Deleting IKE_SA",
406 mapping_find(diffie_hellman_group_m,group) );
407 return DELETE_ME;
408 }
409 this->logger->log(this->logger, CONTROL | LEVEL2, "Set other DH public value");
410
411 dh->set_other_public_value(dh, ke_request->get_key_exchange_data(ke_request));
412
413 this->diffie_hellman = dh;
414
415 this->logger->log(this->logger, CONTROL | LEVEL2, "KE Payload processed.");
416
417 this->logger->log(this->logger, CONTROL|LEVEL2, "Building KE payload");
418 this->diffie_hellman->get_my_public_value(this->diffie_hellman,&key_data);
419
420 ke_payload = ke_payload_create();
421 ke_payload->set_key_exchange_data(ke_payload,key_data);
422 ke_payload->set_dh_group_number(ke_payload, this->dh_group_number);
423 allocator_free_chunk(&key_data);
424
425 this->logger->log(this->logger, CONTROL|LEVEL2, "Add KE payload to message");
426 response->add_payload(response,(payload_t *) ke_payload);
427
428 return SUCCESS;
429 }
430
431 /**
432 * Implementation of private_responder_init_t.build_nonce_payload.
433 */
434 static status_t build_nonce_payload(private_responder_init_t *this,nonce_payload_t *nonce_request, message_t *response)
435 {
436 nonce_payload_t *nonce_payload;
437 randomizer_t *randomizer;
438
439 this->logger->log(this->logger, CONTROL | LEVEL2, "Process received NONCE payload");
440 allocator_free(this->received_nonce.ptr);
441 this->received_nonce = CHUNK_INITIALIZER;
442
443 this->logger->log(this->logger, CONTROL | LEVEL2, "Get NONCE value and store it");
444 this->received_nonce = nonce_request->get_nonce(nonce_request);
445
446 this->logger->log(this->logger, CONTROL | LEVEL2, "Create new NONCE value.");
447
448 randomizer = this->ike_sa->get_randomizer(this->ike_sa);
449 randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE, &(this->sent_nonce));
450
451 this->logger->log(this->logger, CONTROL|LEVEL2, "Building NONCE payload");
452 nonce_payload = nonce_payload_create();
453 nonce_payload->set_nonce(nonce_payload, this->sent_nonce);
454
455 this->logger->log(this->logger, CONTROL|LEVEL2, "Add NONCE payload to message");
456 response->add_payload(response,(payload_t *) nonce_payload);
457
458 return SUCCESS;
459 }
460
461 /**
462 * Implementation of private_responder_init_t.process_notify_payload.
463 */
464 static status_t process_notify_payload(private_responder_init_t *this, notify_payload_t *notify_payload)
465 {
466 notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload);
467
468 this->logger->log(this->logger, CONTROL|LEVEL1, "Process notify type %s for protocol %s",
469 mapping_find(notify_message_type_m, notify_message_type),
470 mapping_find(protocol_id_m, notify_payload->get_protocol_id(notify_payload)));
471
472 if (notify_payload->get_protocol_id(notify_payload) != IKE)
473 {
474 this->logger->log(this->logger, ERROR | LEVEL1, "Notify reply not for IKE protocol.");
475 return FAILED;
476 }
477 switch (notify_message_type)
478 {
479 default:
480 {
481 this->logger->log(this->logger, CONTROL, "IKE_SA_INIT request contained a notify (%d), ignored.",
482 notify_message_type);
483 return SUCCESS;
484 }
485 }
486 }
487
488 /**
489 * Implementation of state_t.get_state.
490 */
491 static ike_sa_state_t get_state(private_responder_init_t *this)
492 {
493 return RESPONDER_INIT;
494 }
495
496 /**
497 * Implementation of state_t.destroy.
498 */
499 static void destroy(private_responder_init_t *this)
500 {
501 this->logger->log(this->logger, CONTROL | LEVEL1, "Going to destroy responder init state object");
502
503 this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy sent nonce");
504 allocator_free_chunk(&(this->sent_nonce));
505 this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy received nonce");
506 allocator_free_chunk(&(this->received_nonce));
507
508 if (this->diffie_hellman != NULL)
509 {
510 this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy diffie_hellman_t hellman object");
511 this->diffie_hellman->destroy(this->diffie_hellman);
512 }
513 this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy object");
514 allocator_free(this);
515 }
516
517 /**
518 * Implementation of private_responder_init_t.destroy_after_state_change
519 */
520 static void destroy_after_state_change (private_responder_init_t *this)
521 {
522 this->logger->log(this->logger, CONTROL | LEVEL1, "Going to destroy responder_init_t state object");
523
524 /* destroy diffie hellman object */
525 if (this->diffie_hellman != NULL)
526 {
527 this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy diffie_hellman_t object");
528 this->diffie_hellman->destroy(this->diffie_hellman);
529 }
530
531 this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy object");
532 allocator_free(this);
533 }
534
535 /*
536 * Described in header.
537 */
538 responder_init_t *responder_init_create(protected_ike_sa_t *ike_sa)
539 {
540 private_responder_init_t *this = allocator_alloc_thing(private_responder_init_t);
541
542 /* interface functions */
543 this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
544 this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
545 this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
546
547 /* private functions */
548 this->build_sa_payload = build_sa_payload;
549 this->build_ke_payload = build_ke_payload;
550 this->build_nonce_payload = build_nonce_payload;
551 this->destroy_after_state_change = destroy_after_state_change;
552 this->process_notify_payload = process_notify_payload;
553
554 /* private data */
555 this->ike_sa = ike_sa;
556 this->logger = this->ike_sa->get_logger(this->ike_sa);
557 this->sent_nonce = CHUNK_INITIALIZER;
558 this->received_nonce = CHUNK_INITIALIZER;
559 this->dh_group_number = MODP_UNDEFINED;
560 this->diffie_hellman = NULL;
561
562 return &(this->public);
563 }