940a87aa778f936ef4f256bf3774b5bca5e3d4c5
[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 response->destroy(response);
272 return status;
273 }
274
275 status = this->build_ke_payload(this, ke_request, response);
276 if (status != SUCCESS)
277 {
278 response->destroy(response);
279 return status;
280 }
281
282 status = this->build_nonce_payload(this, nonce_request, response);
283 if (status != SUCCESS)
284 {
285 response->destroy(response);
286 return status;
287 }
288
289 /* store shared secret */
290 this->logger->log(this->logger, CONTROL | LEVEL2, "Retrieve shared secret and store it");
291 status = this->diffie_hellman->get_shared_secret(this->diffie_hellman, &shared_secret);
292 this->logger->log_chunk(this->logger, PRIVATE, "Shared Diffie Hellman secret", &shared_secret);
293
294 this->ike_sa->compute_secrets(this->ike_sa,shared_secret,this->received_nonce, this->sent_nonce);
295
296 /* not used anymore */
297 allocator_free_chunk(&shared_secret);
298
299 /* message can now be sent (must not be destroyed) */
300 status = this->ike_sa->send_response(this->ike_sa, response);
301 if (status != SUCCESS)
302 {
303 this->logger->log(this->logger, ERROR, "Could not send response message");
304 response->destroy(response);
305 return DELETE_ME;
306 }
307
308 /* state can now be changed */
309 this->logger->log(this->logger, CONTROL|LEVEL2, "Create next state object of type IKE_SA_INIT_RESPONDED");
310
311 response = this->ike_sa->get_last_responded_message(this->ike_sa);
312 ike_sa_init_response_data = response->get_packet_data(response);
313 ike_sa_init_request_data = message->get_packet_data(message);
314
315 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);
316
317 /* state can now be changed */
318 this->ike_sa->set_new_state(this->ike_sa, (state_t *) next_state);
319 /* state has NOW changed :-) */
320 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) );
321
322 this->logger->log(this->logger, CONTROL|LEVEL2, "Destroy old sate object");
323 this->destroy_after_state_change(this);
324
325 return SUCCESS;
326 }
327
328 /**
329 * Implementation of private_initiator_init_t.build_sa_payload.
330 */
331 static status_t build_sa_payload(private_responder_init_t *this,sa_payload_t *sa_request, message_t *response)
332 {
333 ike_proposal_t selected_proposal;
334 ike_proposal_t *ike_proposals;
335 init_config_t *init_config;
336 sa_payload_t* sa_payload;
337 size_t proposal_count;
338 status_t status;
339
340 init_config = this->ike_sa->get_init_config(this->ike_sa);
341
342 this->logger->log(this->logger, CONTROL | LEVEL2, "Process received SA payload");
343 /* get the list of suggested proposals */
344 status = sa_request->get_ike_proposals (sa_request, &ike_proposals,&proposal_count);
345 if (status != SUCCESS)
346 {
347 this->logger->log(this->logger, ERROR | LEVEL1, "SA payload does not contain IKE proposals");
348 this->send_notify_reply(this,NO_PROPOSAL_CHOSEN,CHUNK_INITIALIZER);
349 return DELETE_ME;
350 }
351
352 status = init_config->select_proposal(init_config, ike_proposals,proposal_count,&(selected_proposal));
353 allocator_free(ike_proposals);
354 if (status != SUCCESS)
355 {
356 this->logger->log(this->logger, ERROR | LEVEL1, "No proposal of suggested proposals selected");
357 this->send_notify_reply(this,NO_PROPOSAL_CHOSEN,CHUNK_INITIALIZER);
358 return DELETE_ME;
359 }
360
361 this->dh_group_number = selected_proposal.diffie_hellman_group;
362
363 status = this->ike_sa->create_transforms_from_proposal(this->ike_sa,&(selected_proposal));
364 if (status != SUCCESS)
365 {
366 this->logger->log(this->logger, ERROR | LEVEL1, "Transform objects could not be created from selected proposal");
367 return DELETE_ME;
368 }
369
370 this->logger->log(this->logger, CONTROL | LEVEL2, "SA Payload processed");
371
372 this->logger->log(this->logger, CONTROL|LEVEL2, "Building SA payload");
373 sa_payload = sa_payload_create_from_ike_proposals(&(selected_proposal),1);
374 this->logger->log(this->logger, CONTROL|LEVEL2, "add SA payload to message");
375 response->add_payload(response,(payload_t *) sa_payload);
376
377 return SUCCESS;
378 }
379
380 /**
381 * Implementation of private_initiator_init_t.build_ke_payload.
382 */
383 static status_t build_ke_payload(private_responder_init_t *this,ke_payload_t *ke_request, message_t *response)
384 {
385 diffie_hellman_group_t group;
386 ke_payload_t *ke_payload;
387 diffie_hellman_t *dh;
388 chunk_t key_data;
389
390 this->logger->log(this->logger, CONTROL | LEVEL2, "Process received KE payload");
391 group = ke_request->get_dh_group_number(ke_request);
392
393 if (group == MODP_UNDEFINED)
394 {
395 this->logger->log(this->logger, ERROR | LEVEL1, "Diffie hellman group set to undefined!");
396 return DELETE_ME;
397 }
398 if (this->dh_group_number != group)
399 {
400 u_int16_t accepted_group;
401 chunk_t accepted_group_chunk;
402 /* group not same as selected one
403 * Maybe key exchange payload is before SA payload */
404 this->logger->log(this->logger, ERROR | LEVEL1, "Diffie hellman group not as in selected proposal!");
405
406 accepted_group = htons(this->dh_group_number);
407 accepted_group_chunk.ptr = (u_int8_t*) &(accepted_group);
408 accepted_group_chunk.len = 2;
409 this->send_notify_reply(this,INVALID_KE_PAYLOAD,accepted_group_chunk);
410 return DELETE_ME;
411 }
412
413 /* create diffie hellman object to handle DH exchange */
414 dh = diffie_hellman_create(group);
415 if (dh == NULL)
416 {
417 this->logger->log(this->logger, ERROR, "Could not generate DH object with group %d",mapping_find(diffie_hellman_group_m,group) );
418 return DELETE_ME;
419 }
420 this->logger->log(this->logger, CONTROL | LEVEL2, "Set other DH public value");
421
422 dh->set_other_public_value(dh, ke_request->get_key_exchange_data(ke_request));
423
424 this->diffie_hellman = dh;
425
426 this->logger->log(this->logger, CONTROL | LEVEL2, "KE Payload processed.");
427
428 this->logger->log(this->logger, CONTROL|LEVEL2, "Building KE payload");
429 this->diffie_hellman->get_my_public_value(this->diffie_hellman,&key_data);
430
431 ke_payload = ke_payload_create();
432 ke_payload->set_key_exchange_data(ke_payload,key_data);
433 ke_payload->set_dh_group_number(ke_payload, this->dh_group_number);
434 allocator_free_chunk(&key_data);
435
436 this->logger->log(this->logger, CONTROL|LEVEL2, "Add KE payload to message");
437 response->add_payload(response,(payload_t *) ke_payload);
438
439 return SUCCESS;
440 }
441
442 /**
443 * Implementation of private_initiator_init_t.build_nonce_payload.
444 */
445 static status_t build_nonce_payload(private_responder_init_t *this,nonce_payload_t *nonce_request, message_t *response)
446 {
447 nonce_payload_t *nonce_payload;
448 randomizer_t *randomizer;
449
450 this->logger->log(this->logger, CONTROL | LEVEL2, "Process received NONCE payload");
451 allocator_free(this->received_nonce.ptr);
452 this->received_nonce = CHUNK_INITIALIZER;
453
454 this->logger->log(this->logger, CONTROL | LEVEL2, "Get NONCE value and store it");
455 this->received_nonce = nonce_request->get_nonce(nonce_request);
456
457 this->logger->log(this->logger, CONTROL | LEVEL2, "Create new NONCE value.");
458
459 randomizer = this->ike_sa->get_randomizer(this->ike_sa);
460 randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE, &(this->sent_nonce));
461
462 this->logger->log(this->logger, CONTROL|LEVEL2, "Building NONCE payload");
463 nonce_payload = nonce_payload_create();
464 nonce_payload->set_nonce(nonce_payload, this->sent_nonce);
465
466 this->logger->log(this->logger, CONTROL|LEVEL2, "Add NONCE payload to message");
467 response->add_payload(response,(payload_t *) nonce_payload);
468
469 return SUCCESS;
470 }
471
472
473 /**
474 * Implementation of state_t.get_state.
475 */
476 static ike_sa_state_t get_state(private_responder_init_t *this)
477 {
478 return RESPONDER_INIT;
479 }
480
481 /**
482 * Implementation of private_initiator_init_t.send_notify_reply.
483 */
484 static void send_notify_reply (private_responder_init_t *this,notify_message_type_t type, chunk_t data)
485 {
486 notify_payload_t *payload;
487 message_t *response;
488 packet_t *packet;
489 status_t status;
490
491 this->logger->log(this->logger, CONTROL|LEVEL2, "Going to build message with notify payload");
492 /* set up the reply */
493 this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, FALSE, &response);
494 payload = notify_payload_create_from_protocol_and_type(IKE,type);
495 if ((data.ptr != NULL) && (data.len > 0))
496 {
497 this->logger->log(this->logger, CONTROL|LEVEL2, "Add Data to notify payload");
498 payload->set_notification_data(payload,data);
499 }
500
501 this->logger->log(this->logger, CONTROL|LEVEL2, "Add Notify payload to message");
502 response->add_payload(response,(payload_t *) payload);
503
504 /* generate packet */
505 this->logger->log(this->logger, CONTROL|LEVEL2, "Gnerate packet from message");
506 status = response->generate(response, NULL, NULL, &packet);
507 if (status != SUCCESS)
508 {
509 this->logger->log(this->logger, ERROR, "Could not generate packet from message");
510 return;
511 }
512
513 this->logger->log(this->logger, CONTROL|LEVEL2, "Add packet to global send queue");
514 charon->send_queue->add(charon->send_queue, packet);
515 this->logger->log(this->logger, CONTROL|LEVEL2, "Destroy message");
516 response->destroy(response);
517 }
518
519 /**
520 * Implementation of state_t.destroy.
521 */
522 static void destroy(private_responder_init_t *this)
523 {
524 this->logger->log(this->logger, CONTROL | LEVEL1, "Going to destroy responder init state object");
525
526 this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy sent nonce");
527 allocator_free_chunk(&(this->sent_nonce));
528 this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy received nonce");
529 allocator_free_chunk(&(this->received_nonce));
530
531 if (this->diffie_hellman != NULL)
532 {
533 this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy diffie_hellman_t hellman object");
534 this->diffie_hellman->destroy(this->diffie_hellman);
535 }
536 this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy object");
537 allocator_free(this);
538 }
539
540 /**
541 * Implementation of private_responder_init_t.destroy_after_state_change
542 */
543 static void destroy_after_state_change (private_responder_init_t *this)
544 {
545 this->logger->log(this->logger, CONTROL | LEVEL1, "Going to destroy responder_init_t state object");
546
547 /* destroy diffie hellman object */
548 if (this->diffie_hellman != NULL)
549 {
550 this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy diffie_hellman_t object");
551 this->diffie_hellman->destroy(this->diffie_hellman);
552 }
553
554 this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy object");
555 allocator_free(this);
556 }
557
558 /*
559 * Described in header.
560 */
561 responder_init_t *responder_init_create(protected_ike_sa_t *ike_sa)
562 {
563 private_responder_init_t *this = allocator_alloc_thing(private_responder_init_t);
564
565 /* interface functions */
566 this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
567 this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
568 this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
569
570 /* private functions */
571 this->build_sa_payload = build_sa_payload;
572 this->build_ke_payload = build_ke_payload;
573 this->build_nonce_payload = build_nonce_payload;
574 this->destroy_after_state_change = destroy_after_state_change;
575 this->send_notify_reply = send_notify_reply;
576
577 /* private data */
578 this->ike_sa = ike_sa;
579 this->logger = this->ike_sa->get_logger(this->ike_sa);
580 this->sent_nonce = CHUNK_INITIALIZER;
581 this->received_nonce = CHUNK_INITIALIZER;
582 this->dh_group_number = MODP_UNDEFINED;
583
584 return &(this->public);
585 }