]> git.ipfire.org Git - people/ms/strongswan.git/blob - programs/charon/charon/sa/states/responder_init.c
- renamed get_block_size of hasher
[people/ms/strongswan.git] / programs / charon / 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 <encoding/payloads/sa_payload.h>
29 #include <encoding/payloads/ke_payload.h>
30 #include <encoding/payloads/nonce_payload.h>
31 #include <encoding/payloads/notify_payload.h>
32 #include <crypto/diffie_hellman.h>
33
34
35 typedef struct private_responder_init_t private_responder_init_t;
36
37 /**
38 * Private data of a responder_init_t object.
39 *
40 */
41 struct private_responder_init_t {
42 /**
43 * Methods of the state_t interface.
44 */
45 responder_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 compute shared secret.
54 */
55 diffie_hellman_t *diffie_hellman;
56
57 /**
58 * Diffie Hellman group number from selected IKE proposal.
59 */
60 u_int16_t dh_group_number;
61
62 /**
63 * Priority used to get matching dh_group number.
64 */
65 u_int16_t dh_group_priority;
66
67 /**
68 * Sent nonce value.
69 *
70 * This value is passed to the next state of type IKE_SA_INIT_RESPONDED.
71 */
72 chunk_t sent_nonce;
73
74 /**
75 * Received nonce value
76 *
77 * This value is passed to the next state of type IKE_SA_INIT_RESPONDED.
78 */
79 chunk_t received_nonce;
80
81 /**
82 * Selected proposal
83 */
84 proposal_t *proposal;
85
86 /**
87 * Logger used to log data .
88 *
89 * Is logger of ike_sa!
90 */
91 logger_t *logger;
92
93 /**
94 * Handles received SA payload and builds the SA payload for the response.
95 *
96 * @param this calling object
97 * @param sa_request The received SA payload
98 * @param response the SA payload is added to this response message_t object.
99 * @return
100 * - DELETE_ME
101 * - SUCCESS
102 */
103 status_t (*build_sa_payload) (private_responder_init_t *this,sa_payload_t *sa_request, message_t *response);
104
105 /**
106 * Handles received KE payload and builds the KE payload for the response.
107 *
108 * @param this calling object
109 * @param ke_request The received KE payload
110 * @param response the KE payload is added to this response message_t object.
111 * - DELETE_ME
112 * - SUCCESS
113 */
114 status_t (*build_ke_payload) (private_responder_init_t *this,ke_payload_t *ke_request, message_t *response);
115
116 /**
117 * Handles received NONCE payload and builds the NONCE payload for the response.
118 *
119 * @param this calling object
120 * @param nonce_request The received NONCE payload
121 * @param response the NONCE payload is added to this response message_t object.
122 * - DELETE_ME
123 * - SUCCESS
124 */
125 status_t (*build_nonce_payload) (private_responder_init_t *this,nonce_payload_t *nonce_request, message_t *response);
126
127 /**
128 * Sends a IKE_SA_INIT reply containing a notify payload.
129 *
130 * @param this calling object
131 * @param notify_payload notify_payload to process
132 */
133 status_t (*process_notify_payload) (private_responder_init_t *this, notify_payload_t *notify_payload);
134
135 /**
136 * Destroy function called internally of this class after change
137 * to state IKE_SA_INIT_RESPONDED succeeded.
138 *
139 * This destroy function does not destroy objects which were passed to the new state.
140 *
141 * @param this calling object
142 */
143 void (*destroy_after_state_change) (private_responder_init_t *this);
144
145 };
146
147 /**
148 * Implementation of state_t.process_message.
149 */
150 static status_t process_message(private_responder_init_t *this, message_t *message)
151 {
152 ike_sa_init_responded_t *next_state;
153 chunk_t ike_sa_init_response_data;
154 chunk_t ike_sa_init_request_data;
155 sa_payload_t *sa_request = NULL;
156 ke_payload_t *ke_request = NULL;
157 nonce_payload_t *nonce_request = NULL;
158 host_t *source, *destination;
159 connection_t *connection;
160 iterator_t *payloads;
161 message_t *response;
162 status_t status;
163
164 if (message->get_exchange_type(message) != IKE_SA_INIT)
165 {
166 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)));
167 return DELETE_ME;
168 }
169 if (!message->get_request(message))
170 {
171 this->logger->log(this->logger, ERROR | LEVEL1, "IKE_SA_INIT responses not allowed state ike_sa_init_responded");
172 return DELETE_ME;
173 }
174
175 /* this is the first message to process, so get host infos */
176 source = message->get_source(message);
177 destination = message->get_destination(message);
178
179 connection = charon->connections->get_connection_by_hosts(charon->connections, destination, source);
180 if (connection == NULL)
181 {
182 /* no configuration matches given hosts */
183 this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request does not match any available connection. Deleting IKE_SA");
184 /* TODO: inform requestor */
185 return DELETE_ME;
186 }
187 this->ike_sa->set_connection(this->ike_sa,connection);
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 /* derive all the keys used in the IKE_SA */
281 status = this->ike_sa->build_transforms(this->ike_sa, this->proposal, this->diffie_hellman, this->received_nonce, this->sent_nonce);
282 if (status != SUCCESS)
283 {
284 this->logger->log(this->logger, AUDIT, "Transform objects could not be created from selected proposal. Deleting IKE_SA");
285 return DELETE_ME;
286 }
287
288 /* message can now be sent (must not be destroyed) */
289 status = this->ike_sa->send_response(this->ike_sa, response);
290 if (status != SUCCESS)
291 {
292 this->logger->log(this->logger, AUDIT, "Unable to send IKE_SA_INIT response. Deleting IKE_SA");
293 response->destroy(response);
294 return DELETE_ME;
295 }
296
297 /* state can now be changed */
298 this->logger->log(this->logger, CONTROL|LEVEL2, "Create next state object of type IKE_SA_INIT_RESPONDED");
299
300 response = this->ike_sa->get_last_responded_message(this->ike_sa);
301 ike_sa_init_response_data = response->get_packet_data(response);
302 ike_sa_init_request_data = message->get_packet_data(message);
303
304 next_state = ike_sa_init_responded_create(this->ike_sa, this->received_nonce, this->sent_nonce,ike_sa_init_request_data,
305 ike_sa_init_response_data);
306
307 /* state can now be changed */
308 this->ike_sa->set_new_state(this->ike_sa, (state_t *) next_state);
309 this->destroy_after_state_change(this);
310
311 return SUCCESS;
312 }
313
314 /**
315 * Implementation of private_initiator_init_t.build_sa_payload.
316 */
317 static status_t build_sa_payload(private_responder_init_t *this,sa_payload_t *sa_request, message_t *response)
318 {
319 proposal_t *proposal;
320 linked_list_t *proposal_list;
321 connection_t *connection;
322 sa_payload_t* sa_payload;
323 algorithm_t *algo;
324
325 connection = this->ike_sa->get_connection(this->ike_sa);
326
327 this->logger->log(this->logger, CONTROL | LEVEL2, "Process received SA payload");
328
329 /* get the list of suggested proposals */
330 proposal_list = sa_request->get_proposals (sa_request);
331
332 /* select proposal */
333 this->proposal = connection->select_proposal(connection, proposal_list);
334 while(proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
335 {
336 proposal->destroy(proposal);
337 }
338 proposal_list->destroy(proposal_list);
339 if (this->proposal == NULL)
340 {
341 this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain any acceptable proposals. Deleting IKE_SA");
342 this->ike_sa->send_notify(this->ike_sa, IKE_SA_INIT, NO_PROPOSAL_CHOSEN, CHUNK_INITIALIZER);
343 return DELETE_ME;
344 }
345 /* get selected DH group to force policy, this is very restrictive!? */
346 this->proposal->get_algorithm(this->proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, &algo);
347 this->dh_group_number = algo->algorithm;
348
349 this->logger->log(this->logger, CONTROL | LEVEL2, "SA Payload processed");
350
351 this->logger->log(this->logger, CONTROL|LEVEL2, "Building SA payload");
352 sa_payload = sa_payload_create_from_proposal(this->proposal);
353 this->logger->log(this->logger, CONTROL|LEVEL2, "add SA payload to message");
354 response->add_payload(response,(payload_t *) sa_payload);
355
356 return SUCCESS;
357 }
358
359 /**
360 * Implementation of private_initiator_init_t.build_ke_payload.
361 */
362 static status_t build_ke_payload(private_responder_init_t *this,ke_payload_t *ke_request, message_t *response)
363 {
364 diffie_hellman_group_t group;
365 ke_payload_t *ke_payload;
366 diffie_hellman_t *dh;
367 chunk_t key_data;
368
369 this->logger->log(this->logger, CONTROL | LEVEL2, "Process received KE payload");
370 group = ke_request->get_dh_group_number(ke_request);
371
372 if (group == MODP_UNDEFINED)
373 {
374 this->logger->log(this->logger, AUDIT, "No diffie hellman group to select. Deleting IKE_SA");
375 return DELETE_ME;
376 }
377
378 if (this->dh_group_number != group)
379 {
380 u_int16_t accepted_group;
381 chunk_t accepted_group_chunk;
382 /* group not same as selected one
383 * Maybe key exchange payload is before SA payload */
384 this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain a acceptable diffie hellman group. Deleting IKE_SA");
385
386 accepted_group = htons(this->dh_group_number);
387 accepted_group_chunk.ptr = (u_int8_t*) &(accepted_group);
388 accepted_group_chunk.len = 2;
389 this->ike_sa->send_notify(this->ike_sa,IKE_SA_INIT,INVALID_KE_PAYLOAD,accepted_group_chunk);
390 return DELETE_ME;
391 }
392
393 /* create diffie hellman object to handle DH exchange */
394 dh = diffie_hellman_create(group);
395 if (dh == NULL)
396 {
397 this->logger->log(this->logger, AUDIT, "Could not generate DH object with group %d. Deleting IKE_SA",
398 mapping_find(diffie_hellman_group_m,group) );
399 return DELETE_ME;
400 }
401 this->logger->log(this->logger, CONTROL | LEVEL2, "Set other DH public value");
402
403 dh->set_other_public_value(dh, ke_request->get_key_exchange_data(ke_request));
404
405 this->diffie_hellman = dh;
406
407 this->logger->log(this->logger, CONTROL | LEVEL2, "KE Payload processed.");
408
409 this->logger->log(this->logger, CONTROL|LEVEL2, "Building KE payload");
410 this->diffie_hellman->get_my_public_value(this->diffie_hellman,&key_data);
411
412 ke_payload = ke_payload_create();
413 ke_payload->set_key_exchange_data(ke_payload,key_data);
414 ke_payload->set_dh_group_number(ke_payload, this->dh_group_number);
415 chunk_free(&key_data);
416
417 this->logger->log(this->logger, CONTROL|LEVEL2, "Add KE payload to message");
418 response->add_payload(response,(payload_t *) ke_payload);
419
420 return SUCCESS;
421 }
422
423 /**
424 * Implementation of private_responder_init_t.build_nonce_payload.
425 */
426 static status_t build_nonce_payload(private_responder_init_t *this,nonce_payload_t *nonce_request, message_t *response)
427 {
428 nonce_payload_t *nonce_payload;
429 randomizer_t *randomizer;
430 status_t status;
431
432 this->logger->log(this->logger, CONTROL | LEVEL2, "Process received NONCE payload");
433 free(this->received_nonce.ptr);
434 this->received_nonce = CHUNK_INITIALIZER;
435
436 this->logger->log(this->logger, CONTROL | LEVEL2, "Get NONCE value and store it");
437 this->received_nonce = nonce_request->get_nonce(nonce_request);
438
439 this->logger->log(this->logger, CONTROL | LEVEL2, "Create new NONCE value.");
440
441 randomizer = this->ike_sa->get_randomizer(this->ike_sa);
442 status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE, &(this->sent_nonce));
443 if (status != SUCCESS)
444 {
445 return status;
446 }
447
448 this->logger->log(this->logger, CONTROL|LEVEL2, "Building NONCE payload");
449 nonce_payload = nonce_payload_create();
450 nonce_payload->set_nonce(nonce_payload, this->sent_nonce);
451
452 this->logger->log(this->logger, CONTROL|LEVEL2, "Add NONCE payload to message");
453 response->add_payload(response,(payload_t *) nonce_payload);
454
455 return SUCCESS;
456 }
457
458 /**
459 * Implementation of private_responder_init_t.process_notify_payload.
460 */
461 static status_t process_notify_payload(private_responder_init_t *this, notify_payload_t *notify_payload)
462 {
463 notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload);
464
465 this->logger->log(this->logger, CONTROL|LEVEL1, "Process notify type %s",
466 mapping_find(notify_message_type_m, notify_message_type));
467
468 if (notify_payload->get_protocol_id(notify_payload) != PROTO_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 chunk_free(&(this->sent_nonce));
501 this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy received nonce");
502 chunk_free(&(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 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 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 = malloc_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 = logger_manager->get_logger(logger_manager, 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 }