implemented IKE_SA rekeying
[strongswan.git] / src / charon / sa / transactions / rekey_ike_sa.c
1 /**
2 * @file rekey_ike_sa.c
3 *
4 * @brief Implementation of rekey_ike_sa_t transaction.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006 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 "rekey_ike_sa.h"
24
25 #include <string.h>
26
27 #include <daemon.h>
28 #include <encoding/payloads/sa_payload.h>
29 #include <encoding/payloads/nonce_payload.h>
30 #include <encoding/payloads/ke_payload.h>
31 #include <sa/transactions/delete_ike_sa.h>
32 #include <utils/randomizer.h>
33
34
35 typedef struct private_rekey_ike_sa_t private_rekey_ike_sa_t;
36
37 /**
38 * Private members of a rekey_ike_sa_t object..
39 */
40 struct private_rekey_ike_sa_t {
41
42 /**
43 * Public methods and transaction_t interface.
44 */
45 rekey_ike_sa_t public;
46
47 /**
48 * Assigned IKE_SA.
49 */
50 ike_sa_t *ike_sa;
51
52 /**
53 * Message sent by our peer, if already generated
54 */
55 message_t *message;
56
57 /**
58 * Message ID this transaction uses
59 */
60 u_int32_t message_id;
61
62 /**
63 * Times we did send the request
64 */
65 u_int32_t requested;
66
67 /**
68 * IKE_SA we set up, replaces ike_sa
69 */
70 ike_sa_t *new_sa;
71
72 /**
73 * Connection used to replace IKE_SA
74 */
75 connection_t *connection;
76
77 /**
78 * initiator chosen nonce
79 */
80 chunk_t nonce_i;
81
82 /**
83 * responder chosen nonce
84 */
85 chunk_t nonce_r;
86
87 /**
88 * lower of the nonces of a simultaneus rekeying request
89 */
90 chunk_t nonce_s;
91
92 /**
93 * Diffie hellman to generate new shared secret
94 */
95 diffie_hellman_t *diffie_hellman;
96
97 /**
98 * negotiated proposal to use
99 */
100 proposal_t *proposal;
101
102 /**
103 * Have we lost the simultaneous rekeying nonce compare?
104 */
105 bool lost;
106
107 /**
108 * source of randomness for nonces
109 */
110 randomizer_t *randomizer;
111
112 /**
113 * next transaction processed by the IKE_SA
114 */
115 transaction_t **next;
116
117 /**
118 * Assigned logger.
119 */
120 logger_t *logger;
121 };
122
123 /**
124 * Implementation of transaction_t.get_message_id.
125 */
126 static u_int32_t get_message_id(private_rekey_ike_sa_t *this)
127 {
128 return this->message_id;
129 }
130
131 /**
132 * Implementation of transaction_t.requested.
133 */
134 static u_int32_t requested(private_rekey_ike_sa_t *this)
135 {
136 return this->requested++;
137 }
138
139
140 /**
141 * Implementation of rekey_ike_sa_t.use_dh_group.
142 */
143 static bool use_dh_group(private_rekey_ike_sa_t *this, diffie_hellman_group_t dh_group)
144 {
145 if (this->connection->check_dh_group(this->connection, dh_group))
146 {
147 this->diffie_hellman = diffie_hellman_create(dh_group);
148 if (this->diffie_hellman)
149 {
150 return TRUE;
151 }
152 }
153 return FALSE;
154 }
155
156 /**
157 * Implementation of rekey_ike_sa_t.cancel.
158 */
159 static void cancel(private_rekey_ike_sa_t *this)
160 {
161 this->lost = TRUE;
162 }
163
164 /**
165 * destroy a list of proposals
166 */
167 static void destroy_proposal_list(linked_list_t *list)
168 {
169 proposal_t *proposal;
170
171 while (list->remove_last(list, (void**)&proposal) == SUCCESS)
172 {
173 proposal->destroy(proposal);
174 }
175 list->destroy(list);
176 }
177
178 /**
179 * Implementation of transaction_t.get_request.
180 */
181 static status_t get_request(private_rekey_ike_sa_t *this, message_t **result)
182 {
183 message_t *request;
184 host_t *me, *other;
185
186 /* check if we already have built a message (retransmission) */
187 if (this->message)
188 {
189 *result = this->message;
190 return SUCCESS;
191 }
192
193 me = this->ike_sa->get_my_host(this->ike_sa);
194 other = this->ike_sa->get_other_host(this->ike_sa);
195
196 /* build the request */
197 request = message_create();
198 request->set_source(request, me->clone(me));
199 request->set_destination(request, other->clone(other));
200 request->set_exchange_type(request, CREATE_CHILD_SA);
201 request->set_request(request, TRUE);
202 request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
203 *result = request;
204 this->message = request;
205
206 { /* build SA payload */
207 sa_payload_t *sa_payload;
208 linked_list_t *proposals;
209 ike_sa_id_t *ike_sa_id;
210 iterator_t *iterator;
211 proposal_t *proposal;
212 u_int64_t spi;
213
214 /* get a connection to replace current IKE_SA */
215 this->connection = charon->connections->get_connection_by_name(
216 charon->connections,
217 this->ike_sa->get_name(this->ike_sa));
218 /* if connection lookup by name fails, try it with the hosts */
219 if (this->connection == NULL)
220 {
221 this->connection = charon->connections->get_connection_by_hosts(
222 charon->connections,
223 me, other);
224 if (this->connection == NULL)
225 {
226 this->logger->log(this->logger, ERROR,
227 "no connection found to rekey IKE_SA");
228 return FAILED;
229 }
230 }
231
232 /* create a new SA */
233 ike_sa_id = ike_sa_id_create(0, 0, TRUE);
234 this->new_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
235 ike_sa_id);
236 spi = ike_sa_id->get_initiator_spi(ike_sa_id);
237 ike_sa_id->destroy(ike_sa_id);
238
239 proposals = this->connection->get_proposals(this->connection);
240 iterator = proposals->create_iterator(proposals, TRUE);
241 while (iterator->iterate(iterator, (void**)&proposal))
242 {
243 proposal->set_spi(proposal, spi);
244 }
245 iterator->destroy(iterator);
246
247 sa_payload = sa_payload_create_from_proposal_list(proposals);
248 destroy_proposal_list(proposals);
249 request->add_payload(request, (payload_t*)sa_payload);
250 }
251
252 { /* build the NONCE payload for us (initiator) */
253 nonce_payload_t *nonce_payload;
254
255 if (this->randomizer->allocate_pseudo_random_bytes(this->randomizer,
256 NONCE_SIZE, &this->nonce_i) != SUCCESS)
257 {
258 return FAILED;
259 }
260 nonce_payload = nonce_payload_create();
261 nonce_payload->set_nonce(nonce_payload, this->nonce_i);
262 request->add_payload(request, (payload_t*)nonce_payload);
263 }
264
265 /* if the DH group is set via use_dh_group(), we already have a DH object */
266 if (!this->diffie_hellman)
267 {
268 diffie_hellman_group_t dh_group;
269
270 dh_group = this->connection->get_dh_group(this->connection);
271 this->diffie_hellman = diffie_hellman_create(dh_group);
272 if (this->diffie_hellman == NULL)
273 {
274 this->logger->log(this->logger, AUDIT,
275 "DH group %s (%d) not supported, aborting",
276 mapping_find(diffie_hellman_group_m, dh_group), dh_group);
277 return DESTROY_ME;
278 }
279 }
280
281 { /* build the KE payload from the DH object */
282 ke_payload_t *ke_payload;
283
284 ke_payload = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
285 request->add_payload(request, (payload_t*)ke_payload);
286 }
287
288 this->message_id = this->ike_sa->get_next_message_id(this->ike_sa);
289 request->set_message_id(request, this->message_id);
290
291 return SUCCESS;
292 }
293
294 /**
295 * Handle all kind of notifys
296 */
297 static status_t process_notifys(private_rekey_ike_sa_t *this, notify_payload_t *notify_payload)
298 {
299 notify_type_t notify_type = notify_payload->get_notify_type(notify_payload);
300
301 this->logger->log(this->logger, CONTROL|LEVEL1, "process notify type %s",
302 mapping_find(notify_type_m, notify_type));
303
304 switch (notify_type)
305 {
306 case NO_PROPOSAL_CHOSEN:
307 {
308 this->logger->log(this->logger, AUDIT,
309 "received a NO_PROPOSAL_CHOSEN notify, IKE_SA rekeying failed");
310 return FAILED;
311 }
312 case INVALID_KE_PAYLOAD:
313 {
314 chunk_t notify_data;
315 diffie_hellman_group_t dh_group, old_dh_group;
316 rekey_ike_sa_t *retry;
317
318 old_dh_group = this->connection->get_dh_group(this->connection);
319 notify_data = notify_payload->get_notification_data(notify_payload);
320 dh_group = ntohs(*((u_int16_t*)notify_data.ptr));
321
322 this->logger->log(this->logger, AUDIT,
323 "peer didn't accept DH group %s, it requested %s",
324 mapping_find(diffie_hellman_group_m, old_dh_group),
325 mapping_find(diffie_hellman_group_m, dh_group));
326 if (!this->connection->check_dh_group(this->connection, dh_group))
327 {
328 this->logger->log(this->logger, AUDIT,
329 "requested DH group not acceptable, IKE_SA rekeying failed");
330 return FAILED;
331 }
332 retry = rekey_ike_sa_create(this->ike_sa);
333 retry->use_dh_group(retry, dh_group);
334 *this->next = (transaction_t*)retry;
335 return FAILED;
336 }
337 default:
338 {
339 if (notify_type < 16383)
340 {
341 this->logger->log(this->logger, AUDIT,
342 "received %s notify error (%d, IKE_SA rekeying failed",
343 mapping_find(notify_type_m, notify_type),
344 notify_type);
345 return FAILED;
346 }
347 else
348 {
349 this->logger->log(this->logger, CONTROL,
350 "received %s notify (%d), ignored",
351 mapping_find(notify_type_m, notify_type),
352 notify_type);
353 return SUCCESS;
354 }
355 }
356 }
357 }
358
359 /**
360 * Switch to the new created IKE_SA
361 */
362 static status_t switchto_new_sa(private_rekey_ike_sa_t* this, bool initiator)
363 {
364 identification_t *my_id, *other_id;
365 host_t *my_host, *other_host;
366 char *name;
367
368 my_id = this->ike_sa->get_my_id(this->ike_sa);
369 other_id = this->ike_sa->get_other_id(this->ike_sa);
370 my_host = this->ike_sa->get_my_host(this->ike_sa);
371 other_host = this->ike_sa->get_other_host(this->ike_sa);
372 name = this->connection->get_name(this->connection);
373
374 this->new_sa->set_my_id(this->new_sa, my_id->clone(my_id));
375 this->new_sa->set_other_id(this->new_sa, other_id->clone(other_id));
376 this->new_sa->set_my_host(this->new_sa, my_host->clone(my_host));
377 this->new_sa->set_other_host(this->new_sa, other_host->clone(other_host));
378 this->new_sa->set_name(this->new_sa, name);
379
380 if (this->new_sa->derive_keys(this->new_sa, this->proposal,
381 this->diffie_hellman,
382 this->nonce_i, this->nonce_r, initiator,
383 this->ike_sa->get_child_prf(this->ike_sa)
384 ) != SUCCESS)
385 {
386 return FAILED;
387 }
388
389 this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED);
390
391 this->new_sa->adopt_children(this->new_sa, this->ike_sa);
392
393 this->new_sa->set_lifetimes(this->new_sa,
394 this->connection->get_soft_lifetime(this->connection),
395 this->connection->get_hard_lifetime(this->connection));
396
397 charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa);
398 this->new_sa = NULL;
399 return SUCCESS;
400 }
401
402 /**
403 * Build a notify message.
404 */
405 static void build_notify(notify_type_t type, chunk_t data, message_t *message, bool flush_message)
406 {
407 notify_payload_t *notify;
408
409 if (flush_message)
410 {
411 payload_t *payload;
412 iterator_t *iterator = message->get_payload_iterator(message);
413 while (iterator->iterate(iterator, (void**)&payload))
414 {
415 payload->destroy(payload);
416 iterator->remove(iterator);
417 }
418 iterator->destroy(iterator);
419 }
420
421 notify = notify_payload_create();
422 notify->set_notify_type(notify, type);
423 notify->set_notification_data(notify, data);
424 message->add_payload(message, (payload_t*)notify);
425 }
426
427 /**
428 * Implementation of transaction_t.get_response.
429 */
430 static status_t get_response(private_rekey_ike_sa_t *this, message_t *request,
431 message_t **result, transaction_t **next)
432 {
433 host_t *me, *other;
434 message_t *response;
435 status_t status;
436 iterator_t *payloads;
437 sa_payload_t *sa_request = NULL;
438 nonce_payload_t *nonce_request = NULL;
439 ke_payload_t *ke_request = NULL;
440 nonce_payload_t *nonce_response;
441
442 /* check if we already have built a response (retransmission) */
443 if (this->message)
444 {
445 *result = this->message;
446 return SUCCESS;
447 }
448
449 me = this->ike_sa->get_my_host(this->ike_sa);
450 other = this->ike_sa->get_other_host(this->ike_sa);
451 this->message_id = request->get_message_id(request);
452
453 /* set up response */
454 response = message_create();
455 response->set_source(response, me->clone(me));
456 response->set_destination(response, other->clone(other));
457 response->set_exchange_type(response, CREATE_CHILD_SA);
458 response->set_request(response, FALSE);
459 response->set_message_id(response, this->message_id);
460 response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
461 this->message = response;
462 *result = response;
463
464 /* check message type */
465 if (request->get_exchange_type(request) != CREATE_CHILD_SA)
466 {
467 this->logger->log(this->logger, ERROR,
468 "CREATE_CHILD_SA response of invalid type, aborted");
469 return FAILED;
470 }
471
472 /* apply for notify processing */
473 this->next = next;
474
475 /* Iterate over all payloads. */
476 payloads = request->get_payload_iterator(request);
477 while (payloads->has_next(payloads))
478 {
479 payload_t *payload;
480 payloads->current(payloads, (void**)&payload);
481 switch (payload->get_type(payload))
482 {
483 case SECURITY_ASSOCIATION:
484 sa_request = (sa_payload_t*)payload;
485 break;
486 case NONCE:
487 nonce_request = (nonce_payload_t*)payload;
488 break;
489 case KEY_EXCHANGE:
490 {
491 ke_request = (ke_payload_t*)payload;
492 break;
493 }
494 case NOTIFY:
495 {
496 status = process_notifys(this, (notify_payload_t*)payload);
497 if (status != SUCCESS)
498 {
499 payloads->destroy(payloads);
500 return status;
501 }
502 break;
503 }
504 default:
505 {
506 this->logger->log(this->logger, ERROR, "ignoring %s payload (%d)",
507 mapping_find(payload_type_m, payload->get_type(payload)),
508 payload->get_type(payload));
509 break;
510 }
511 }
512 }
513 payloads->destroy(payloads);
514
515 /* check if we have all payloads */
516 if (!(sa_request && nonce_request && ke_request))
517 {
518 build_notify(INVALID_SYNTAX, CHUNK_INITIALIZER, response, TRUE);
519 this->logger->log(this->logger, AUDIT,
520 "request message incomplete, IKE_SA rekeying failed");
521 return FAILED;
522 }
523
524 { /* process nonce payload */
525 this->nonce_i = nonce_request->get_nonce(nonce_request);
526 if (this->randomizer->allocate_pseudo_random_bytes(this->randomizer,
527 NONCE_SIZE, &this->nonce_r) != SUCCESS)
528 {
529 build_notify(NO_PROPOSAL_CHOSEN, CHUNK_INITIALIZER, response, TRUE);
530 return FAILED;
531 }
532 nonce_response = nonce_payload_create();
533 nonce_response->set_nonce(nonce_response, this->nonce_r);
534 }
535
536 { /* get a connection to replace current IKE_SA */
537 this->connection = charon->connections->get_connection_by_name(
538 charon->connections,
539 this->ike_sa->get_name(this->ike_sa));
540 /* if connection lookup by name fails, try it with the hosts */
541 if (this->connection == NULL)
542 {
543 this->connection = charon->connections->get_connection_by_hosts(
544 charon->connections,
545 me, other);
546 if (this->connection == NULL)
547 {
548 this->logger->log(this->logger, ERROR,
549 "no connection found to rekey IKE_SA, sending NO_RROPOSAL_CHOSEN");
550 build_notify(NO_PROPOSAL_CHOSEN, CHUNK_INITIALIZER, response, TRUE);
551 return FAILED;
552 }
553 }
554 }
555
556 { /* process SA payload */
557 linked_list_t *proposal_list;
558 sa_payload_t *sa_response;
559 u_int64_t spi;
560 ike_sa_id_t *ike_sa_id;
561
562 sa_response = sa_payload_create();
563 /* get proposals from request, and select one with ours */
564 proposal_list = sa_request->get_proposals(sa_request);
565 this->logger->log(this->logger, CONTROL|LEVEL1, "selecting proposals:");
566 this->proposal = this->connection->select_proposal(this->connection, proposal_list);
567 destroy_proposal_list(proposal_list);
568
569 /* do we have a proposal? */
570 if (this->proposal == NULL)
571 {
572 this->logger->log(this->logger, AUDIT,
573 "no proposals acceptable to rekey IKE_SA, sending NO_PROPOSAL_CHOSEN");
574 build_notify(NO_PROPOSAL_CHOSEN, CHUNK_INITIALIZER, response, TRUE);
575 return FAILED;
576 }
577
578 /* create IKE_SA with new SPIs */
579 spi = this->proposal->get_spi(this->proposal);
580 ike_sa_id = ike_sa_id_create(spi, 0, FALSE);
581 this->new_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
582 ike_sa_id);
583 spi = ike_sa_id->get_responder_spi(ike_sa_id);
584 ike_sa_id->destroy(ike_sa_id);
585 this->proposal->set_spi(this->proposal, spi);
586
587 sa_response->add_proposal(sa_response, this->proposal);
588 response->add_payload(response, (payload_t*)sa_response);
589 /* add nonce after sa payload */
590 response->add_payload(response, (payload_t *)nonce_response);
591 }
592
593 { /* process KE payload */
594 diffie_hellman_group_t used_group;
595 ke_payload_t *ke_response;
596
597 used_group = ke_request->get_dh_group_number(ke_request);
598
599 if (!this->connection->check_dh_group(this->connection, used_group) ||
600 (this->diffie_hellman = diffie_hellman_create(used_group)) == NULL)
601 {
602 u_int16_t notify_group;
603 chunk_t notify_chunk;
604
605 notify_group = this->connection->get_dh_group(this->connection);
606 this->logger->log(this->logger, AUDIT,
607 "request used inacceptable DH group %s, sending INVALID_KE_PAYLOAD with %s",
608 mapping_find(diffie_hellman_group_m, used_group),
609 mapping_find(diffie_hellman_group_m, notify_group));
610
611 notify_group = htons(notify_group);
612 notify_chunk.ptr = (u_int8_t*)&notify_group;
613 notify_chunk.len = sizeof(notify_group);
614 build_notify(INVALID_KE_PAYLOAD, notify_chunk, response, TRUE);
615 return DESTROY_ME;
616 }
617 this->diffie_hellman->set_other_public_value(this->diffie_hellman,
618 ke_request->get_key_exchange_data(ke_request));
619
620 /* build response */
621 ke_response = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
622 response->add_payload(response, (payload_t*)ke_response);
623 }
624
625 return switchto_new_sa(this, FALSE);
626 }
627
628 /**
629 * Implementation of transaction_t.conclude
630 */
631 static status_t conclude(private_rekey_ike_sa_t *this, message_t *response,
632 transaction_t **next)
633 {
634 iterator_t *payloads;
635 host_t *me, *other;
636 sa_payload_t *sa_payload = NULL;
637 nonce_payload_t *nonce_payload = NULL;
638 ke_payload_t *ke_payload = NULL;
639 status_t status;
640
641 /* check message type */
642 if (response->get_exchange_type(response) != CREATE_CHILD_SA)
643 {
644 this->logger->log(this->logger, ERROR,
645 "CREATE_CHILD_SA response of invalid type, aborting");
646 return FAILED;
647 }
648
649 me = this->ike_sa->get_my_host(this->ike_sa);
650 other = this->ike_sa->get_other_host(this->ike_sa);
651
652 /* apply for notify processing */
653 this->next = next;
654
655 /* Iterate over all payloads to collect them */
656 payloads = response->get_payload_iterator(response);
657 while (payloads->has_next(payloads))
658 {
659 payload_t *payload;
660 payloads->current(payloads, (void**)&payload);
661 switch (payload->get_type(payload))
662 {
663 case SECURITY_ASSOCIATION:
664 sa_payload = (sa_payload_t*)payload;
665 break;
666 case NONCE:
667 nonce_payload = (nonce_payload_t*)payload;
668 break;
669 case KEY_EXCHANGE:
670 ke_payload = (ke_payload_t*)payload;
671 break;
672 case NOTIFY:
673 {
674 status = process_notifys(this, (notify_payload_t*)payload);
675 if (status != SUCCESS)
676 {
677 payloads->destroy(payloads);
678 return status;
679 }
680 break;
681 }
682 default:
683 {
684 this->logger->log(this->logger, ERROR, "ignoring %s payload (%d)",
685 mapping_find(payload_type_m, payload->get_type(payload)),
686 payload->get_type(payload));
687 break;
688 }
689 }
690 }
691 payloads->destroy(payloads);
692
693 if (!(sa_payload && nonce_payload && ke_payload))
694 {
695 this->logger->log(this->logger, AUDIT, "response message incomplete, rekeying IKE_SA failed");
696 return FAILED;
697 }
698
699 { /* process NONCE payload */
700 this->nonce_r = nonce_payload->get_nonce(nonce_payload);
701 }
702
703 { /* process SA payload */
704 linked_list_t *proposal_list;
705 ike_sa_id_t *ike_sa_id;
706 u_int64_t spi;
707
708 proposal_list = sa_payload->get_proposals(sa_payload);
709 /* we have to re-check here if other's selection is valid */
710 this->proposal = this->connection->select_proposal(this->connection, proposal_list);
711 destroy_proposal_list(proposal_list);
712
713 if (this->proposal == NULL)
714 {
715 this->logger->log(this->logger, AUDIT,
716 "no proposal selected, rekeying IKE_SA failed");
717 return FAILED;
718 }
719 spi = this->proposal->get_spi(this->proposal);
720 ike_sa_id = this->new_sa->get_id(this->new_sa);
721 ike_sa_id->set_responder_spi(ike_sa_id, spi);
722 }
723
724 { /* process KE payload */
725 this->diffie_hellman->set_other_public_value(this->diffie_hellman,
726 ke_payload->get_key_exchange_data(ke_payload));
727 }
728
729 if (switchto_new_sa(this, TRUE) == SUCCESS)
730 {
731 /* new IKE_SA is in use now, delete old */
732 *next = (transaction_t*)delete_ike_sa_create(this->ike_sa);
733 return SUCCESS;
734 }
735 else
736 {
737 /* this should not happen. But if, we destroy both SAs */
738 *next = (transaction_t*)delete_ike_sa_create(this->new_sa);
739 return DESTROY_ME;
740 }
741 }
742
743 /**
744 * implements transaction_t.destroy
745 */
746 static void destroy(private_rekey_ike_sa_t *this)
747 {
748 if (this->new_sa)
749 {
750 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
751 this->new_sa);
752 }
753 DESTROY_IF(this->message);
754 DESTROY_IF(this->connection);
755 DESTROY_IF(this->diffie_hellman);
756 DESTROY_IF(this->proposal);
757 chunk_free(&this->nonce_i);
758 chunk_free(&this->nonce_r);
759 chunk_free(&this->nonce_s);
760 this->randomizer->destroy(this->randomizer);
761 free(this);
762 }
763
764 /*
765 * Described in header.
766 */
767 rekey_ike_sa_t *rekey_ike_sa_create(ike_sa_t *ike_sa)
768 {
769 private_rekey_ike_sa_t *this = malloc_thing(private_rekey_ike_sa_t);
770
771 /* transaction interface functions */
772 this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
773 this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
774 this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
775 this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
776 this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
777 this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
778
779 /* public functions */
780 this->public.use_dh_group = (bool(*)(rekey_ike_sa_t*,diffie_hellman_group_t))use_dh_group;
781 this->public.cancel = (void(*)(rekey_ike_sa_t*))cancel;
782
783 /* private data */
784 this->ike_sa = ike_sa;
785 this->message_id = 0;
786 this->message = NULL;
787 this->requested = 0;
788 this->nonce_i = CHUNK_INITIALIZER;
789 this->nonce_r = CHUNK_INITIALIZER;
790 this->nonce_s = CHUNK_INITIALIZER;
791 this->new_sa = NULL;
792 this->lost = FALSE;
793 this->connection = NULL;
794 this->randomizer = randomizer_create();
795 this->diffie_hellman = NULL;
796 this->proposal = NULL;
797 this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
798
799 return &this->public;
800 }