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