2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "main_mode.h"
21 #include <crypto/diffie_hellman.h>
22 #include <encoding/payloads/sa_payload.h>
23 #include <encoding/payloads/ke_payload.h>
24 #include <encoding/payloads/nonce_payload.h>
26 typedef struct private_main_mode_t private_main_mode_t
;
29 * Private members of a main_mode_t task.
31 struct private_main_mode_t
{
34 * Public methods and task_t interface.
44 * Are we the initiator?
49 * IKE config to establish
54 * selected IKE proposal
64 * Received public DH value from peer
78 /** states of main mode */
87 METHOD(task_t
, build_i
, status_t
,
88 private_main_mode_t
*this, message_t
*message
)
94 sa_payload_t
*sa_payload
;
95 linked_list_t
*proposals
;
97 this->ike_cfg
= this->ike_sa
->get_ike_cfg(this->ike_sa
);
98 DBG0(DBG_IKE
, "initiating IKE_SA %s[%d] to %H",
99 this->ike_sa
->get_name(this->ike_sa
),
100 this->ike_sa
->get_unique_id(this->ike_sa
),
101 this->ike_sa
->get_other_host(this->ike_sa
));
102 this->ike_sa
->set_state(this->ike_sa
, IKE_CONNECTING
);
104 proposals
= this->ike_cfg
->get_proposals(this->ike_cfg
);
106 sa_payload
= sa_payload_create_from_proposal_list(
107 SECURITY_ASSOCIATION_V1
, proposals
);
108 proposals
->destroy_offset(proposals
, offsetof(proposal_t
, destroy
));
110 message
->add_payload(message
, &sa_payload
->payload_interface
);
117 ke_payload_t
*ke_payload
;
118 nonce_payload_t
*nonce_payload
;
122 if (!this->proposal
->get_algorithm(this->proposal
,
123 DIFFIE_HELLMAN_GROUP
, &group
, NULL
))
125 DBG1(DBG_IKE
, "DH group selection failed");
128 this->dh
= lib
->crypto
->create_dh(lib
->crypto
, group
);
131 DBG1(DBG_IKE
, "negotiated DH group not supported");
134 ke_payload
= ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1
,
136 message
->add_payload(message
, &ke_payload
->payload_interface
);
138 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
141 DBG1(DBG_IKE
, "no RNG found to create nonce");
144 /* TODO-IKEv1: nonce size? */
145 rng
->allocate_bytes(rng
, 20, &this->nonce_i
);
148 nonce_payload
= nonce_payload_create(NONCE_V1
);
149 nonce_payload
->set_nonce(nonce_payload
, this->nonce_i
);
150 message
->add_payload(message
, &nonce_payload
->payload_interface
);
160 METHOD(task_t
, process_r
, status_t
,
161 private_main_mode_t
*this, message_t
*message
)
169 sa_payload_t
*sa_payload
;
171 this->ike_cfg
= this->ike_sa
->get_ike_cfg(this->ike_sa
);
172 DBG0(DBG_IKE
, "%H is initiating a Main Mode",
173 message
->get_source(message
));
174 this->ike_sa
->set_state(this->ike_sa
, IKE_CONNECTING
);
176 sa_payload
= (sa_payload_t
*)message
->get_payload(message
,
177 SECURITY_ASSOCIATION_V1
);
180 DBG1(DBG_IKE
, "SA payload missing");
183 list
= sa_payload
->get_proposals(sa_payload
);
184 this->proposal
= this->ike_cfg
->select_proposal(this->ike_cfg
,
186 list
->destroy_offset(list
, offsetof(proposal_t
, destroy
));
189 DBG1(DBG_IKE
, "no proposal found");
197 ke_payload_t
*ke_payload
;
198 nonce_payload_t
*nonce_payload
;
201 ke_payload
= (ke_payload_t
*)message
->get_payload(message
,
205 DBG1(DBG_IKE
, "KE payload missing");
208 this->dh_value
= ke_payload
->get_key_exchange_data(ke_payload
);
209 this->dh_value
= chunk_clone(this->dh_value
);
211 if (!this->proposal
->get_algorithm(this->proposal
,
212 DIFFIE_HELLMAN_GROUP
, &group
, NULL
))
214 DBG1(DBG_IKE
, "DH group selection failed");
217 this->dh
= lib
->crypto
->create_dh(lib
->crypto
, group
);
220 DBG1(DBG_IKE
, "negotiated DH group not supported");
223 this->dh
->set_other_public_value(this->dh
, this->dh_value
);
226 nonce_payload
= (nonce_payload_t
*)message
->get_payload(message
,
230 DBG1(DBG_IKE
, "Nonce payload missing");
233 this->nonce_i
= nonce_payload
->get_nonce(nonce_payload
);
234 /* TODO-IKEv1: verify nonce length */
244 METHOD(task_t
, build_r
, status_t
,
245 private_main_mode_t
*this, message_t
*message
)
251 sa_payload_t
*sa_payload
;
253 sa_payload
= sa_payload_create_from_proposal(SECURITY_ASSOCIATION_V1
,
255 message
->add_payload(message
, &sa_payload
->payload_interface
);
260 ke_payload_t
*ke_payload
;
261 nonce_payload_t
*nonce_payload
;
264 ke_payload
= ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1
,
266 message
->add_payload(message
, &ke_payload
->payload_interface
);
268 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
271 DBG1(DBG_IKE
, "no RNG found to create nonce");
274 /* TODO-IKEv1: nonce size? */
275 rng
->allocate_bytes(rng
, 20, &this->nonce_r
);
278 nonce_payload
= nonce_payload_create(NONCE_V1
);
279 nonce_payload
->set_nonce(nonce_payload
, this->nonce_r
);
280 message
->add_payload(message
, &nonce_payload
->payload_interface
);
288 METHOD(task_t
, process_i
, status_t
,
289 private_main_mode_t
*this, message_t
*message
)
296 sa_payload_t
*sa_payload
;
298 sa_payload
= (sa_payload_t
*)message
->get_payload(message
,
299 SECURITY_ASSOCIATION_V1
);
302 DBG1(DBG_IKE
, "SA payload missing");
305 list
= sa_payload
->get_proposals(sa_payload
);
306 this->proposal
= this->ike_cfg
->select_proposal(this->ike_cfg
,
308 list
->destroy_offset(list
, offsetof(proposal_t
, destroy
));
311 DBG1(DBG_IKE
, "no proposal found");
318 ke_payload_t
*ke_payload
;
319 nonce_payload_t
*nonce_payload
;
321 ke_payload
= (ke_payload_t
*)message
->get_payload(message
,
325 DBG1(DBG_IKE
, "KE payload missing");
328 this->dh_value
= ke_payload
->get_key_exchange_data(ke_payload
);
329 this->dh_value
= chunk_clone(this->dh_value
);
330 this->dh
->set_other_public_value(this->dh
, this->dh_value
);
332 nonce_payload
= (nonce_payload_t
*)message
->get_payload(message
,
336 DBG1(DBG_IKE
, "Nonce payload missing");
339 this->nonce_r
= nonce_payload
->get_nonce(nonce_payload
);
340 /* TODO-IKEv1: verify nonce length */
349 METHOD(task_t
, get_type
, task_type_t
,
350 private_main_mode_t
*this)
355 METHOD(task_t
, migrate
, void,
356 private_main_mode_t
*this, ike_sa_t
*ike_sa
)
358 this->ike_sa
= ike_sa
;
361 METHOD(task_t
, destroy
, void,
362 private_main_mode_t
*this)
364 DESTROY_IF(this->proposal
);
365 DESTROY_IF(this->dh
);
366 free(this->dh_value
.ptr
);
367 free(this->nonce_i
.ptr
);
368 free(this->nonce_r
.ptr
);
373 * Described in header.
375 main_mode_t
*main_mode_create(ike_sa_t
*ike_sa
, bool initiator
)
377 private_main_mode_t
*this;
382 .get_type
= _get_type
,
388 .initiator
= initiator
,
394 this->public.task
.build
= _build_i
;
395 this->public.task
.process
= _process_i
;
399 this->public.task
.build
= _build_r
;
400 this->public.task
.process
= _process_r
;
403 return &this->public;