Verify IKEv1 nonce size, send 32 byte nonces
[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 #include <encoding/payloads/id_payload.h>
26
27 typedef struct private_main_mode_t private_main_mode_t;
28
29 /**
30 * Private members of a main_mode_t task.
31 */
32 struct private_main_mode_t {
33
34 /**
35 * Public methods and task_t interface.
36 */
37 main_mode_t public;
38
39 /**
40 * Assigned IKE_SA.
41 */
42 ike_sa_t *ike_sa;
43
44 /**
45 * Are we the initiator?
46 */
47 bool initiator;
48
49 /**
50 * IKE config to establish
51 */
52 ike_cfg_t *ike_cfg;
53
54 /**
55 * Peer config to use
56 */
57 peer_cfg_t *peer_cfg;
58
59 /**
60 * Local authentication configuration
61 */
62 auth_cfg_t *my_auth;
63
64 /**
65 * Remote authentication configuration
66 */
67 auth_cfg_t *other_auth;
68
69 /**
70 * selected IKE proposal
71 */
72 proposal_t *proposal;
73
74 /**
75 * DH exchange
76 */
77 diffie_hellman_t *dh;
78
79 /**
80 * Received public DH value from peer
81 */
82 chunk_t dh_value;
83
84 /**
85 * Initiators nonce
86 */
87 chunk_t nonce_i;
88
89 /**
90 * Responder nonce
91 */
92 chunk_t nonce_r;
93
94 /** states of main mode */
95 enum {
96 MM_INIT,
97 MM_SA,
98 MM_KE,
99 MM_AUTH,
100 } state;
101 };
102
103 /**
104 * Get the first authentcation config from peer config
105 */
106 static auth_cfg_t *get_auth_cfg(private_main_mode_t *this, bool local)
107 {
108 enumerator_t *enumerator;
109 auth_cfg_t *cfg = NULL;
110
111 enumerator = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg,
112 local);
113 enumerator->enumerate(enumerator, &cfg);
114 return cfg;
115 }
116
117 METHOD(task_t, build_i, status_t,
118 private_main_mode_t *this, message_t *message)
119 {
120 switch (this->state)
121 {
122 case MM_INIT:
123 {
124 sa_payload_t *sa_payload;
125 linked_list_t *proposals;
126
127 this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
128 DBG0(DBG_IKE, "initiating IKE_SA %s[%d] to %H",
129 this->ike_sa->get_name(this->ike_sa),
130 this->ike_sa->get_unique_id(this->ike_sa),
131 this->ike_sa->get_other_host(this->ike_sa));
132 this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
133
134 proposals = this->ike_cfg->get_proposals(this->ike_cfg);
135
136 sa_payload = sa_payload_create_from_proposal_list(
137 SECURITY_ASSOCIATION_V1, proposals);
138 proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
139
140 message->add_payload(message, &sa_payload->payload_interface);
141
142 this->state = MM_SA;
143 return NEED_MORE;
144 }
145 case MM_SA:
146 {
147 ke_payload_t *ke_payload;
148 nonce_payload_t *nonce_payload;
149 u_int16_t group;
150 rng_t *rng;
151
152 if (!this->proposal->get_algorithm(this->proposal,
153 DIFFIE_HELLMAN_GROUP, &group, NULL))
154 {
155 DBG1(DBG_IKE, "DH group selection failed");
156 return FAILED;
157 }
158 this->dh = lib->crypto->create_dh(lib->crypto, group);
159 if (!this->dh)
160 {
161 DBG1(DBG_IKE, "negotiated DH group not supported");
162 return FAILED;
163 }
164 ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1,
165 this->dh);
166 message->add_payload(message, &ke_payload->payload_interface);
167
168 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
169 if (!rng)
170 {
171 DBG1(DBG_IKE, "no RNG found to create nonce");
172 return FAILED;
173 }
174 rng->allocate_bytes(rng, NONCE_SIZE, &this->nonce_i);
175 rng->destroy(rng);
176
177 nonce_payload = nonce_payload_create(NONCE_V1);
178 nonce_payload->set_nonce(nonce_payload, this->nonce_i);
179 message->add_payload(message, &nonce_payload->payload_interface);
180
181 this->state = MM_KE;
182 return NEED_MORE;
183 }
184 case MM_KE:
185 {
186 id_payload_t *id_payload;
187 identification_t *id;
188
189 this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
190 this->peer_cfg->get_ref(this->peer_cfg);
191
192 this->my_auth = get_auth_cfg(this, TRUE);
193 this->other_auth = get_auth_cfg(this, FALSE);
194 if (!this->my_auth || !this->other_auth)
195 {
196 DBG1(DBG_CFG, "no auth config found");
197 return FAILED;
198 }
199 id = this->my_auth->get(this->my_auth, AUTH_RULE_IDENTITY);
200 if (!id)
201 {
202 DBG1(DBG_CFG, "own identity not known");
203 return FAILED;
204 }
205
206 this->ike_sa->set_my_id(this->ike_sa, id->clone(id));
207
208 id_payload = id_payload_create_from_identification(ID_V1, id);
209 message->add_payload(message, &id_payload->payload_interface);
210
211 /* TODO-IKEv1: authenticate */
212
213 this->state = MM_AUTH;
214 return NEED_MORE;
215 }
216 default:
217 return FAILED;
218 }
219 }
220
221 METHOD(task_t, process_r, status_t,
222 private_main_mode_t *this, message_t *message)
223 {
224 switch (this->state)
225 {
226 case MM_INIT:
227 {
228
229 linked_list_t *list;
230 sa_payload_t *sa_payload;
231
232 this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
233 DBG0(DBG_IKE, "%H is initiating a Main Mode",
234 message->get_source(message));
235 this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
236
237 this->ike_sa->update_hosts(this->ike_sa,
238 message->get_destination(message),
239 message->get_source(message), TRUE);
240
241 sa_payload = (sa_payload_t*)message->get_payload(message,
242 SECURITY_ASSOCIATION_V1);
243 if (!sa_payload)
244 {
245 DBG1(DBG_IKE, "SA payload missing");
246 return FAILED;
247 }
248 list = sa_payload->get_proposals(sa_payload);
249 this->proposal = this->ike_cfg->select_proposal(this->ike_cfg,
250 list, FALSE);
251 list->destroy_offset(list, offsetof(proposal_t, destroy));
252 if (!this->proposal)
253 {
254 DBG1(DBG_IKE, "no proposal found");
255 return FAILED;
256 }
257 this->state = MM_SA;
258 return NEED_MORE;
259 }
260 case MM_SA:
261 {
262 ke_payload_t *ke_payload;
263 nonce_payload_t *nonce_payload;
264 u_int16_t group;
265
266 ke_payload = (ke_payload_t*)message->get_payload(message,
267 KEY_EXCHANGE_V1);
268 if (!ke_payload)
269 {
270 DBG1(DBG_IKE, "KE payload missing");
271 return FAILED;
272 }
273 this->dh_value = ke_payload->get_key_exchange_data(ke_payload);
274 this->dh_value = chunk_clone(this->dh_value);
275
276 if (!this->proposal->get_algorithm(this->proposal,
277 DIFFIE_HELLMAN_GROUP, &group, NULL))
278 {
279 DBG1(DBG_IKE, "DH group selection failed");
280 return FAILED;
281 }
282 this->dh = lib->crypto->create_dh(lib->crypto, group);
283 if (!this->dh)
284 {
285 DBG1(DBG_IKE, "negotiated DH group not supported");
286 return FAILED;
287 }
288 this->dh->set_other_public_value(this->dh, this->dh_value);
289
290
291 nonce_payload = (nonce_payload_t*)message->get_payload(message,
292 NONCE_V1);
293 if (!nonce_payload)
294 {
295 DBG1(DBG_IKE, "Nonce payload missing");
296 return FAILED;
297 }
298 this->nonce_i = nonce_payload->get_nonce(nonce_payload);
299
300 this->state = MM_KE;
301 return NEED_MORE;
302 }
303 case MM_KE:
304 {
305 enumerator_t *enumerator;
306 id_payload_t *id_payload;
307 identification_t *id, *any;
308
309 id_payload = (id_payload_t*)message->get_payload(message, ID_V1);
310 if (!id_payload)
311 {
312 DBG1(DBG_IKE, "IDii payload missing");
313 return FAILED;
314 }
315
316 id = id_payload->get_identification(id_payload);
317 any = identification_create_from_encoding(ID_ANY, chunk_empty);
318 enumerator = charon->backends->create_peer_cfg_enumerator(
319 charon->backends,
320 this->ike_sa->get_my_host(this->ike_sa),
321 this->ike_sa->get_other_host(this->ike_sa),
322 any, id);
323 if (!enumerator->enumerate(enumerator, &this->peer_cfg))
324 {
325 DBG1(DBG_IKE, "no peer config found");
326 id->destroy(id);
327 any->destroy(any);
328 enumerator->destroy(enumerator);
329 return FAILED;
330 }
331 this->peer_cfg->get_ref(this->peer_cfg);
332 enumerator->destroy(enumerator);
333 any->destroy(any);
334
335 this->ike_sa->set_other_id(this->ike_sa, id);
336
337 this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg);
338
339 this->my_auth = get_auth_cfg(this, TRUE);
340 this->other_auth = get_auth_cfg(this, FALSE);
341 if (!this->my_auth || !this->other_auth)
342 {
343 DBG1(DBG_CFG, "auth config missing");
344 return FAILED;
345 }
346
347 /* TODO-IKEv1: authenticate peer */
348
349 this->state = MM_AUTH;
350 return NEED_MORE;
351 }
352 default:
353 return FAILED;
354 }
355 }
356
357 METHOD(task_t, build_r, status_t,
358 private_main_mode_t *this, message_t *message)
359 {
360 switch (this->state)
361 {
362 case MM_SA:
363 {
364 sa_payload_t *sa_payload;
365
366 sa_payload = sa_payload_create_from_proposal(SECURITY_ASSOCIATION_V1,
367 this->proposal);
368 message->add_payload(message, &sa_payload->payload_interface);
369 return NEED_MORE;
370 }
371 case MM_KE:
372 {
373 ke_payload_t *ke_payload;
374 nonce_payload_t *nonce_payload;
375 rng_t *rng;
376
377 ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1,
378 this->dh);
379 message->add_payload(message, &ke_payload->payload_interface);
380
381 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
382 if (!rng)
383 {
384 DBG1(DBG_IKE, "no RNG found to create nonce");
385 return FAILED;
386 }
387 rng->allocate_bytes(rng, NONCE_SIZE, &this->nonce_r);
388 rng->destroy(rng);
389
390 nonce_payload = nonce_payload_create(NONCE_V1);
391 nonce_payload->set_nonce(nonce_payload, this->nonce_r);
392 message->add_payload(message, &nonce_payload->payload_interface);
393 return NEED_MORE;
394 }
395 case MM_AUTH:
396 {
397 id_payload_t *id_payload;
398 identification_t *id;
399
400 id = this->my_auth->get(this->my_auth, AUTH_RULE_IDENTITY);
401 if (!id)
402 {
403 DBG1(DBG_CFG, "own identity not known");
404 return FAILED;
405 }
406
407 this->ike_sa->set_my_id(this->ike_sa, id);
408
409 id_payload = id_payload_create_from_identification(ID_V1, id);
410 message->add_payload(message, &id_payload->payload_interface);
411
412 /* TODO-IKEv1: authenticate us */
413
414 /* TODO-IKEv1: check for XAUTH rounds, queue them */
415 DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
416 this->ike_sa->get_name(this->ike_sa),
417 this->ike_sa->get_unique_id(this->ike_sa),
418 this->ike_sa->get_my_host(this->ike_sa),
419 this->ike_sa->get_my_id(this->ike_sa),
420 this->ike_sa->get_other_host(this->ike_sa),
421 this->ike_sa->get_other_id(this->ike_sa));
422 this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
423 charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
424 return SUCCESS;
425 }
426 default:
427 return FAILED;
428 }
429 }
430
431 METHOD(task_t, process_i, status_t,
432 private_main_mode_t *this, message_t *message)
433 {
434 switch (this->state)
435 {
436 case MM_SA:
437 {
438 linked_list_t *list;
439 sa_payload_t *sa_payload;
440
441 sa_payload = (sa_payload_t*)message->get_payload(message,
442 SECURITY_ASSOCIATION_V1);
443 if (!sa_payload)
444 {
445 DBG1(DBG_IKE, "SA payload missing");
446 return FAILED;
447 }
448 list = sa_payload->get_proposals(sa_payload);
449 this->proposal = this->ike_cfg->select_proposal(this->ike_cfg,
450 list, FALSE);
451 list->destroy_offset(list, offsetof(proposal_t, destroy));
452 if (!this->proposal)
453 {
454 DBG1(DBG_IKE, "no proposal found");
455 return FAILED;
456 }
457 return NEED_MORE;
458 }
459 case MM_KE:
460 {
461 ke_payload_t *ke_payload;
462 nonce_payload_t *nonce_payload;
463
464 ke_payload = (ke_payload_t*)message->get_payload(message,
465 KEY_EXCHANGE_V1);
466 if (!ke_payload)
467 {
468 DBG1(DBG_IKE, "KE payload missing");
469 return FAILED;
470 }
471 this->dh_value = ke_payload->get_key_exchange_data(ke_payload);
472 this->dh_value = chunk_clone(this->dh_value);
473 this->dh->set_other_public_value(this->dh, this->dh_value);
474
475 nonce_payload = (nonce_payload_t*)message->get_payload(message,
476 NONCE_V1);
477 if (!nonce_payload)
478 {
479 DBG1(DBG_IKE, "Nonce payload missing");
480 return FAILED;
481 }
482 this->nonce_r = nonce_payload->get_nonce(nonce_payload);
483
484 return NEED_MORE;
485 }
486 case MM_AUTH:
487 {
488 id_payload_t *id_payload;
489 identification_t *id;
490
491 id_payload = (id_payload_t*)message->get_payload(message, ID_V1);
492 if (!id_payload)
493 {
494 DBG1(DBG_IKE, "IDir payload missing");
495 return FAILED;
496 }
497 id = id_payload->get_identification(id_payload);
498 if (!id->matches(id, this->other_auth->get(this->other_auth,
499 AUTH_RULE_IDENTITY)))
500 {
501 DBG1(DBG_IKE, "IDir does not match");
502 id->destroy(id);
503 return FAILED;
504 }
505 this->ike_sa->set_other_id(this->ike_sa, id);
506
507 /* TODO-IKEv1: verify auth */
508
509 /* TODO-IKEv1: check for XAUTH rounds, queue them */
510 DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
511 this->ike_sa->get_name(this->ike_sa),
512 this->ike_sa->get_unique_id(this->ike_sa),
513 this->ike_sa->get_my_host(this->ike_sa),
514 this->ike_sa->get_my_id(this->ike_sa),
515 this->ike_sa->get_other_host(this->ike_sa),
516 this->ike_sa->get_other_id(this->ike_sa));
517 this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
518 charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
519 return SUCCESS;
520 }
521 default:
522 return FAILED;
523 }
524 }
525
526 METHOD(task_t, get_type, task_type_t,
527 private_main_mode_t *this)
528 {
529 return MAIN_MODE;
530 }
531
532 METHOD(task_t, migrate, void,
533 private_main_mode_t *this, ike_sa_t *ike_sa)
534 {
535 this->ike_sa = ike_sa;
536 }
537
538 METHOD(task_t, destroy, void,
539 private_main_mode_t *this)
540 {
541 DESTROY_IF(this->peer_cfg);
542 DESTROY_IF(this->proposal);
543 DESTROY_IF(this->dh);
544 free(this->dh_value.ptr);
545 free(this->nonce_i.ptr);
546 free(this->nonce_r.ptr);
547 free(this);
548 }
549
550 /*
551 * Described in header.
552 */
553 main_mode_t *main_mode_create(ike_sa_t *ike_sa, bool initiator)
554 {
555 private_main_mode_t *this;
556
557 INIT(this,
558 .public = {
559 .task = {
560 .get_type = _get_type,
561 .migrate = _migrate,
562 .destroy = _destroy,
563 },
564 },
565 .ike_sa = ike_sa,
566 .initiator = initiator,
567 .state = MM_INIT,
568 );
569
570 if (initiator)
571 {
572 this->public.task.build = _build_i;
573 this->public.task.process = _process_i;
574 }
575 else
576 {
577 this->public.task.build = _build_r;
578 this->public.task.process = _process_r;
579 }
580
581 return &this->public;
582 }