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