]>
Commit | Line | Data |
---|---|---|
c60c7694 | 1 | /* |
93104d0f | 2 | * Copyright (C) 2008-2019 Tobias Brunner |
6a4ff35c | 3 | * Copyright (C) 2005-2008 Martin Willi |
c60c7694 | 4 | * Copyright (C) 2005 Jan Hutter |
727615ee | 5 | * HSR Hochschule fuer Technik Rapperswil |
c60c7694 MW |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License as published by the | |
9 | * Free Software Foundation; either version 2 of the License, or (at your | |
10 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 | * for more details. | |
16 | */ | |
17 | ||
18 | #include "ike_init.h" | |
19 | ||
20 | #include <string.h> | |
21 | ||
22 | #include <daemon.h> | |
f6329cae TB |
23 | #include <bio/bio_reader.h> |
24 | #include <bio/bio_writer.h> | |
15a682f4 | 25 | #include <sa/ikev2/keymat_v2.h> |
c60c7694 | 26 | #include <crypto/diffie_hellman.h> |
1d94b795 | 27 | #include <crypto/hashers/hash_algorithm_set.h> |
c60c7694 MW |
28 | #include <encoding/payloads/sa_payload.h> |
29 | #include <encoding/payloads/ke_payload.h> | |
30 | #include <encoding/payloads/nonce_payload.h> | |
31 | ||
a6bdc731 MW |
32 | /** maximum retries to do with cookies/other dh groups */ |
33 | #define MAX_RETRIES 5 | |
c60c7694 MW |
34 | |
35 | typedef struct private_ike_init_t private_ike_init_t; | |
36 | ||
37 | /** | |
38 | * Private members of a ike_init_t task. | |
39 | */ | |
40 | struct private_ike_init_t { | |
7daf5226 | 41 | |
c60c7694 MW |
42 | /** |
43 | * Public methods and task_t interface. | |
44 | */ | |
45 | ike_init_t public; | |
7daf5226 | 46 | |
c60c7694 MW |
47 | /** |
48 | * Assigned IKE_SA. | |
49 | */ | |
50 | ike_sa_t *ike_sa; | |
7daf5226 | 51 | |
c60c7694 MW |
52 | /** |
53 | * Are we the initiator? | |
54 | */ | |
55 | bool initiator; | |
7daf5226 | 56 | |
c60c7694 MW |
57 | /** |
58 | * diffie hellman group to use | |
59 | */ | |
60 | diffie_hellman_group_t dh_group; | |
7daf5226 | 61 | |
c60c7694 | 62 | /** |
6a4ff35c | 63 | * diffie hellman key exchange |
c60c7694 | 64 | */ |
1fd5383e | 65 | diffie_hellman_t *dh; |
7daf5226 | 66 | |
a777155f MW |
67 | /** |
68 | * Applying DH public value failed? | |
69 | */ | |
70 | bool dh_failed; | |
71 | ||
6a4ff35c MW |
72 | /** |
73 | * Keymat derivation (from IKE_SA) | |
74 | */ | |
a0563846 | 75 | keymat_v2_t *keymat; |
7daf5226 | 76 | |
c60c7694 MW |
77 | /** |
78 | * nonce chosen by us | |
79 | */ | |
80 | chunk_t my_nonce; | |
7daf5226 | 81 | |
c60c7694 MW |
82 | /** |
83 | * nonce chosen by peer | |
84 | */ | |
85 | chunk_t other_nonce; | |
7daf5226 | 86 | |
0b308faf RB |
87 | /** |
88 | * nonce generator | |
89 | */ | |
90 | nonce_gen_t *nonceg; | |
91 | ||
c60c7694 MW |
92 | /** |
93 | * Negotiated proposal used for IKE_SA | |
94 | */ | |
95 | proposal_t *proposal; | |
7daf5226 | 96 | |
c60c7694 MW |
97 | /** |
98 | * Old IKE_SA which gets rekeyed | |
99 | */ | |
100 | ike_sa_t *old_sa; | |
7daf5226 | 101 | |
e5a7f1cd MW |
102 | /** |
103 | * cookie received from responder | |
104 | */ | |
105 | chunk_t cookie; | |
7daf5226 | 106 | |
a6bdc731 MW |
107 | /** |
108 | * retries done so far after failure (cookie or bad dh group) | |
109 | */ | |
110 | u_int retry; | |
fff3576b TB |
111 | |
112 | /** | |
113 | * Whether to use Signature Authentication as per RFC 7427 | |
114 | */ | |
115 | bool signature_authentication; | |
489d154e TB |
116 | |
117 | /** | |
118 | * Whether to follow IKEv2 redirects as per RFC 5685 | |
119 | */ | |
120 | bool follow_redirects; | |
c60c7694 MW |
121 | }; |
122 | ||
59565ebf TB |
123 | /** |
124 | * Allocate our own nonce value | |
125 | */ | |
126 | static bool generate_nonce(private_ike_init_t *this) | |
127 | { | |
128 | if (!this->nonceg) | |
129 | { | |
130 | DBG1(DBG_IKE, "no nonce generator found to create nonce"); | |
131 | return FALSE; | |
132 | } | |
133 | if (!this->nonceg->allocate_nonce(this->nonceg, NONCE_SIZE, | |
134 | &this->my_nonce)) | |
135 | { | |
136 | DBG1(DBG_IKE, "nonce allocation failed"); | |
137 | return FALSE; | |
138 | } | |
139 | return TRUE; | |
140 | } | |
141 | ||
f6329cae | 142 | /** |
1d94b795 TB |
143 | * Notify the peer about the hash algorithms we support or expect, |
144 | * as per RFC 7427 | |
f6329cae | 145 | */ |
1d94b795 TB |
146 | static void send_supported_hash_algorithms(private_ike_init_t *this, |
147 | message_t *message) | |
f6329cae | 148 | { |
1d94b795 TB |
149 | hash_algorithm_set_t *algos; |
150 | enumerator_t *enumerator, *rounds; | |
f6329cae TB |
151 | bio_writer_t *writer; |
152 | hash_algorithm_t hash; | |
1d94b795 TB |
153 | peer_cfg_t *peer; |
154 | auth_cfg_t *auth; | |
155 | auth_rule_t rule; | |
54f8d092 | 156 | signature_params_t *config; |
f2eb367a AS |
157 | int written; |
158 | size_t len = BUF_LEN; | |
159 | char buf[len]; | |
160 | char *pos = buf; | |
f6329cae TB |
161 | char *plugin_name; |
162 | ||
1d94b795 TB |
163 | algos = hash_algorithm_set_create(); |
164 | peer = this->ike_sa->get_peer_cfg(this->ike_sa); | |
165 | if (peer) | |
f6329cae | 166 | { |
1d94b795 TB |
167 | rounds = peer->create_auth_cfg_enumerator(peer, FALSE); |
168 | while (rounds->enumerate(rounds, &auth)) | |
f6329cae | 169 | { |
1d94b795 TB |
170 | enumerator = auth->create_enumerator(auth); |
171 | while (enumerator->enumerate(enumerator, &rule, &config)) | |
172 | { | |
c8a07813 | 173 | if (rule == AUTH_RULE_IKE_SIGNATURE_SCHEME) |
1d94b795 | 174 | { |
54f8d092 TB |
175 | hash = hasher_from_signature_scheme(config->scheme, |
176 | config->params); | |
1d94b795 TB |
177 | if (hasher_algorithm_for_ikev2(hash)) |
178 | { | |
179 | algos->add(algos, hash); | |
180 | } | |
181 | } | |
182 | } | |
183 | enumerator->destroy(enumerator); | |
f6329cae | 184 | } |
1d94b795 | 185 | rounds->destroy(rounds); |
f6329cae | 186 | } |
f6329cae | 187 | |
1d94b795 | 188 | if (!algos->count(algos)) |
f6329cae | 189 | { |
1d94b795 TB |
190 | enumerator = lib->crypto->create_hasher_enumerator(lib->crypto); |
191 | while (enumerator->enumerate(enumerator, &hash, &plugin_name)) | |
192 | { | |
193 | if (hasher_algorithm_for_ikev2(hash)) | |
194 | { | |
195 | algos->add(algos, hash); | |
196 | } | |
197 | } | |
198 | enumerator->destroy(enumerator); | |
199 | } | |
200 | ||
201 | if (algos->count(algos)) | |
202 | { | |
203 | writer = bio_writer_create(0); | |
204 | enumerator = algos->create_enumerator(algos); | |
205 | while (enumerator->enumerate(enumerator, &hash)) | |
206 | { | |
207 | writer->write_uint16(writer, hash); | |
f2eb367a AS |
208 | |
209 | /* generate debug output */ | |
210 | written = snprintf(pos, len, " %N", hash_algorithm_short_names, | |
211 | hash); | |
212 | if (written > 0 && written < len) | |
213 | { | |
214 | pos += written; | |
215 | len -= written; | |
216 | } | |
1d94b795 TB |
217 | } |
218 | enumerator->destroy(enumerator); | |
f6329cae TB |
219 | message->add_notify(message, FALSE, SIGNATURE_HASH_ALGORITHMS, |
220 | writer->get_buf(writer)); | |
1d94b795 | 221 | writer->destroy(writer); |
f2eb367a AS |
222 | |
223 | *pos = '\0'; | |
224 | DBG2(DBG_CFG, "sending supported signature hash algorithms:%s", buf); | |
f6329cae | 225 | } |
1d94b795 | 226 | algos->destroy(algos); |
f6329cae TB |
227 | } |
228 | ||
229 | /** | |
230 | * Store algorithms supported by other peer | |
231 | */ | |
232 | static void handle_supported_hash_algorithms(private_ike_init_t *this, | |
233 | notify_payload_t *notify) | |
234 | { | |
235 | bio_reader_t *reader; | |
b12c53ce | 236 | uint16_t algo; |
f2eb367a AS |
237 | int written; |
238 | size_t len = BUF_LEN; | |
239 | char buf[len]; | |
240 | char *pos = buf; | |
f6329cae TB |
241 | bool added = FALSE; |
242 | ||
243 | reader = bio_reader_create(notify->get_notification_data(notify)); | |
244 | while (reader->remaining(reader) >= 2 && reader->read_uint16(reader, &algo)) | |
245 | { | |
246 | if (hasher_algorithm_for_ikev2(algo)) | |
247 | { | |
248 | this->keymat->add_hash_algorithm(this->keymat, algo); | |
249 | added = TRUE; | |
f2eb367a AS |
250 | |
251 | /* generate debug output */ | |
252 | written = snprintf(pos, len, " %N", hash_algorithm_short_names, | |
253 | algo); | |
254 | if (written > 0 && written < len) | |
255 | { | |
256 | pos += written; | |
257 | len -= written; | |
258 | } | |
f6329cae TB |
259 | } |
260 | } | |
261 | reader->destroy(reader); | |
262 | ||
f2eb367a AS |
263 | *pos = '\0'; |
264 | DBG2(DBG_CFG, "received supported signature hash algorithms:%s", buf); | |
265 | ||
f6329cae TB |
266 | if (added) |
267 | { | |
268 | this->ike_sa->enable_extension(this->ike_sa, EXT_SIGNATURE_AUTH); | |
269 | } | |
270 | } | |
271 | ||
600b1068 TB |
272 | /** |
273 | * Check whether to send a USE_PPK notify | |
274 | */ | |
275 | static bool send_use_ppk(private_ike_init_t *this) | |
276 | { | |
277 | peer_cfg_t *peer; | |
278 | enumerator_t *keys; | |
279 | shared_key_t *key; | |
280 | bool use_ppk = FALSE; | |
281 | ||
282 | if (this->initiator) | |
283 | { | |
284 | peer = this->ike_sa->get_peer_cfg(this->ike_sa); | |
285 | if (peer->get_ppk_id(peer)) | |
286 | { | |
287 | use_ppk = TRUE; | |
288 | } | |
289 | } | |
290 | else if (this->ike_sa->supports_extension(this->ike_sa, EXT_PPK)) | |
291 | { | |
292 | /* check if we have at least one PPK available */ | |
293 | keys = lib->credmgr->create_shared_enumerator(lib->credmgr, SHARED_PPK, | |
294 | NULL, NULL); | |
295 | if (keys->enumerate(keys, &key, NULL, NULL)) | |
296 | { | |
297 | use_ppk = TRUE; | |
298 | } | |
299 | keys->destroy(keys); | |
300 | } | |
301 | return use_ppk; | |
302 | } | |
303 | ||
c60c7694 MW |
304 | /** |
305 | * build the payloads for the message | |
306 | */ | |
520d58e0 | 307 | static bool build_payloads(private_ike_init_t *this, message_t *message) |
c60c7694 MW |
308 | { |
309 | sa_payload_t *sa_payload; | |
310 | ke_payload_t *ke_payload; | |
311 | nonce_payload_t *nonce_payload; | |
ff79020c | 312 | linked_list_t *proposal_list, *other_dh_groups; |
c60c7694 MW |
313 | ike_sa_id_t *id; |
314 | proposal_t *proposal; | |
e2630434 | 315 | enumerator_t *enumerator; |
054ee5e7 | 316 | ike_cfg_t *ike_cfg; |
7daf5226 | 317 | |
c60c7694 | 318 | id = this->ike_sa->get_id(this->ike_sa); |
7daf5226 | 319 | |
054ee5e7 | 320 | ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); |
c60c7694 MW |
321 | |
322 | if (this->initiator) | |
323 | { | |
054ee5e7 | 324 | proposal_list = ike_cfg->get_proposals(ike_cfg); |
ff79020c TB |
325 | other_dh_groups = linked_list_create(); |
326 | enumerator = proposal_list->create_enumerator(proposal_list); | |
327 | while (enumerator->enumerate(enumerator, (void**)&proposal)) | |
484a06bc | 328 | { |
c60c7694 | 329 | /* include SPI of new IKE_SA when we are rekeying */ |
ff79020c | 330 | if (this->old_sa) |
c60c7694 MW |
331 | { |
332 | proposal->set_spi(proposal, id->get_initiator_spi(id)); | |
333 | } | |
ff79020c TB |
334 | /* move the selected DH group to the front of the proposal */ |
335 | if (!proposal->promote_dh_group(proposal, this->dh_group)) | |
336 | { /* the proposal does not include the group, move to the back */ | |
337 | proposal_list->remove_at(proposal_list, enumerator); | |
338 | other_dh_groups->insert_last(other_dh_groups, proposal); | |
339 | } | |
c60c7694 | 340 | } |
ff79020c TB |
341 | enumerator->destroy(enumerator); |
342 | /* add proposals that don't contain the selected group */ | |
343 | enumerator = other_dh_groups->create_enumerator(other_dh_groups); | |
344 | while (enumerator->enumerate(enumerator, (void**)&proposal)) | |
345 | { /* no need to remove from the list as we destroy it anyway*/ | |
346 | proposal_list->insert_last(proposal_list, proposal); | |
347 | } | |
348 | enumerator->destroy(enumerator); | |
349 | other_dh_groups->destroy(other_dh_groups); | |
7daf5226 | 350 | |
e174e0d4 | 351 | sa_payload = sa_payload_create_from_proposals_v2(proposal_list); |
c60c7694 MW |
352 | proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy)); |
353 | } | |
354 | else | |
355 | { | |
356 | if (this->old_sa) | |
357 | { | |
358 | /* include SPI of new IKE_SA when we are rekeying */ | |
359 | this->proposal->set_spi(this->proposal, id->get_responder_spi(id)); | |
360 | } | |
e174e0d4 | 361 | sa_payload = sa_payload_create_from_proposal_v2(this->proposal); |
c60c7694 MW |
362 | } |
363 | message->add_payload(message, (payload_t*)sa_payload); | |
7daf5226 | 364 | |
520d58e0 MW |
365 | ke_payload = ke_payload_create_from_diffie_hellman(PLV2_KEY_EXCHANGE, |
366 | this->dh); | |
367 | if (!ke_payload) | |
368 | { | |
369 | DBG1(DBG_IKE, "creating KE payload failed"); | |
370 | return FALSE; | |
371 | } | |
e5e500c0 TB |
372 | nonce_payload = nonce_payload_create(PLV2_NONCE); |
373 | nonce_payload->set_nonce(nonce_payload, this->my_nonce); | |
7daf5226 | 374 | |
cc68e173 MW |
375 | if (this->old_sa) |
376 | { /* payload order differs if we are rekeying */ | |
377 | message->add_payload(message, (payload_t*)nonce_payload); | |
378 | message->add_payload(message, (payload_t*)ke_payload); | |
379 | } | |
380 | else | |
381 | { | |
382 | message->add_payload(message, (payload_t*)ke_payload); | |
383 | message->add_payload(message, (payload_t*)nonce_payload); | |
384 | } | |
34dc37f3 TB |
385 | |
386 | /* negotiate fragmentation if we are not rekeying */ | |
387 | if (!this->old_sa && | |
054ee5e7 | 388 | ike_cfg->fragmentation(ike_cfg) != FRAGMENTATION_NO) |
34dc37f3 TB |
389 | { |
390 | if (this->initiator || | |
391 | this->ike_sa->supports_extension(this->ike_sa, | |
392 | EXT_IKE_FRAGMENTATION)) | |
393 | { | |
394 | message->add_notify(message, FALSE, FRAGMENTATION_SUPPORTED, | |
395 | chunk_empty); | |
396 | } | |
397 | } | |
f6329cae | 398 | /* submit supported hash algorithms for signature authentication */ |
fff3576b | 399 | if (!this->old_sa && this->signature_authentication) |
f6329cae TB |
400 | { |
401 | if (this->initiator || | |
402 | this->ike_sa->supports_extension(this->ike_sa, | |
403 | EXT_SIGNATURE_AUTH)) | |
404 | { | |
1d94b795 | 405 | send_supported_hash_algorithms(this, message); |
f6329cae TB |
406 | } |
407 | } | |
10009b29 | 408 | /* notify other peer if we support redirection */ |
489d154e | 409 | if (!this->old_sa && this->initiator && this->follow_redirects) |
10009b29 | 410 | { |
6cde9875 TB |
411 | identification_t *gateway; |
412 | host_t *from; | |
413 | chunk_t data; | |
414 | ||
415 | from = this->ike_sa->get_redirected_from(this->ike_sa); | |
416 | if (from) | |
417 | { | |
418 | gateway = identification_create_from_sockaddr( | |
419 | from->get_sockaddr(from)); | |
420 | data = redirect_data_create(gateway, chunk_empty); | |
421 | message->add_notify(message, FALSE, REDIRECTED_FROM, data); | |
422 | chunk_free(&data); | |
423 | gateway->destroy(gateway); | |
424 | } | |
425 | else | |
426 | { | |
427 | message->add_notify(message, FALSE, REDIRECT_SUPPORTED, | |
428 | chunk_empty); | |
429 | } | |
10009b29 | 430 | } |
600b1068 TB |
431 | /* notify the peer if we want to use/support PPK */ |
432 | if (!this->old_sa && send_use_ppk(this)) | |
433 | { | |
434 | message->add_notify(message, FALSE, USE_PPK, chunk_empty); | |
435 | } | |
93104d0f TB |
436 | /* notify the peer if we accept childless IKE_SAs */ |
437 | if (!this->old_sa && !this->initiator && | |
438 | ike_cfg->childless(ike_cfg) != CHILDLESS_NEVER) | |
439 | { | |
440 | message->add_notify(message, FALSE, CHILDLESS_IKEV2_SUPPORTED, | |
441 | chunk_empty); | |
442 | } | |
520d58e0 | 443 | return TRUE; |
c60c7694 MW |
444 | } |
445 | ||
054ee5e7 TB |
446 | /** |
447 | * Process the SA payload and select a proposal | |
448 | */ | |
449 | static void process_sa_payload(private_ike_init_t *this, message_t *message, | |
450 | sa_payload_t *sa_payload) | |
451 | { | |
452 | ike_cfg_t *ike_cfg, *cfg, *alt_cfg = NULL; | |
453 | enumerator_t *enumerator; | |
454 | linked_list_t *proposal_list; | |
455 | host_t *me, *other; | |
f930b732 | 456 | proposal_selection_flag_t flags = 0; |
054ee5e7 TB |
457 | |
458 | ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); | |
459 | ||
460 | proposal_list = sa_payload->get_proposals(sa_payload); | |
05e373ae TE |
461 | if (!this->ike_sa->supports_extension(this->ike_sa, EXT_STRONGSWAN) && |
462 | !lib->settings->get_bool(lib->settings, "%s.accept_private_algs", | |
463 | FALSE, lib->ns)) | |
f930b732 | 464 | { |
a2cb2c9c | 465 | flags |= PROPOSAL_SKIP_PRIVATE; |
f930b732 | 466 | } |
c9599d41 TB |
467 | if (!lib->settings->get_bool(lib->settings, |
468 | "%s.prefer_configured_proposals", TRUE, lib->ns)) | |
f930b732 | 469 | { |
c9599d41 | 470 | flags |= PROPOSAL_PREFER_SUPPLIED; |
f930b732 TE |
471 | } |
472 | this->proposal = ike_cfg->select_proposal(ike_cfg, proposal_list, flags); | |
054ee5e7 TB |
473 | if (!this->proposal) |
474 | { | |
475 | if (!this->initiator && !this->old_sa) | |
476 | { | |
477 | me = message->get_destination(message); | |
478 | other = message->get_source(message); | |
479 | enumerator = charon->backends->create_ike_cfg_enumerator( | |
480 | charon->backends, me, other, IKEV2); | |
481 | while (enumerator->enumerate(enumerator, &cfg)) | |
482 | { | |
483 | if (ike_cfg == cfg) | |
484 | { /* already tried and failed */ | |
485 | continue; | |
486 | } | |
487 | DBG1(DBG_IKE, "no matching proposal found, trying alternative " | |
488 | "config"); | |
489 | this->proposal = cfg->select_proposal(cfg, proposal_list, | |
f930b732 | 490 | flags); |
054ee5e7 TB |
491 | if (this->proposal) |
492 | { | |
493 | alt_cfg = cfg->get_ref(cfg); | |
494 | break; | |
495 | } | |
496 | } | |
497 | enumerator->destroy(enumerator); | |
498 | } | |
499 | if (alt_cfg) | |
500 | { | |
501 | this->ike_sa->set_ike_cfg(this->ike_sa, alt_cfg); | |
502 | alt_cfg->destroy(alt_cfg); | |
503 | } | |
504 | else | |
505 | { | |
506 | charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_IKE, | |
507 | proposal_list); | |
508 | } | |
509 | } | |
510 | proposal_list->destroy_offset(proposal_list, | |
511 | offsetof(proposal_t, destroy)); | |
512 | } | |
513 | ||
c60c7694 MW |
514 | /** |
515 | * Read payloads from message | |
516 | */ | |
517 | static void process_payloads(private_ike_init_t *this, message_t *message) | |
518 | { | |
a44bb934 | 519 | enumerator_t *enumerator; |
c60c7694 | 520 | payload_t *payload; |
691d00f1 | 521 | ke_payload_t *ke_payload = NULL; |
7daf5226 | 522 | |
a44bb934 MW |
523 | enumerator = message->create_payload_enumerator(message); |
524 | while (enumerator->enumerate(enumerator, &payload)) | |
c60c7694 MW |
525 | { |
526 | switch (payload->get_type(payload)) | |
527 | { | |
3ecfc83c | 528 | case PLV2_SECURITY_ASSOCIATION: |
c60c7694 | 529 | { |
054ee5e7 | 530 | process_sa_payload(this, message, (sa_payload_t*)payload); |
c60c7694 MW |
531 | break; |
532 | } | |
3ecfc83c | 533 | case PLV2_KEY_EXCHANGE: |
c60c7694 | 534 | { |
691d00f1 | 535 | ke_payload = (ke_payload_t*)payload; |
7daf5226 | 536 | |
1fd5383e | 537 | this->dh_group = ke_payload->get_dh_group_number(ke_payload); |
c60c7694 MW |
538 | break; |
539 | } | |
3ecfc83c | 540 | case PLV2_NONCE: |
c60c7694 MW |
541 | { |
542 | nonce_payload_t *nonce_payload = (nonce_payload_t*)payload; | |
125aaf1a | 543 | |
c60c7694 MW |
544 | this->other_nonce = nonce_payload->get_nonce(nonce_payload); |
545 | break; | |
546 | } | |
34dc37f3 TB |
547 | case PLV2_NOTIFY: |
548 | { | |
549 | notify_payload_t *notify = (notify_payload_t*)payload; | |
550 | ||
f6329cae | 551 | switch (notify->get_notify_type(notify)) |
34dc37f3 | 552 | { |
f6329cae TB |
553 | case FRAGMENTATION_SUPPORTED: |
554 | this->ike_sa->enable_extension(this->ike_sa, | |
555 | EXT_IKE_FRAGMENTATION); | |
556 | break; | |
557 | case SIGNATURE_HASH_ALGORITHMS: | |
fff3576b TB |
558 | if (this->signature_authentication) |
559 | { | |
560 | handle_supported_hash_algorithms(this, notify); | |
561 | } | |
f6329cae | 562 | break; |
600b1068 TB |
563 | case USE_PPK: |
564 | if (!this->old_sa) | |
565 | { | |
566 | this->ike_sa->enable_extension(this->ike_sa, | |
567 | EXT_PPK); | |
568 | } | |
569 | break; | |
3d074bce TB |
570 | case REDIRECTED_FROM: |
571 | { | |
572 | identification_t *gateway; | |
573 | chunk_t data; | |
574 | ||
575 | data = notify->get_notification_data(notify); | |
576 | gateway = redirect_data_parse(data, NULL); | |
577 | if (!gateway) | |
578 | { | |
579 | DBG1(DBG_IKE, "received invalid REDIRECTED_FROM " | |
580 | "notify, ignored"); | |
581 | break; | |
582 | } | |
583 | DBG1(DBG_IKE, "client got redirected from %Y", gateway); | |
584 | gateway->destroy(gateway); | |
585 | /* fall-through */ | |
586 | } | |
099c0b12 | 587 | case REDIRECT_SUPPORTED: |
9282bc39 TB |
588 | if (!this->old_sa) |
589 | { | |
590 | this->ike_sa->enable_extension(this->ike_sa, | |
591 | EXT_IKE_REDIRECTION); | |
592 | } | |
099c0b12 | 593 | break; |
93104d0f TB |
594 | case CHILDLESS_IKEV2_SUPPORTED: |
595 | if (this->initiator && !this->old_sa) | |
596 | { | |
597 | this->ike_sa->enable_extension(this->ike_sa, | |
598 | EXT_IKE_CHILDLESS); | |
599 | } | |
600 | break; | |
f6329cae TB |
601 | default: |
602 | /* other notifies are handled elsewhere */ | |
603 | break; | |
34dc37f3 | 604 | } |
f6329cae | 605 | |
34dc37f3 | 606 | } |
c60c7694 MW |
607 | default: |
608 | break; | |
609 | } | |
610 | } | |
a44bb934 | 611 | enumerator->destroy(enumerator); |
691d00f1 | 612 | |
fd1662cd TB |
613 | if (this->proposal) |
614 | { | |
615 | this->ike_sa->set_proposal(this->ike_sa, this->proposal); | |
616 | } | |
617 | ||
691d00f1 TB |
618 | if (ke_payload && this->proposal && |
619 | this->proposal->has_dh_group(this->proposal, this->dh_group)) | |
620 | { | |
621 | if (!this->initiator) | |
622 | { | |
623 | this->dh = this->keymat->keymat.create_dh( | |
624 | &this->keymat->keymat, this->dh_group); | |
625 | } | |
bd371590 TB |
626 | else if (this->dh) |
627 | { | |
628 | this->dh_failed = this->dh->get_dh_group(this->dh) != this->dh_group; | |
629 | } | |
630 | if (this->dh && !this->dh_failed) | |
691d00f1 | 631 | { |
a777155f | 632 | this->dh_failed = !this->dh->set_other_public_value(this->dh, |
691d00f1 TB |
633 | ke_payload->get_key_exchange_data(ke_payload)); |
634 | } | |
635 | } | |
c60c7694 MW |
636 | } |
637 | ||
c73694e7 AS |
638 | METHOD(task_t, build_i, status_t, |
639 | private_ike_init_t *this, message_t *message) | |
c60c7694 | 640 | { |
054ee5e7 TB |
641 | ike_cfg_t *ike_cfg; |
642 | ||
643 | ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); | |
644 | ||
7790ab0f | 645 | DBG0(DBG_IKE, "initiating IKE_SA %s[%d] to %H", |
a985db3f MW |
646 | this->ike_sa->get_name(this->ike_sa), |
647 | this->ike_sa->get_unique_id(this->ike_sa), | |
648 | this->ike_sa->get_other_host(this->ike_sa)); | |
c60c7694 | 649 | this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); |
7daf5226 | 650 | |
f12d8cf7 | 651 | if (this->retry >= MAX_RETRIES) |
a6bdc731 | 652 | { |
a985db3f | 653 | DBG1(DBG_IKE, "giving up after %d retries", MAX_RETRIES); |
a6bdc731 MW |
654 | return FAILED; |
655 | } | |
7daf5226 | 656 | |
727615ee | 657 | /* if we are retrying after an INVALID_KE_PAYLOAD we already have one */ |
1fd5383e | 658 | if (!this->dh) |
c60c7694 | 659 | { |
576d9b90 TB |
660 | if (this->old_sa && lib->settings->get_bool(lib->settings, |
661 | "%s.prefer_previous_dh_group", TRUE, lib->ns)) | |
727615ee TB |
662 | { /* reuse the DH group we used for the old IKE_SA when rekeying */ |
663 | proposal_t *proposal; | |
664 | uint16_t dh_group; | |
665 | ||
666 | proposal = this->old_sa->get_proposal(this->old_sa); | |
667 | if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, | |
668 | &dh_group, NULL)) | |
669 | { | |
670 | this->dh_group = dh_group; | |
671 | } | |
672 | else | |
673 | { /* this shouldn't happen, but let's be safe */ | |
054ee5e7 | 674 | this->dh_group = ike_cfg->get_dh_group(ike_cfg); |
727615ee TB |
675 | } |
676 | } | |
677 | else | |
678 | { | |
054ee5e7 | 679 | this->dh_group = ike_cfg->get_dh_group(ike_cfg); |
727615ee | 680 | } |
a0563846 TB |
681 | this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, |
682 | this->dh_group); | |
a64cc8f7 | 683 | if (!this->dh) |
c60c7694 | 684 | { |
a985db3f | 685 | DBG1(DBG_IKE, "configured DH group %N not supported", |
c60c7694 MW |
686 | diffie_hellman_group_names, this->dh_group); |
687 | return FAILED; | |
688 | } | |
689 | } | |
18242f62 TB |
690 | else if (this->dh->get_dh_group(this->dh) != this->dh_group) |
691 | { /* reset DH instance if group changed (INVALID_KE_PAYLOAD) */ | |
692 | this->dh->destroy(this->dh); | |
693 | this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, | |
694 | this->dh_group); | |
695 | if (!this->dh) | |
696 | { | |
697 | DBG1(DBG_IKE, "requested DH group %N not supported", | |
698 | diffie_hellman_group_names, this->dh_group); | |
699 | return FAILED; | |
700 | } | |
701 | } | |
7daf5226 | 702 | |
e5a7f1cd MW |
703 | /* generate nonce only when we are trying the first time */ |
704 | if (this->my_nonce.ptr == NULL) | |
c60c7694 | 705 | { |
59565ebf | 706 | if (!generate_nonce(this)) |
605985d1 | 707 | { |
605985d1 RB |
708 | return FAILED; |
709 | } | |
e5a7f1cd | 710 | } |
7daf5226 | 711 | |
e5a7f1cd MW |
712 | if (this->cookie.ptr) |
713 | { | |
714 | message->add_notify(message, FALSE, COOKIE, this->cookie); | |
c60c7694 | 715 | } |
7daf5226 | 716 | |
520d58e0 MW |
717 | if (!build_payloads(this, message)) |
718 | { | |
719 | return FAILED; | |
720 | } | |
9c2a905d TB |
721 | |
722 | #ifdef ME | |
723 | { | |
724 | chunk_t connect_id = this->ike_sa->get_connect_id(this->ike_sa); | |
725 | if (connect_id.ptr) | |
726 | { | |
727 | message->add_notify(message, FALSE, ME_CONNECTID, connect_id); | |
728 | } | |
729 | } | |
730 | #endif /* ME */ | |
7daf5226 | 731 | |
c60c7694 MW |
732 | return NEED_MORE; |
733 | } | |
734 | ||
c73694e7 AS |
735 | METHOD(task_t, process_r, status_t, |
736 | private_ike_init_t *this, message_t *message) | |
484a06bc | 737 | { |
7790ab0f | 738 | DBG0(DBG_IKE, "%H is initiating an IKE_SA", message->get_source(message)); |
c60c7694 MW |
739 | this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); |
740 | ||
59565ebf | 741 | if (!generate_nonce(this)) |
605985d1 | 742 | { |
605985d1 RB |
743 | return FAILED; |
744 | } | |
7daf5226 | 745 | |
9c2a905d TB |
746 | #ifdef ME |
747 | { | |
a20e9874 TB |
748 | notify_payload_t *notify = message->get_notify(message, ME_CONNECTID); |
749 | if (notify) | |
9c2a905d | 750 | { |
a20e9874 TB |
751 | chunk_t connect_id = notify->get_notification_data(notify); |
752 | DBG2(DBG_IKE, "received ME_CONNECTID %#B", &connect_id); | |
9c2a905d | 753 | charon->connect_manager->stop_checks(charon->connect_manager, |
a20e9874 | 754 | connect_id); |
9c2a905d TB |
755 | } |
756 | } | |
757 | #endif /* ME */ | |
7daf5226 | 758 | |
c60c7694 | 759 | process_payloads(this, message); |
7daf5226 | 760 | |
c60c7694 MW |
761 | return NEED_MORE; |
762 | } | |
763 | ||
764 | /** | |
ddef4552 | 765 | * Derive the keymat for the IKE_SA |
c60c7694 | 766 | */ |
ddef4552 MW |
767 | static bool derive_keys(private_ike_init_t *this, |
768 | chunk_t nonce_i, chunk_t nonce_r) | |
c60c7694 | 769 | { |
a0563846 | 770 | keymat_v2_t *old_keymat; |
ddef4552 MW |
771 | pseudo_random_function_t prf_alg = PRF_UNDEFINED; |
772 | chunk_t skd = chunk_empty; | |
6a4ff35c | 773 | ike_sa_id_t *id; |
7daf5226 | 774 | |
ddef4552 MW |
775 | id = this->ike_sa->get_id(this->ike_sa); |
776 | if (this->old_sa) | |
777 | { | |
778 | /* rekeying: Include old SKd, use old PRF, apply SPI */ | |
a0563846 | 779 | old_keymat = (keymat_v2_t*)this->old_sa->get_keymat(this->old_sa); |
ddef4552 MW |
780 | prf_alg = old_keymat->get_skd(old_keymat, &skd); |
781 | if (this->initiator) | |
782 | { | |
783 | id->set_responder_spi(id, this->proposal->get_spi(this->proposal)); | |
784 | } | |
785 | else | |
786 | { | |
787 | id->set_initiator_spi(id, this->proposal->get_spi(this->proposal)); | |
788 | } | |
789 | } | |
790 | if (!this->keymat->derive_ike_keys(this->keymat, this->proposal, this->dh, | |
791 | nonce_i, nonce_r, id, prf_alg, skd)) | |
792 | { | |
793 | return FALSE; | |
794 | } | |
23f9e7a1 | 795 | charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, chunk_empty, |
eed20c21 | 796 | nonce_i, nonce_r, this->old_sa, NULL, AUTH_NONE); |
ddef4552 MW |
797 | return TRUE; |
798 | } | |
799 | ||
c73694e7 AS |
800 | METHOD(task_t, build_r, status_t, |
801 | private_ike_init_t *this, message_t *message) | |
ddef4552 | 802 | { |
dd2b335b TB |
803 | identification_t *gateway; |
804 | ||
c60c7694 MW |
805 | /* check if we have everything we need */ |
806 | if (this->proposal == NULL || | |
807 | this->other_nonce.len == 0 || this->my_nonce.len == 0) | |
808 | { | |
2ad1df95 | 809 | DBG1(DBG_IKE, "received proposals unacceptable"); |
c60c7694 MW |
810 | message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); |
811 | return FAILED; | |
812 | } | |
7daf5226 | 813 | |
dd2b335b | 814 | /* check if we'd have to redirect the client */ |
9282bc39 TB |
815 | if (!this->old_sa && |
816 | this->ike_sa->supports_extension(this->ike_sa, EXT_IKE_REDIRECTION) && | |
dd2b335b TB |
817 | charon->redirect->redirect_on_init(charon->redirect, this->ike_sa, |
818 | &gateway)) | |
819 | { | |
820 | chunk_t data; | |
821 | ||
822 | DBG1(DBG_IKE, "redirecting peer to %Y", gateway); | |
823 | data = redirect_data_create(gateway, this->other_nonce); | |
824 | message->add_notify(message, TRUE, REDIRECT, data); | |
825 | gateway->destroy(gateway); | |
826 | chunk_free(&data); | |
827 | return FAILED; | |
828 | } | |
829 | ||
1fd5383e | 830 | if (this->dh == NULL || |
6a4ff35c | 831 | !this->proposal->has_dh_group(this->proposal, this->dh_group)) |
c60c7694 | 832 | { |
b12c53ce | 833 | uint16_t group; |
7daf5226 | 834 | |
1fd5383e | 835 | if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, |
3c7e72f5 | 836 | &group, NULL)) |
1fd5383e | 837 | { |
2ad1df95 | 838 | DBG1(DBG_IKE, "DH group %N unacceptable, requesting %N", |
a985db3f MW |
839 | diffie_hellman_group_names, this->dh_group, |
840 | diffie_hellman_group_names, group); | |
1fd5383e MW |
841 | this->dh_group = group; |
842 | group = htons(group); | |
843 | message->add_notify(message, FALSE, INVALID_KE_PAYLOAD, | |
844 | chunk_from_thing(group)); | |
845 | } | |
846 | else | |
847 | { | |
a985db3f | 848 | DBG1(DBG_IKE, "no acceptable proposal found"); |
fcca7d29 | 849 | message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); |
1fd5383e | 850 | } |
c60c7694 MW |
851 | return FAILED; |
852 | } | |
7daf5226 | 853 | |
a777155f MW |
854 | if (this->dh_failed) |
855 | { | |
856 | DBG1(DBG_IKE, "applying DH public value failed"); | |
857 | message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); | |
858 | return FAILED; | |
859 | } | |
860 | ||
ddef4552 | 861 | if (!derive_keys(this, this->other_nonce, this->my_nonce)) |
c60c7694 | 862 | { |
a985db3f | 863 | DBG1(DBG_IKE, "key derivation failed"); |
c60c7694 MW |
864 | message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); |
865 | return FAILED; | |
866 | } | |
520d58e0 MW |
867 | if (!build_payloads(this, message)) |
868 | { | |
42431690 | 869 | message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); |
520d58e0 MW |
870 | return FAILED; |
871 | } | |
c60c7694 MW |
872 | return SUCCESS; |
873 | } | |
874 | ||
00080d2b MW |
875 | /** |
876 | * Raise alerts for received notify errors | |
877 | */ | |
878 | static void raise_alerts(private_ike_init_t *this, notify_type_t type) | |
879 | { | |
054ee5e7 | 880 | ike_cfg_t *ike_cfg; |
00080d2b MW |
881 | linked_list_t *list; |
882 | ||
883 | switch (type) | |
884 | { | |
885 | case NO_PROPOSAL_CHOSEN: | |
054ee5e7 TB |
886 | ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); |
887 | list = ike_cfg->get_proposals(ike_cfg); | |
00080d2b MW |
888 | charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_IKE, list); |
889 | list->destroy_offset(list, offsetof(proposal_t, destroy)); | |
890 | break; | |
891 | default: | |
892 | break; | |
893 | } | |
894 | } | |
895 | ||
47701e11 TB |
896 | METHOD(task_t, pre_process_i, status_t, |
897 | private_ike_init_t *this, message_t *message) | |
898 | { | |
899 | enumerator_t *enumerator; | |
900 | payload_t *payload; | |
901 | ||
902 | /* check for erroneous notifies */ | |
903 | enumerator = message->create_payload_enumerator(message); | |
904 | while (enumerator->enumerate(enumerator, &payload)) | |
905 | { | |
906 | if (payload->get_type(payload) == PLV2_NOTIFY) | |
907 | { | |
908 | notify_payload_t *notify = (notify_payload_t*)payload; | |
909 | notify_type_t type = notify->get_notify_type(notify); | |
910 | ||
911 | switch (type) | |
912 | { | |
01f462f0 TB |
913 | case COOKIE: |
914 | { | |
915 | chunk_t cookie; | |
916 | ||
917 | cookie = notify->get_notification_data(notify); | |
918 | if (chunk_equals(cookie, this->cookie)) | |
919 | { | |
920 | DBG1(DBG_IKE, "ignore response with duplicate COOKIE " | |
921 | "notify"); | |
922 | enumerator->destroy(enumerator); | |
923 | return FAILED; | |
924 | } | |
925 | break; | |
926 | } | |
47701e11 TB |
927 | case REDIRECT: |
928 | { | |
929 | identification_t *gateway; | |
930 | chunk_t data, nonce = chunk_empty; | |
931 | status_t status = SUCCESS; | |
932 | ||
933 | if (this->old_sa) | |
934 | { | |
935 | break; | |
936 | } | |
937 | data = notify->get_notification_data(notify); | |
938 | gateway = redirect_data_parse(data, &nonce); | |
939 | if (!gateway || !chunk_equals(nonce, this->my_nonce)) | |
940 | { | |
941 | DBG1(DBG_IKE, "received invalid REDIRECT notify"); | |
942 | status = FAILED; | |
943 | } | |
944 | DESTROY_IF(gateway); | |
945 | chunk_free(&nonce); | |
946 | enumerator->destroy(enumerator); | |
947 | return status; | |
948 | } | |
949 | default: | |
950 | break; | |
951 | } | |
952 | } | |
953 | } | |
954 | enumerator->destroy(enumerator); | |
955 | return SUCCESS; | |
956 | } | |
957 | ||
c73694e7 AS |
958 | METHOD(task_t, process_i, status_t, |
959 | private_ike_init_t *this, message_t *message) | |
c60c7694 | 960 | { |
a44bb934 | 961 | enumerator_t *enumerator; |
c60c7694 | 962 | payload_t *payload; |
7daf5226 | 963 | |
ef33a4ab | 964 | /* check for erroneous notifies */ |
a44bb934 MW |
965 | enumerator = message->create_payload_enumerator(message); |
966 | while (enumerator->enumerate(enumerator, &payload)) | |
c60c7694 | 967 | { |
3ecfc83c | 968 | if (payload->get_type(payload) == PLV2_NOTIFY) |
c60c7694 MW |
969 | { |
970 | notify_payload_t *notify = (notify_payload_t*)payload; | |
971 | notify_type_t type = notify->get_notify_type(notify); | |
7daf5226 | 972 | |
c60c7694 MW |
973 | switch (type) |
974 | { | |
975 | case INVALID_KE_PAYLOAD: | |
976 | { | |
977 | chunk_t data; | |
1fd5383e | 978 | diffie_hellman_group_t bad_group; |
7daf5226 | 979 | |
1fd5383e | 980 | bad_group = this->dh_group; |
c60c7694 | 981 | data = notify->get_notification_data(notify); |
b12c53ce | 982 | this->dh_group = ntohs(*((uint16_t*)data.ptr)); |
1fd5383e MW |
983 | DBG1(DBG_IKE, "peer didn't accept DH group %N, " |
984 | "it requested %N", diffie_hellman_group_names, | |
985 | bad_group, diffie_hellman_group_names, this->dh_group); | |
7daf5226 | 986 | |
1fd5383e MW |
987 | if (this->old_sa == NULL) |
988 | { /* reset the IKE_SA if we are not rekeying */ | |
c3539961 | 989 | this->ike_sa->reset(this->ike_sa, FALSE); |
c60c7694 | 990 | } |
7daf5226 | 991 | |
a44bb934 | 992 | enumerator->destroy(enumerator); |
f12d8cf7 | 993 | this->retry++; |
c60c7694 MW |
994 | return NEED_MORE; |
995 | } | |
e5a7f1cd MW |
996 | case NAT_DETECTION_SOURCE_IP: |
997 | case NAT_DETECTION_DESTINATION_IP: | |
998 | /* skip, handled in ike_natd_t */ | |
999 | break; | |
a44bb934 MW |
1000 | case MULTIPLE_AUTH_SUPPORTED: |
1001 | /* handled in ike_auth_t */ | |
1002 | break; | |
e5a7f1cd MW |
1003 | case COOKIE: |
1004 | { | |
a6bdc731 | 1005 | chunk_free(&this->cookie); |
e5a7f1cd | 1006 | this->cookie = chunk_clone(notify->get_notification_data(notify)); |
c3539961 | 1007 | this->ike_sa->reset(this->ike_sa, FALSE); |
a44bb934 | 1008 | enumerator->destroy(enumerator); |
196b28a4 | 1009 | DBG2(DBG_IKE, "received %N notify", notify_type_names, type); |
f12d8cf7 | 1010 | this->retry++; |
e5a7f1cd MW |
1011 | return NEED_MORE; |
1012 | } | |
c126ddd0 TB |
1013 | case REDIRECT: |
1014 | { | |
1015 | identification_t *gateway; | |
1016 | chunk_t data, nonce = chunk_empty; | |
1017 | status_t status = FAILED; | |
1018 | ||
9282bc39 TB |
1019 | if (this->old_sa) |
1020 | { | |
1021 | DBG1(DBG_IKE, "received REDIRECT notify during rekeying" | |
1022 | ", ignored"); | |
1023 | break; | |
1024 | } | |
c126ddd0 TB |
1025 | data = notify->get_notification_data(notify); |
1026 | gateway = redirect_data_parse(data, &nonce); | |
47701e11 | 1027 | if (this->ike_sa->handle_redirect(this->ike_sa, gateway)) |
c126ddd0 TB |
1028 | { |
1029 | status = NEED_MORE; | |
1030 | } | |
1031 | DESTROY_IF(gateway); | |
1032 | chunk_free(&nonce); | |
47701e11 | 1033 | enumerator->destroy(enumerator); |
c126ddd0 TB |
1034 | return status; |
1035 | } | |
c60c7694 MW |
1036 | default: |
1037 | { | |
30d8e8d0 | 1038 | if (type <= 16383) |
c60c7694 | 1039 | { |
a985db3f | 1040 | DBG1(DBG_IKE, "received %N notify error", |
c60c7694 | 1041 | notify_type_names, type); |
a44bb934 | 1042 | enumerator->destroy(enumerator); |
00080d2b | 1043 | raise_alerts(this, type); |
484a06bc | 1044 | return FAILED; |
c60c7694 | 1045 | } |
196b28a4 | 1046 | DBG2(DBG_IKE, "received %N notify", |
e5a7f1cd MW |
1047 | notify_type_names, type); |
1048 | break; | |
c60c7694 MW |
1049 | } |
1050 | } | |
1051 | } | |
1052 | } | |
a44bb934 | 1053 | enumerator->destroy(enumerator); |
7daf5226 | 1054 | |
c60c7694 MW |
1055 | process_payloads(this, message); |
1056 | ||
1057 | /* check if we have everything */ | |
1058 | if (this->proposal == NULL || | |
1059 | this->other_nonce.len == 0 || this->my_nonce.len == 0) | |
1060 | { | |
a985db3f | 1061 | DBG1(DBG_IKE, "peers proposal selection invalid"); |
c60c7694 MW |
1062 | return FAILED; |
1063 | } | |
7daf5226 | 1064 | |
1fd5383e | 1065 | if (this->dh == NULL || |
6a4ff35c | 1066 | !this->proposal->has_dh_group(this->proposal, this->dh_group)) |
c60c7694 | 1067 | { |
a985db3f | 1068 | DBG1(DBG_IKE, "peer DH group selection invalid"); |
c60c7694 MW |
1069 | return FAILED; |
1070 | } | |
7daf5226 | 1071 | |
a777155f MW |
1072 | if (this->dh_failed) |
1073 | { | |
1074 | DBG1(DBG_IKE, "applying DH public value failed"); | |
1075 | return FAILED; | |
1076 | } | |
1077 | ||
ddef4552 | 1078 | if (!derive_keys(this, this->my_nonce, this->other_nonce)) |
c60c7694 | 1079 | { |
a985db3f | 1080 | DBG1(DBG_IKE, "key derivation failed"); |
c60c7694 MW |
1081 | return FAILED; |
1082 | } | |
1083 | return SUCCESS; | |
1084 | } | |
1085 | ||
c73694e7 AS |
1086 | METHOD(task_t, get_type, task_type_t, |
1087 | private_ike_init_t *this) | |
c60c7694 | 1088 | { |
a09972df | 1089 | return TASK_IKE_INIT; |
c60c7694 MW |
1090 | } |
1091 | ||
c73694e7 AS |
1092 | METHOD(task_t, migrate, void, |
1093 | private_ike_init_t *this, ike_sa_t *ike_sa) | |
c60c7694 MW |
1094 | { |
1095 | DESTROY_IF(this->proposal); | |
c60c7694 | 1096 | chunk_free(&this->other_nonce); |
7daf5226 | 1097 | |
c60c7694 | 1098 | this->ike_sa = ike_sa; |
a0563846 | 1099 | this->keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa); |
c60c7694 | 1100 | this->proposal = NULL; |
a777155f | 1101 | this->dh_failed = FALSE; |
c60c7694 MW |
1102 | } |
1103 | ||
c73694e7 AS |
1104 | METHOD(task_t, destroy, void, |
1105 | private_ike_init_t *this) | |
c60c7694 | 1106 | { |
a64cc8f7 | 1107 | DESTROY_IF(this->dh); |
c60c7694 | 1108 | DESTROY_IF(this->proposal); |
0b308faf | 1109 | DESTROY_IF(this->nonceg); |
c60c7694 MW |
1110 | chunk_free(&this->my_nonce); |
1111 | chunk_free(&this->other_nonce); | |
e5a7f1cd | 1112 | chunk_free(&this->cookie); |
c60c7694 MW |
1113 | free(this); |
1114 | } | |
1115 | ||
c73694e7 AS |
1116 | METHOD(ike_init_t, get_lower_nonce, chunk_t, |
1117 | private_ike_init_t *this) | |
1118 | { | |
1119 | if (memcmp(this->my_nonce.ptr, this->other_nonce.ptr, | |
1120 | min(this->my_nonce.len, this->other_nonce.len)) < 0) | |
1121 | { | |
1122 | return this->my_nonce; | |
1123 | } | |
1124 | else | |
1125 | { | |
1126 | return this->other_nonce; | |
1127 | } | |
1128 | } | |
1129 | ||
c60c7694 MW |
1130 | /* |
1131 | * Described in header. | |
1132 | */ | |
1133 | ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa) | |
1134 | { | |
c73694e7 AS |
1135 | private_ike_init_t *this; |
1136 | ||
1137 | INIT(this, | |
1138 | .public = { | |
1139 | .task = { | |
1140 | .get_type = _get_type, | |
1141 | .migrate = _migrate, | |
1142 | .destroy = _destroy, | |
1143 | }, | |
1144 | .get_lower_nonce = _get_lower_nonce, | |
1145 | }, | |
1146 | .ike_sa = ike_sa, | |
1147 | .initiator = initiator, | |
1148 | .dh_group = MODP_NONE, | |
a0563846 | 1149 | .keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa), |
c73694e7 | 1150 | .old_sa = old_sa, |
fff3576b TB |
1151 | .signature_authentication = lib->settings->get_bool(lib->settings, |
1152 | "%s.signature_authentication", TRUE, lib->ns), | |
489d154e TB |
1153 | .follow_redirects = lib->settings->get_bool(lib->settings, |
1154 | "%s.follow_redirects", TRUE, lib->ns), | |
c73694e7 | 1155 | ); |
0b308faf | 1156 | this->nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat); |
0b308faf | 1157 | |
c60c7694 MW |
1158 | if (initiator) |
1159 | { | |
c73694e7 AS |
1160 | this->public.task.build = _build_i; |
1161 | this->public.task.process = _process_i; | |
47701e11 | 1162 | this->public.task.pre_process = _pre_process_i; |
c60c7694 MW |
1163 | } |
1164 | else | |
1165 | { | |
c73694e7 AS |
1166 | this->public.task.build = _build_r; |
1167 | this->public.task.process = _process_r; | |
c60c7694 | 1168 | } |
c60c7694 MW |
1169 | return &this->public; |
1170 | } |