Skip any payloads in front of SA to extract initiators SA bytes
[strongswan.git] / src / libcharon / sa / tasks / main_mode.c
1 /*
2 * Copyright (C) 2011 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * Copyright (C) 2011 Martin Willi
6 * Copyright (C) 2011 revosec AG
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19 #include "main_mode.h"
20
21 #include <string.h>
22
23 #include <daemon.h>
24 #include <sa/keymat_v1.h>
25 #include <crypto/diffie_hellman.h>
26 #include <encoding/payloads/sa_payload.h>
27 #include <encoding/payloads/ke_payload.h>
28 #include <encoding/payloads/nonce_payload.h>
29 #include <encoding/payloads/id_payload.h>
30 #include <encoding/payloads/hash_payload.h>
31
32 typedef struct private_main_mode_t private_main_mode_t;
33
34 /**
35 * Private members of a main_mode_t task.
36 */
37 struct private_main_mode_t {
38
39 /**
40 * Public methods and task_t interface.
41 */
42 main_mode_t public;
43
44 /**
45 * Assigned IKE_SA.
46 */
47 ike_sa_t *ike_sa;
48
49 /**
50 * Are we the initiator?
51 */
52 bool initiator;
53
54 /**
55 * IKE config to establish
56 */
57 ike_cfg_t *ike_cfg;
58
59 /**
60 * Peer config to use
61 */
62 peer_cfg_t *peer_cfg;
63
64 /**
65 * Local authentication configuration
66 */
67 auth_cfg_t *my_auth;
68
69 /**
70 * Remote authentication configuration
71 */
72 auth_cfg_t *other_auth;
73
74 /**
75 * selected IKE proposal
76 */
77 proposal_t *proposal;
78
79 /**
80 * DH exchange
81 */
82 diffie_hellman_t *dh;
83
84 /**
85 * Keymat derivation (from SA)
86 */
87 keymat_v1_t *keymat;
88
89 /**
90 * Received public DH value from peer
91 */
92 chunk_t dh_value;
93
94 /**
95 * Initiators nonce
96 */
97 chunk_t nonce_i;
98
99 /**
100 * Responder nonce
101 */
102 chunk_t nonce_r;
103
104 /**
105 * Encoded SA initiator payload used for authentication
106 */
107 chunk_t sa_payload;
108
109 /** states of main mode */
110 enum {
111 MM_INIT,
112 MM_SA,
113 MM_KE,
114 MM_AUTH,
115 } state;
116 };
117
118 /**
119 * Get the first authentcation config from peer config
120 */
121 static auth_cfg_t *get_auth_cfg(private_main_mode_t *this, bool local)
122 {
123 enumerator_t *enumerator;
124 auth_cfg_t *cfg = NULL;
125
126 enumerator = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg,
127 local);
128 enumerator->enumerate(enumerator, &cfg);
129 enumerator->destroy(enumerator);
130 return cfg;
131 }
132
133 /**
134 * Save the encoded SA payload of a message
135 */
136 static bool save_sa_payload(private_main_mode_t *this, message_t *message)
137 {
138 enumerator_t *enumerator;
139 payload_t *payload, *sa = NULL;
140 chunk_t data;
141 size_t offset = IKE_HEADER_LENGTH;
142
143 enumerator = message->create_payload_enumerator(message);
144 while (enumerator->enumerate(enumerator, &payload))
145 {
146 if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1)
147 {
148 sa = payload;
149 break;
150 }
151 else
152 {
153 offset += payload->get_length(payload);
154 }
155 }
156 enumerator->destroy(enumerator);
157
158 data = message->get_packet_data(message);
159 if (sa && data.len >= offset + sa->get_length(sa))
160 {
161 /* Get SA payload without 4 byte fixed header */
162 data = chunk_skip(data, offset);
163 data.len = sa->get_length(sa);
164 data = chunk_skip(data, 4);
165 this->sa_payload = chunk_clone(data);
166 return TRUE;
167 }
168 return FALSE;
169 }
170
171 METHOD(task_t, build_i, status_t,
172 private_main_mode_t *this, message_t *message)
173 {
174 switch (this->state)
175 {
176 case MM_INIT:
177 {
178 sa_payload_t *sa_payload;
179 linked_list_t *proposals;
180 packet_t *packet;
181
182 this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
183 DBG0(DBG_IKE, "initiating IKE_SA %s[%d] to %H",
184 this->ike_sa->get_name(this->ike_sa),
185 this->ike_sa->get_unique_id(this->ike_sa),
186 this->ike_sa->get_other_host(this->ike_sa));
187 this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
188
189 proposals = this->ike_cfg->get_proposals(this->ike_cfg);
190
191 sa_payload = sa_payload_create_from_proposal_list(
192 SECURITY_ASSOCIATION_V1, proposals);
193 proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
194
195 message->add_payload(message, &sa_payload->payload_interface);
196
197 /* pregenerate message to store SA payload */
198 if (this->ike_sa->generate_message(this->ike_sa, message,
199 &packet) != SUCCESS)
200 {
201 DBG1(DBG_IKE, "pregenerating SA payload failed");
202 return FAILED;
203 }
204 packet->destroy(packet);
205 if (!save_sa_payload(this, message))
206 {
207 DBG1(DBG_IKE, "SA payload invalid");
208 return FAILED;
209 }
210
211 this->state = MM_SA;
212 return NEED_MORE;
213 }
214 case MM_SA:
215 {
216 ke_payload_t *ke_payload;
217 nonce_payload_t *nonce_payload;
218 u_int16_t group;
219 rng_t *rng;
220
221 if (!this->proposal->get_algorithm(this->proposal,
222 DIFFIE_HELLMAN_GROUP, &group, NULL))
223 {
224 DBG1(DBG_IKE, "DH group selection failed");
225 return FAILED;
226 }
227 this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat,
228 group);
229 if (!this->dh)
230 {
231 DBG1(DBG_IKE, "negotiated DH group not supported");
232 return FAILED;
233 }
234 ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1,
235 this->dh);
236 message->add_payload(message, &ke_payload->payload_interface);
237
238 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
239 if (!rng)
240 {
241 DBG1(DBG_IKE, "no RNG found to create nonce");
242 return FAILED;
243 }
244 rng->allocate_bytes(rng, NONCE_SIZE, &this->nonce_i);
245 rng->destroy(rng);
246
247 nonce_payload = nonce_payload_create(NONCE_V1);
248 nonce_payload->set_nonce(nonce_payload, this->nonce_i);
249 message->add_payload(message, &nonce_payload->payload_interface);
250
251 this->state = MM_KE;
252 return NEED_MORE;
253 }
254 case MM_KE:
255 {
256 id_payload_t *id_payload;
257 hash_payload_t *hash_payload;
258 identification_t *id;
259 chunk_t hash, dh;
260
261 this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
262 this->peer_cfg->get_ref(this->peer_cfg);
263
264 this->my_auth = get_auth_cfg(this, TRUE);
265 this->other_auth = get_auth_cfg(this, FALSE);
266 if (!this->my_auth || !this->other_auth)
267 {
268 DBG1(DBG_CFG, "no auth config found");
269 return FAILED;
270 }
271 id = this->my_auth->get(this->my_auth, AUTH_RULE_IDENTITY);
272 if (!id)
273 {
274 DBG1(DBG_CFG, "own identity not known");
275 return FAILED;
276 }
277
278 this->ike_sa->set_my_id(this->ike_sa, id->clone(id));
279
280 id_payload = id_payload_create_from_identification(ID_V1, id);
281 message->add_payload(message, &id_payload->payload_interface);
282
283 this->dh->get_my_public_value(this->dh, &dh);
284 hash = this->keymat->get_hash(this->keymat, TRUE,
285 dh, this->dh_value, this->ike_sa->get_id(this->ike_sa),
286 this->sa_payload, id);
287 free(dh.ptr);
288 hash_payload = hash_payload_create();
289 hash_payload->set_hash(hash_payload, hash);
290 free(hash.ptr);
291 message->add_payload(message, &hash_payload->payload_interface);
292
293 this->state = MM_AUTH;
294 return NEED_MORE;
295 }
296 default:
297 return FAILED;
298 }
299 }
300
301 METHOD(task_t, process_r, status_t,
302 private_main_mode_t *this, message_t *message)
303 {
304 switch (this->state)
305 {
306 case MM_INIT:
307 {
308 linked_list_t *list;
309 sa_payload_t *sa_payload;
310
311 this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
312 DBG0(DBG_IKE, "%H is initiating a Main Mode",
313 message->get_source(message));
314 this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
315
316 this->ike_sa->update_hosts(this->ike_sa,
317 message->get_destination(message),
318 message->get_source(message), TRUE);
319
320 sa_payload = (sa_payload_t*)message->get_payload(message,
321 SECURITY_ASSOCIATION_V1);
322 if (!sa_payload || !save_sa_payload(this, message))
323 {
324 DBG1(DBG_IKE, "SA payload missing or invalid");
325 return FAILED;
326 }
327
328 list = sa_payload->get_proposals(sa_payload);
329 this->proposal = this->ike_cfg->select_proposal(this->ike_cfg,
330 list, FALSE);
331 list->destroy_offset(list, offsetof(proposal_t, destroy));
332 if (!this->proposal)
333 {
334 DBG1(DBG_IKE, "no proposal found");
335 return FAILED;
336 }
337 this->state = MM_SA;
338 return NEED_MORE;
339 }
340 case MM_SA:
341 {
342 ke_payload_t *ke_payload;
343 nonce_payload_t *nonce_payload;
344 u_int16_t group;
345
346 ke_payload = (ke_payload_t*)message->get_payload(message,
347 KEY_EXCHANGE_V1);
348 if (!ke_payload)
349 {
350 DBG1(DBG_IKE, "KE payload missing");
351 return FAILED;
352 }
353 this->dh_value = ke_payload->get_key_exchange_data(ke_payload);
354 this->dh_value = chunk_clone(this->dh_value);
355
356 if (!this->proposal->get_algorithm(this->proposal,
357 DIFFIE_HELLMAN_GROUP, &group, NULL))
358 {
359 DBG1(DBG_IKE, "DH group selection failed");
360 return FAILED;
361 }
362 this->dh = lib->crypto->create_dh(lib->crypto, group);
363 if (!this->dh)
364 {
365 DBG1(DBG_IKE, "negotiated DH group not supported");
366 return FAILED;
367 }
368 this->dh->set_other_public_value(this->dh, this->dh_value);
369
370 nonce_payload = (nonce_payload_t*)message->get_payload(message,
371 NONCE_V1);
372 if (!nonce_payload)
373 {
374 DBG1(DBG_IKE, "Nonce payload missing");
375 return FAILED;
376 }
377 this->nonce_i = nonce_payload->get_nonce(nonce_payload);
378
379 this->state = MM_KE;
380 return NEED_MORE;
381 }
382 case MM_KE:
383 {
384 enumerator_t *enumerator;
385 id_payload_t *id_payload;
386 hash_payload_t *hash_payload;
387 identification_t *id, *any;
388 chunk_t hash, dh;
389
390 id_payload = (id_payload_t*)message->get_payload(message, ID_V1);
391 if (!id_payload)
392 {
393 DBG1(DBG_IKE, "IDii payload missing");
394 return FAILED;
395 }
396
397 id = id_payload->get_identification(id_payload);
398 any = identification_create_from_encoding(ID_ANY, chunk_empty);
399 enumerator = charon->backends->create_peer_cfg_enumerator(
400 charon->backends,
401 this->ike_sa->get_my_host(this->ike_sa),
402 this->ike_sa->get_other_host(this->ike_sa),
403 any, id);
404 if (!enumerator->enumerate(enumerator, &this->peer_cfg))
405 {
406 DBG1(DBG_IKE, "no peer config found");
407 id->destroy(id);
408 any->destroy(any);
409 enumerator->destroy(enumerator);
410 return FAILED;
411 }
412 this->peer_cfg->get_ref(this->peer_cfg);
413 enumerator->destroy(enumerator);
414 any->destroy(any);
415
416 this->ike_sa->set_other_id(this->ike_sa, id);
417
418 this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg);
419
420 this->my_auth = get_auth_cfg(this, TRUE);
421 this->other_auth = get_auth_cfg(this, FALSE);
422 if (!this->my_auth || !this->other_auth)
423 {
424 DBG1(DBG_IKE, "auth config missing");
425 return FAILED;
426 }
427
428 hash_payload = (hash_payload_t*)message->get_payload(message,
429 HASH_V1);
430 if (!hash_payload)
431 {
432 DBG1(DBG_IKE, "hash payload missing");
433 return FAILED;
434 }
435 hash = hash_payload->get_hash(hash_payload);
436 this->dh->get_my_public_value(this->dh, &dh);
437 hash = this->keymat->get_hash(this->keymat, TRUE,
438 this->dh_value, dh, this->ike_sa->get_id(this->ike_sa),
439 this->sa_payload, id);
440 free(dh.ptr);
441 if (!chunk_equals(hash, hash_payload->get_hash(hash_payload)))
442 {
443 DBG1(DBG_IKE, "calculated hash does not match to hash payload");
444 free(hash.ptr);
445 return FAILED;
446 }
447 free(hash.ptr);
448
449 this->state = MM_AUTH;
450 return NEED_MORE;
451 }
452 default:
453 return FAILED;
454 }
455 }
456
457 /**
458 * Lookup a shared secret for this IKE_SA
459 */
460 static shared_key_t *lookup_shared_key(private_main_mode_t *this)
461 {
462 host_t *me, *other;
463 identification_t *my_id, *other_id;
464 shared_key_t *shared_key;
465
466 me = this->ike_sa->get_my_host(this->ike_sa);
467 other = this->ike_sa->get_other_host(this->ike_sa);
468 my_id = identification_create_from_sockaddr(me->get_sockaddr(me));
469 other_id = identification_create_from_sockaddr(other->get_sockaddr(other));
470 if (!my_id || !other_id)
471 {
472 DESTROY_IF(my_id);
473 DESTROY_IF(other_id);
474 return NULL;
475 }
476 shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE, my_id,
477 other_id);
478 if (!shared_key)
479 {
480 DBG1(DBG_IKE, "no shared key found for %H - %H", me, other);
481 }
482 my_id->destroy(my_id);
483 other_id->destroy(other_id);
484 return shared_key;
485 }
486
487 /**
488 * Derive key material for this IKE_SA
489 */
490 static bool derive_keys(private_main_mode_t *this, chunk_t nonce_i,
491 chunk_t nonce_r)
492 {
493 ike_sa_id_t *id = this->ike_sa->get_id(this->ike_sa);
494 shared_key_t *shared_key = NULL;
495 auth_class_t auth;
496
497 /* TODO-IKEv1: support other authentication classes */
498 auth = AUTH_CLASS_PSK;
499 switch (auth)
500 {
501 case AUTH_CLASS_PSK:
502 shared_key = lookup_shared_key(this);
503 break;
504 default:
505 break;
506 }
507 if (!this->keymat->derive_ike_keys(this->keymat, this->proposal, this->dh,
508 this->dh_value, nonce_i, nonce_r, id, auth, shared_key))
509 {
510 DESTROY_IF(shared_key);
511 return FALSE;
512 }
513 DESTROY_IF(shared_key);
514 charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, nonce_i, nonce_r,
515 NULL);
516 return TRUE;
517 }
518
519 METHOD(task_t, build_r, status_t,
520 private_main_mode_t *this, message_t *message)
521 {
522 switch (this->state)
523 {
524 case MM_SA:
525 {
526 sa_payload_t *sa_payload;
527
528 sa_payload = sa_payload_create_from_proposal(SECURITY_ASSOCIATION_V1,
529 this->proposal);
530 message->add_payload(message, &sa_payload->payload_interface);
531
532 return NEED_MORE;
533 }
534 case MM_KE:
535 {
536 ke_payload_t *ke_payload;
537 nonce_payload_t *nonce_payload;
538 rng_t *rng;
539
540 ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1,
541 this->dh);
542 message->add_payload(message, &ke_payload->payload_interface);
543
544 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
545 if (!rng)
546 {
547 DBG1(DBG_IKE, "no RNG found to create nonce");
548 return FAILED;
549 }
550 rng->allocate_bytes(rng, NONCE_SIZE, &this->nonce_r);
551 rng->destroy(rng);
552
553 if (!derive_keys(this, this->nonce_i, this->nonce_r))
554 {
555 DBG1(DBG_IKE, "key derivation failed");
556 return FAILED;
557 }
558
559 nonce_payload = nonce_payload_create(NONCE_V1);
560 nonce_payload->set_nonce(nonce_payload, this->nonce_r);
561 message->add_payload(message, &nonce_payload->payload_interface);
562 return NEED_MORE;
563 }
564 case MM_AUTH:
565 {
566 id_payload_t *id_payload;
567 hash_payload_t *hash_payload;
568 identification_t *id;
569 chunk_t hash, dh;
570
571 id = this->my_auth->get(this->my_auth, AUTH_RULE_IDENTITY);
572 if (!id)
573 {
574 DBG1(DBG_CFG, "own identity not known");
575 return FAILED;
576 }
577
578 this->ike_sa->set_my_id(this->ike_sa, id->clone(id));
579
580 id_payload = id_payload_create_from_identification(ID_V1, id);
581 message->add_payload(message, &id_payload->payload_interface);
582
583 this->dh->get_my_public_value(this->dh, &dh);
584 hash = this->keymat->get_hash(this->keymat, FALSE,
585 dh, this->dh_value, this->ike_sa->get_id(this->ike_sa),
586 this->sa_payload, id);
587 free(dh.ptr);
588 hash_payload = hash_payload_create();
589 hash_payload->set_hash(hash_payload, hash);
590 free(hash.ptr);
591 message->add_payload(message, &hash_payload->payload_interface);
592
593 /* TODO-IKEv1: check for XAUTH rounds, queue them */
594 DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
595 this->ike_sa->get_name(this->ike_sa),
596 this->ike_sa->get_unique_id(this->ike_sa),
597 this->ike_sa->get_my_host(this->ike_sa),
598 this->ike_sa->get_my_id(this->ike_sa),
599 this->ike_sa->get_other_host(this->ike_sa),
600 this->ike_sa->get_other_id(this->ike_sa));
601 this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
602 charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
603 return SUCCESS;
604 }
605 default:
606 return FAILED;
607 }
608 }
609
610 METHOD(task_t, process_i, status_t,
611 private_main_mode_t *this, message_t *message)
612 {
613 switch (this->state)
614 {
615 case MM_SA:
616 {
617 linked_list_t *list;
618 sa_payload_t *sa_payload;
619
620 sa_payload = (sa_payload_t*)message->get_payload(message,
621 SECURITY_ASSOCIATION_V1);
622 if (!sa_payload)
623 {
624 DBG1(DBG_IKE, "SA payload missing");
625 return FAILED;
626 }
627 list = sa_payload->get_proposals(sa_payload);
628 this->proposal = this->ike_cfg->select_proposal(this->ike_cfg,
629 list, FALSE);
630 list->destroy_offset(list, offsetof(proposal_t, destroy));
631 if (!this->proposal)
632 {
633 DBG1(DBG_IKE, "no proposal found");
634 return FAILED;
635 }
636 return NEED_MORE;
637 }
638 case MM_KE:
639 {
640 ke_payload_t *ke_payload;
641 nonce_payload_t *nonce_payload;
642
643 ke_payload = (ke_payload_t*)message->get_payload(message,
644 KEY_EXCHANGE_V1);
645 if (!ke_payload)
646 {
647 DBG1(DBG_IKE, "KE payload missing");
648 return FAILED;
649 }
650 this->dh_value = ke_payload->get_key_exchange_data(ke_payload);
651 this->dh_value = chunk_clone(this->dh_value);
652 this->dh->set_other_public_value(this->dh, this->dh_value);
653
654 nonce_payload = (nonce_payload_t*)message->get_payload(message,
655 NONCE_V1);
656 if (!nonce_payload)
657 {
658 DBG1(DBG_IKE, "Nonce payload missing");
659 return FAILED;
660 }
661 this->nonce_r = nonce_payload->get_nonce(nonce_payload);
662
663 if (!derive_keys(this, this->nonce_i, this->nonce_r))
664 {
665 DBG1(DBG_IKE, "key derivation failed");
666 return FAILED;
667 }
668
669 return NEED_MORE;
670 }
671 case MM_AUTH:
672 {
673 id_payload_t *id_payload;
674 hash_payload_t *hash_payload;
675 identification_t *id;
676 chunk_t hash, dh;
677
678 id_payload = (id_payload_t*)message->get_payload(message, ID_V1);
679 if (!id_payload)
680 {
681 DBG1(DBG_IKE, "IDir payload missing");
682 return FAILED;
683 }
684 id = id_payload->get_identification(id_payload);
685 if (!id->matches(id, this->other_auth->get(this->other_auth,
686 AUTH_RULE_IDENTITY)))
687 {
688 DBG1(DBG_IKE, "IDir does not match");
689 id->destroy(id);
690 return FAILED;
691 }
692 this->ike_sa->set_other_id(this->ike_sa, id);
693
694 hash_payload = (hash_payload_t*)message->get_payload(message,
695 HASH_V1);
696 if (!hash_payload)
697 {
698 DBG1(DBG_IKE, "hash payload missing");
699 return FAILED;
700 }
701 hash = hash_payload->get_hash(hash_payload);
702 this->dh->get_my_public_value(this->dh, &dh);
703 hash = this->keymat->get_hash(this->keymat, FALSE,
704 this->dh_value, dh, this->ike_sa->get_id(this->ike_sa),
705 this->sa_payload, id);
706 free(dh.ptr);
707 if (!chunk_equals(hash, hash_payload->get_hash(hash_payload)))
708 {
709 DBG1(DBG_IKE, "calculated hash does not match to hash payload");
710 free(hash.ptr);
711 return FAILED;
712 }
713 free(hash.ptr);
714
715 /* TODO-IKEv1: check for XAUTH rounds, queue them */
716 DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
717 this->ike_sa->get_name(this->ike_sa),
718 this->ike_sa->get_unique_id(this->ike_sa),
719 this->ike_sa->get_my_host(this->ike_sa),
720 this->ike_sa->get_my_id(this->ike_sa),
721 this->ike_sa->get_other_host(this->ike_sa),
722 this->ike_sa->get_other_id(this->ike_sa));
723 this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
724 charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
725 return SUCCESS;
726 }
727 default:
728 return FAILED;
729 }
730 }
731
732 METHOD(task_t, get_type, task_type_t,
733 private_main_mode_t *this)
734 {
735 return TASK_MAIN_MODE;
736 }
737
738 METHOD(task_t, migrate, void,
739 private_main_mode_t *this, ike_sa_t *ike_sa)
740 {
741 this->ike_sa = ike_sa;
742 }
743
744 METHOD(task_t, destroy, void,
745 private_main_mode_t *this)
746 {
747 DESTROY_IF(this->peer_cfg);
748 DESTROY_IF(this->proposal);
749 DESTROY_IF(this->dh);
750 free(this->dh_value.ptr);
751 free(this->nonce_i.ptr);
752 free(this->nonce_r.ptr);
753 free(this->sa_payload.ptr);
754 free(this);
755 }
756
757 /*
758 * Described in header.
759 */
760 main_mode_t *main_mode_create(ike_sa_t *ike_sa, bool initiator)
761 {
762 private_main_mode_t *this;
763
764 INIT(this,
765 .public = {
766 .task = {
767 .get_type = _get_type,
768 .migrate = _migrate,
769 .destroy = _destroy,
770 },
771 },
772 .ike_sa = ike_sa,
773 .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
774 .initiator = initiator,
775 .state = MM_INIT,
776 );
777
778 if (initiator)
779 {
780 this->public.task.build = _build_i;
781 this->public.task.process = _process_i;
782 }
783 else
784 {
785 this->public.task.build = _build_r;
786 this->public.task.process = _process_r;
787 }
788
789 return &this->public;
790 }