530568a8d468eb61da63bd081e1ee01ac05899bc
[strongswan.git] / src / libcharon / sa / tasks / main_mode.c
1 /*
2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
4 *
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>.
9 *
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
13 * for more details.
14 */
15
16 #include "main_mode.h"
17
18 #include <string.h>
19
20 #include <daemon.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>
25
26 typedef struct private_main_mode_t private_main_mode_t;
27
28 /**
29 * Private members of a main_mode_t task.
30 */
31 struct private_main_mode_t {
32
33 /**
34 * Public methods and task_t interface.
35 */
36 main_mode_t public;
37
38 /**
39 * Assigned IKE_SA.
40 */
41 ike_sa_t *ike_sa;
42
43 /**
44 * Are we the initiator?
45 */
46 bool initiator;
47
48 /**
49 * IKE config to establish
50 */
51 ike_cfg_t *config;
52
53 /**
54 * selected IKE proposal
55 */
56 proposal_t *proposal;
57
58 /**
59 * DH exchange
60 */
61 diffie_hellman_t *dh;
62
63 /**
64 * Received public DH value from peer
65 */
66 chunk_t dh_value;
67
68 /**
69 * Initiators nonce
70 */
71 chunk_t nonce_i;
72
73 /**
74 * Responder nonce
75 */
76 chunk_t nonce_r;
77
78 /** states of main mode */
79 enum {
80 MM_INIT,
81 MM_SA,
82 MM_KE,
83 MM_ID,
84 } state;
85 };
86
87 METHOD(task_t, build_i, status_t,
88 private_main_mode_t *this, message_t *message)
89 {
90 /* TODO-IKEv1: initiate mainmode */
91 return FAILED;
92 }
93
94 METHOD(task_t, process_r, status_t,
95 private_main_mode_t *this, message_t *message)
96 {
97 switch (this->state)
98 {
99 case MM_INIT:
100 {
101
102 linked_list_t *list;
103 sa_payload_t *sa_payload;
104
105 this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
106 DBG0(DBG_IKE, "%H is initiating a Main Mode",
107 message->get_source(message));
108 this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
109
110 sa_payload = (sa_payload_t*)message->get_payload(message,
111 SECURITY_ASSOCIATION_V1);
112 if (!sa_payload)
113 {
114 DBG1(DBG_IKE, "SA payload missing");
115 return FAILED;
116 }
117 list = sa_payload->get_proposals(sa_payload);
118 this->proposal = this->config->select_proposal(this->config,
119 list, FALSE);
120 if (!this->proposal)
121 {
122 DBG1(DBG_IKE, "no proposal found");
123 return FAILED;
124 }
125 this->state = MM_SA;
126 return NEED_MORE;
127 }
128 case MM_SA:
129 {
130 ke_payload_t *ke_payload;
131 nonce_payload_t *nonce_payload;
132 u_int16_t group;
133
134 ke_payload = (ke_payload_t*)message->get_payload(message,
135 KEY_EXCHANGE_V1);
136 if (!ke_payload)
137 {
138 DBG1(DBG_IKE, "KE payload missing");
139 return FAILED;
140 }
141 this->dh_value = ke_payload->get_key_exchange_data(ke_payload);
142 this->dh_value = chunk_clone(this->dh_value);
143
144 if (!this->proposal->get_algorithm(this->proposal,
145 DIFFIE_HELLMAN_GROUP, &group, NULL))
146 {
147 DBG1(DBG_IKE, "DH group selection failed");
148 return FAILED;
149 }
150 this->dh = lib->crypto->create_dh(lib->crypto, group);
151 if (!this->dh)
152 {
153 DBG1(DBG_IKE, "negotiated DH group not supported");
154 return FAILED;
155 }
156 this->dh->set_other_public_value(this->dh, this->dh_value);
157
158
159 nonce_payload = (nonce_payload_t*)message->get_payload(message,
160 NONCE_V1);
161 if (!nonce_payload)
162 {
163 DBG1(DBG_IKE, "Nonce payload missing");
164 return FAILED;
165 }
166 this->nonce_i = nonce_payload->get_nonce(nonce_payload);
167 /* TODO-IKEv1: verify nonce length */
168
169 this->state = MM_KE;
170 return NEED_MORE;
171 }
172 default:
173 return FAILED;
174 }
175 }
176
177 METHOD(task_t, build_r, status_t,
178 private_main_mode_t *this, message_t *message)
179 {
180 switch (this->state)
181 {
182 case MM_SA:
183 {
184 sa_payload_t *sa_payload;
185
186 sa_payload = sa_payload_create_from_proposal(SECURITY_ASSOCIATION_V1,
187 this->proposal);
188 message->add_payload(message, &sa_payload->payload_interface);
189 return NEED_MORE;
190 }
191 case MM_KE:
192 {
193 ke_payload_t *ke_payload;
194 nonce_payload_t *nonce_payload;
195 rng_t *rng;
196
197 ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1,
198 this->dh);
199 message->add_payload(message, &ke_payload->payload_interface);
200
201 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
202 if (!rng)
203 {
204 DBG1(DBG_IKE, "no RNG found to create nonce");
205 return FAILED;
206 }
207 /* TODO-IKEv1: nonce size? */
208 rng->allocate_bytes(rng, 20, &this->nonce_r);
209 rng->destroy(rng);
210
211 nonce_payload = nonce_payload_create(NONCE_V1);
212 nonce_payload->set_nonce(nonce_payload, this->nonce_r);
213 message->add_payload(message, &nonce_payload->payload_interface);
214 return NEED_MORE;
215 }
216 default:
217 return FAILED;
218 }
219 }
220
221 METHOD(task_t, process_i, status_t,
222 private_main_mode_t *this, message_t *message)
223 {
224 /* TODO-IKEv1: process main mode as initiator */
225 return FAILED;
226 }
227
228 METHOD(task_t, get_type, task_type_t,
229 private_main_mode_t *this)
230 {
231 return MAIN_MODE;
232 }
233
234 METHOD(task_t, migrate, void,
235 private_main_mode_t *this, ike_sa_t *ike_sa)
236 {
237 this->ike_sa = ike_sa;
238 }
239
240 METHOD(task_t, destroy, void,
241 private_main_mode_t *this)
242 {
243 DESTROY_IF(this->proposal);
244 DESTROY_IF(this->dh);
245 free(this->dh_value.ptr);
246 free(this->nonce_i.ptr);
247 free(this->nonce_r.ptr);
248 free(this);
249 }
250
251 /*
252 * Described in header.
253 */
254 main_mode_t *main_mode_create(ike_sa_t *ike_sa, bool initiator)
255 {
256 private_main_mode_t *this;
257
258 INIT(this,
259 .public = {
260 .task = {
261 .get_type = _get_type,
262 .migrate = _migrate,
263 .destroy = _destroy,
264 },
265 },
266 .ike_sa = ike_sa,
267 .initiator = initiator,
268 .state = MM_INIT,
269 );
270
271 if (initiator)
272 {
273 this->public.task.build = _build_i;
274 this->public.task.process = _process_i;
275 }
276 else
277 {
278 this->public.task.build = _build_r;
279 this->public.task.process = _process_r;
280 }
281
282 return &this->public;
283 }