]>
Commit | Line | Data |
---|---|---|
c60c7694 | 1 | /* |
f6329cae | 2 | * Copyright (C) 2008-2015 Tobias Brunner |
6a4ff35c | 3 | * Copyright (C) 2005-2008 Martin Willi |
c60c7694 MW |
4 | * Copyright (C) 2005 Jan Hutter |
5 | * Hochschule fuer Technik Rapperswil | |
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 | 57 | /** |
e0fe7651 | 58 | * IKE config to establish |
c60c7694 | 59 | */ |
e0fe7651 | 60 | ike_cfg_t *config; |
7daf5226 | 61 | |
c60c7694 MW |
62 | /** |
63 | * diffie hellman group to use | |
64 | */ | |
65 | diffie_hellman_group_t dh_group; | |
7daf5226 | 66 | |
c60c7694 | 67 | /** |
6a4ff35c | 68 | * diffie hellman key exchange |
c60c7694 | 69 | */ |
1fd5383e | 70 | diffie_hellman_t *dh; |
7daf5226 | 71 | |
a777155f MW |
72 | /** |
73 | * Applying DH public value failed? | |
74 | */ | |
75 | bool dh_failed; | |
76 | ||
6a4ff35c MW |
77 | /** |
78 | * Keymat derivation (from IKE_SA) | |
79 | */ | |
a0563846 | 80 | keymat_v2_t *keymat; |
7daf5226 | 81 | |
c60c7694 MW |
82 | /** |
83 | * nonce chosen by us | |
84 | */ | |
85 | chunk_t my_nonce; | |
7daf5226 | 86 | |
c60c7694 MW |
87 | /** |
88 | * nonce chosen by peer | |
89 | */ | |
90 | chunk_t other_nonce; | |
7daf5226 | 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; | |
c60c7694 MW |
116 | }; |
117 | ||
f6329cae | 118 | /** |
1d94b795 TB |
119 | * Notify the peer about the hash algorithms we support or expect, |
120 | * as per RFC 7427 | |
f6329cae | 121 | */ |
1d94b795 TB |
122 | static void send_supported_hash_algorithms(private_ike_init_t *this, |
123 | message_t *message) | |
f6329cae | 124 | { |
1d94b795 TB |
125 | hash_algorithm_set_t *algos; |
126 | enumerator_t *enumerator, *rounds; | |
f6329cae TB |
127 | bio_writer_t *writer; |
128 | hash_algorithm_t hash; | |
1d94b795 TB |
129 | peer_cfg_t *peer; |
130 | auth_cfg_t *auth; | |
131 | auth_rule_t rule; | |
132 | uintptr_t config; | |
f6329cae TB |
133 | char *plugin_name; |
134 | ||
1d94b795 TB |
135 | algos = hash_algorithm_set_create(); |
136 | peer = this->ike_sa->get_peer_cfg(this->ike_sa); | |
137 | if (peer) | |
f6329cae | 138 | { |
1d94b795 TB |
139 | rounds = peer->create_auth_cfg_enumerator(peer, FALSE); |
140 | while (rounds->enumerate(rounds, &auth)) | |
f6329cae | 141 | { |
1d94b795 TB |
142 | enumerator = auth->create_enumerator(auth); |
143 | while (enumerator->enumerate(enumerator, &rule, &config)) | |
144 | { | |
145 | if (rule == AUTH_RULE_SIGNATURE_SCHEME) | |
146 | { | |
147 | hash = hasher_from_signature_scheme(config); | |
148 | if (hasher_algorithm_for_ikev2(hash)) | |
149 | { | |
150 | algos->add(algos, hash); | |
151 | } | |
152 | } | |
153 | } | |
154 | enumerator->destroy(enumerator); | |
f6329cae | 155 | } |
1d94b795 | 156 | rounds->destroy(rounds); |
f6329cae | 157 | } |
f6329cae | 158 | |
1d94b795 | 159 | if (!algos->count(algos)) |
f6329cae | 160 | { |
1d94b795 TB |
161 | enumerator = lib->crypto->create_hasher_enumerator(lib->crypto); |
162 | while (enumerator->enumerate(enumerator, &hash, &plugin_name)) | |
163 | { | |
164 | if (hasher_algorithm_for_ikev2(hash)) | |
165 | { | |
166 | algos->add(algos, hash); | |
167 | } | |
168 | } | |
169 | enumerator->destroy(enumerator); | |
170 | } | |
171 | ||
172 | if (algos->count(algos)) | |
173 | { | |
174 | writer = bio_writer_create(0); | |
175 | enumerator = algos->create_enumerator(algos); | |
176 | while (enumerator->enumerate(enumerator, &hash)) | |
177 | { | |
178 | writer->write_uint16(writer, hash); | |
179 | } | |
180 | enumerator->destroy(enumerator); | |
f6329cae TB |
181 | message->add_notify(message, FALSE, SIGNATURE_HASH_ALGORITHMS, |
182 | writer->get_buf(writer)); | |
1d94b795 | 183 | writer->destroy(writer); |
f6329cae | 184 | } |
1d94b795 | 185 | algos->destroy(algos); |
f6329cae TB |
186 | } |
187 | ||
188 | /** | |
189 | * Store algorithms supported by other peer | |
190 | */ | |
191 | static void handle_supported_hash_algorithms(private_ike_init_t *this, | |
192 | notify_payload_t *notify) | |
193 | { | |
194 | bio_reader_t *reader; | |
195 | u_int16_t algo; | |
196 | bool added = FALSE; | |
197 | ||
198 | reader = bio_reader_create(notify->get_notification_data(notify)); | |
199 | while (reader->remaining(reader) >= 2 && reader->read_uint16(reader, &algo)) | |
200 | { | |
201 | if (hasher_algorithm_for_ikev2(algo)) | |
202 | { | |
203 | this->keymat->add_hash_algorithm(this->keymat, algo); | |
204 | added = TRUE; | |
205 | } | |
206 | } | |
207 | reader->destroy(reader); | |
208 | ||
209 | if (added) | |
210 | { | |
211 | this->ike_sa->enable_extension(this->ike_sa, EXT_SIGNATURE_AUTH); | |
212 | } | |
213 | } | |
214 | ||
c60c7694 MW |
215 | /** |
216 | * build the payloads for the message | |
217 | */ | |
520d58e0 | 218 | static bool build_payloads(private_ike_init_t *this, message_t *message) |
c60c7694 MW |
219 | { |
220 | sa_payload_t *sa_payload; | |
221 | ke_payload_t *ke_payload; | |
222 | nonce_payload_t *nonce_payload; | |
223 | linked_list_t *proposal_list; | |
224 | ike_sa_id_t *id; | |
225 | proposal_t *proposal; | |
e2630434 | 226 | enumerator_t *enumerator; |
7daf5226 | 227 | |
c60c7694 | 228 | id = this->ike_sa->get_id(this->ike_sa); |
7daf5226 | 229 | |
e0fe7651 | 230 | this->config = this->ike_sa->get_ike_cfg(this->ike_sa); |
c60c7694 MW |
231 | |
232 | if (this->initiator) | |
233 | { | |
e0fe7651 | 234 | proposal_list = this->config->get_proposals(this->config); |
c60c7694 | 235 | if (this->old_sa) |
484a06bc | 236 | { |
c60c7694 | 237 | /* include SPI of new IKE_SA when we are rekeying */ |
e2630434 TB |
238 | enumerator = proposal_list->create_enumerator(proposal_list); |
239 | while (enumerator->enumerate(enumerator, (void**)&proposal)) | |
c60c7694 MW |
240 | { |
241 | proposal->set_spi(proposal, id->get_initiator_spi(id)); | |
242 | } | |
e2630434 | 243 | enumerator->destroy(enumerator); |
c60c7694 | 244 | } |
7daf5226 | 245 | |
e174e0d4 | 246 | sa_payload = sa_payload_create_from_proposals_v2(proposal_list); |
c60c7694 MW |
247 | proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy)); |
248 | } | |
249 | else | |
250 | { | |
251 | if (this->old_sa) | |
252 | { | |
253 | /* include SPI of new IKE_SA when we are rekeying */ | |
254 | this->proposal->set_spi(this->proposal, id->get_responder_spi(id)); | |
255 | } | |
e174e0d4 | 256 | sa_payload = sa_payload_create_from_proposal_v2(this->proposal); |
c60c7694 MW |
257 | } |
258 | message->add_payload(message, (payload_t*)sa_payload); | |
7daf5226 | 259 | |
3ecfc83c | 260 | nonce_payload = nonce_payload_create(PLV2_NONCE); |
c60c7694 | 261 | nonce_payload->set_nonce(nonce_payload, this->my_nonce); |
520d58e0 MW |
262 | ke_payload = ke_payload_create_from_diffie_hellman(PLV2_KEY_EXCHANGE, |
263 | this->dh); | |
264 | if (!ke_payload) | |
265 | { | |
266 | DBG1(DBG_IKE, "creating KE payload failed"); | |
267 | return FALSE; | |
268 | } | |
7daf5226 | 269 | |
cc68e173 MW |
270 | if (this->old_sa) |
271 | { /* payload order differs if we are rekeying */ | |
272 | message->add_payload(message, (payload_t*)nonce_payload); | |
273 | message->add_payload(message, (payload_t*)ke_payload); | |
274 | } | |
275 | else | |
276 | { | |
277 | message->add_payload(message, (payload_t*)ke_payload); | |
278 | message->add_payload(message, (payload_t*)nonce_payload); | |
279 | } | |
34dc37f3 TB |
280 | |
281 | /* negotiate fragmentation if we are not rekeying */ | |
282 | if (!this->old_sa && | |
283 | this->config->fragmentation(this->config) != FRAGMENTATION_NO) | |
284 | { | |
285 | if (this->initiator || | |
286 | this->ike_sa->supports_extension(this->ike_sa, | |
287 | EXT_IKE_FRAGMENTATION)) | |
288 | { | |
289 | message->add_notify(message, FALSE, FRAGMENTATION_SUPPORTED, | |
290 | chunk_empty); | |
291 | } | |
292 | } | |
f6329cae | 293 | /* submit supported hash algorithms for signature authentication */ |
fff3576b | 294 | if (!this->old_sa && this->signature_authentication) |
f6329cae TB |
295 | { |
296 | if (this->initiator || | |
297 | this->ike_sa->supports_extension(this->ike_sa, | |
298 | EXT_SIGNATURE_AUTH)) | |
299 | { | |
1d94b795 | 300 | send_supported_hash_algorithms(this, message); |
f6329cae TB |
301 | } |
302 | } | |
520d58e0 | 303 | return TRUE; |
c60c7694 MW |
304 | } |
305 | ||
306 | /** | |
307 | * Read payloads from message | |
308 | */ | |
309 | static void process_payloads(private_ike_init_t *this, message_t *message) | |
310 | { | |
a44bb934 | 311 | enumerator_t *enumerator; |
c60c7694 | 312 | payload_t *payload; |
691d00f1 | 313 | ke_payload_t *ke_payload = NULL; |
7daf5226 | 314 | |
a44bb934 MW |
315 | enumerator = message->create_payload_enumerator(message); |
316 | while (enumerator->enumerate(enumerator, &payload)) | |
c60c7694 MW |
317 | { |
318 | switch (payload->get_type(payload)) | |
319 | { | |
3ecfc83c | 320 | case PLV2_SECURITY_ASSOCIATION: |
c60c7694 MW |
321 | { |
322 | sa_payload_t *sa_payload = (sa_payload_t*)payload; | |
323 | linked_list_t *proposal_list; | |
023fd8f1 | 324 | bool private; |
7daf5226 | 325 | |
c60c7694 | 326 | proposal_list = sa_payload->get_proposals(sa_payload); |
023fd8f1 MW |
327 | private = this->ike_sa->supports_extension(this->ike_sa, |
328 | EXT_STRONGSWAN); | |
e0fe7651 | 329 | this->proposal = this->config->select_proposal(this->config, |
023fd8f1 | 330 | proposal_list, private); |
bab949bb MW |
331 | if (!this->proposal) |
332 | { | |
333 | charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_IKE, | |
334 | proposal_list); | |
335 | } | |
484a06bc | 336 | proposal_list->destroy_offset(proposal_list, |
c60c7694 MW |
337 | offsetof(proposal_t, destroy)); |
338 | break; | |
339 | } | |
3ecfc83c | 340 | case PLV2_KEY_EXCHANGE: |
c60c7694 | 341 | { |
691d00f1 | 342 | ke_payload = (ke_payload_t*)payload; |
7daf5226 | 343 | |
1fd5383e | 344 | this->dh_group = ke_payload->get_dh_group_number(ke_payload); |
c60c7694 MW |
345 | break; |
346 | } | |
3ecfc83c | 347 | case PLV2_NONCE: |
c60c7694 MW |
348 | { |
349 | nonce_payload_t *nonce_payload = (nonce_payload_t*)payload; | |
125aaf1a | 350 | |
c60c7694 MW |
351 | this->other_nonce = nonce_payload->get_nonce(nonce_payload); |
352 | break; | |
353 | } | |
34dc37f3 TB |
354 | case PLV2_NOTIFY: |
355 | { | |
356 | notify_payload_t *notify = (notify_payload_t*)payload; | |
357 | ||
f6329cae | 358 | switch (notify->get_notify_type(notify)) |
34dc37f3 | 359 | { |
f6329cae TB |
360 | case FRAGMENTATION_SUPPORTED: |
361 | this->ike_sa->enable_extension(this->ike_sa, | |
362 | EXT_IKE_FRAGMENTATION); | |
363 | break; | |
364 | case SIGNATURE_HASH_ALGORITHMS: | |
fff3576b TB |
365 | if (this->signature_authentication) |
366 | { | |
367 | handle_supported_hash_algorithms(this, notify); | |
368 | } | |
f6329cae TB |
369 | break; |
370 | default: | |
371 | /* other notifies are handled elsewhere */ | |
372 | break; | |
34dc37f3 | 373 | } |
f6329cae | 374 | |
34dc37f3 | 375 | } |
c60c7694 MW |
376 | default: |
377 | break; | |
378 | } | |
379 | } | |
a44bb934 | 380 | enumerator->destroy(enumerator); |
691d00f1 TB |
381 | |
382 | if (ke_payload && this->proposal && | |
383 | this->proposal->has_dh_group(this->proposal, this->dh_group)) | |
384 | { | |
385 | if (!this->initiator) | |
386 | { | |
387 | this->dh = this->keymat->keymat.create_dh( | |
388 | &this->keymat->keymat, this->dh_group); | |
389 | } | |
390 | if (this->dh) | |
391 | { | |
a777155f | 392 | this->dh_failed = !this->dh->set_other_public_value(this->dh, |
691d00f1 TB |
393 | ke_payload->get_key_exchange_data(ke_payload)); |
394 | } | |
395 | } | |
c60c7694 MW |
396 | } |
397 | ||
c73694e7 AS |
398 | METHOD(task_t, build_i, status_t, |
399 | private_ike_init_t *this, message_t *message) | |
c60c7694 | 400 | { |
e0fe7651 | 401 | this->config = this->ike_sa->get_ike_cfg(this->ike_sa); |
7790ab0f | 402 | DBG0(DBG_IKE, "initiating IKE_SA %s[%d] to %H", |
a985db3f MW |
403 | this->ike_sa->get_name(this->ike_sa), |
404 | this->ike_sa->get_unique_id(this->ike_sa), | |
405 | this->ike_sa->get_other_host(this->ike_sa)); | |
c60c7694 | 406 | this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); |
7daf5226 | 407 | |
f12d8cf7 | 408 | if (this->retry >= MAX_RETRIES) |
a6bdc731 | 409 | { |
a985db3f | 410 | DBG1(DBG_IKE, "giving up after %d retries", MAX_RETRIES); |
a6bdc731 MW |
411 | return FAILED; |
412 | } | |
7daf5226 | 413 | |
c60c7694 | 414 | /* if the DH group is set via use_dh_group(), we already have a DH object */ |
1fd5383e | 415 | if (!this->dh) |
c60c7694 | 416 | { |
e0fe7651 | 417 | this->dh_group = this->config->get_dh_group(this->config); |
a0563846 TB |
418 | this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, |
419 | this->dh_group); | |
a64cc8f7 | 420 | if (!this->dh) |
c60c7694 | 421 | { |
a985db3f | 422 | DBG1(DBG_IKE, "configured DH group %N not supported", |
c60c7694 MW |
423 | diffie_hellman_group_names, this->dh_group); |
424 | return FAILED; | |
425 | } | |
426 | } | |
7daf5226 | 427 | |
e5a7f1cd MW |
428 | /* generate nonce only when we are trying the first time */ |
429 | if (this->my_nonce.ptr == NULL) | |
c60c7694 | 430 | { |
afaf1bdf AKR |
431 | nonce_gen_t *nonceg; |
432 | ||
433 | nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat); | |
434 | if (!nonceg) | |
e5a7f1cd | 435 | { |
afaf1bdf | 436 | DBG1(DBG_IKE, "no nonce generator found to create nonce"); |
e5a7f1cd MW |
437 | return FAILED; |
438 | } | |
605985d1 RB |
439 | if (!nonceg->allocate_nonce(nonceg, NONCE_SIZE, &this->my_nonce)) |
440 | { | |
441 | DBG1(DBG_IKE, "nonce allocation failed"); | |
442 | nonceg->destroy(nonceg); | |
443 | return FAILED; | |
444 | } | |
afaf1bdf | 445 | nonceg->destroy(nonceg); |
e5a7f1cd | 446 | } |
7daf5226 | 447 | |
e5a7f1cd MW |
448 | if (this->cookie.ptr) |
449 | { | |
450 | message->add_notify(message, FALSE, COOKIE, this->cookie); | |
c60c7694 | 451 | } |
7daf5226 | 452 | |
520d58e0 MW |
453 | if (!build_payloads(this, message)) |
454 | { | |
455 | return FAILED; | |
456 | } | |
9c2a905d TB |
457 | |
458 | #ifdef ME | |
459 | { | |
460 | chunk_t connect_id = this->ike_sa->get_connect_id(this->ike_sa); | |
461 | if (connect_id.ptr) | |
462 | { | |
463 | message->add_notify(message, FALSE, ME_CONNECTID, connect_id); | |
464 | } | |
465 | } | |
466 | #endif /* ME */ | |
7daf5226 | 467 | |
c60c7694 MW |
468 | return NEED_MORE; |
469 | } | |
470 | ||
c73694e7 AS |
471 | METHOD(task_t, process_r, status_t, |
472 | private_ike_init_t *this, message_t *message) | |
484a06bc | 473 | { |
afaf1bdf | 474 | nonce_gen_t *nonceg; |
7daf5226 | 475 | |
e0fe7651 | 476 | this->config = this->ike_sa->get_ike_cfg(this->ike_sa); |
7790ab0f | 477 | DBG0(DBG_IKE, "%H is initiating an IKE_SA", message->get_source(message)); |
c60c7694 MW |
478 | this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); |
479 | ||
afaf1bdf AKR |
480 | nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat); |
481 | if (!nonceg) | |
c60c7694 | 482 | { |
afaf1bdf | 483 | DBG1(DBG_IKE, "no nonce generator found to create nonce"); |
6a365f07 | 484 | return FAILED; |
c60c7694 | 485 | } |
605985d1 RB |
486 | if (!nonceg->allocate_nonce(nonceg, NONCE_SIZE, &this->my_nonce)) |
487 | { | |
488 | DBG1(DBG_IKE, "nonce allocation failed"); | |
489 | nonceg->destroy(nonceg); | |
490 | return FAILED; | |
491 | } | |
afaf1bdf | 492 | nonceg->destroy(nonceg); |
7daf5226 | 493 | |
9c2a905d TB |
494 | #ifdef ME |
495 | { | |
a20e9874 TB |
496 | notify_payload_t *notify = message->get_notify(message, ME_CONNECTID); |
497 | if (notify) | |
9c2a905d | 498 | { |
a20e9874 TB |
499 | chunk_t connect_id = notify->get_notification_data(notify); |
500 | DBG2(DBG_IKE, "received ME_CONNECTID %#B", &connect_id); | |
9c2a905d | 501 | charon->connect_manager->stop_checks(charon->connect_manager, |
a20e9874 | 502 | connect_id); |
9c2a905d TB |
503 | } |
504 | } | |
505 | #endif /* ME */ | |
7daf5226 | 506 | |
c60c7694 | 507 | process_payloads(this, message); |
7daf5226 | 508 | |
c60c7694 MW |
509 | return NEED_MORE; |
510 | } | |
511 | ||
512 | /** | |
ddef4552 | 513 | * Derive the keymat for the IKE_SA |
c60c7694 | 514 | */ |
ddef4552 MW |
515 | static bool derive_keys(private_ike_init_t *this, |
516 | chunk_t nonce_i, chunk_t nonce_r) | |
c60c7694 | 517 | { |
a0563846 | 518 | keymat_v2_t *old_keymat; |
ddef4552 MW |
519 | pseudo_random_function_t prf_alg = PRF_UNDEFINED; |
520 | chunk_t skd = chunk_empty; | |
6a4ff35c | 521 | ike_sa_id_t *id; |
7daf5226 | 522 | |
ddef4552 MW |
523 | id = this->ike_sa->get_id(this->ike_sa); |
524 | if (this->old_sa) | |
525 | { | |
526 | /* rekeying: Include old SKd, use old PRF, apply SPI */ | |
a0563846 | 527 | old_keymat = (keymat_v2_t*)this->old_sa->get_keymat(this->old_sa); |
ddef4552 MW |
528 | prf_alg = old_keymat->get_skd(old_keymat, &skd); |
529 | if (this->initiator) | |
530 | { | |
531 | id->set_responder_spi(id, this->proposal->get_spi(this->proposal)); | |
532 | } | |
533 | else | |
534 | { | |
535 | id->set_initiator_spi(id, this->proposal->get_spi(this->proposal)); | |
536 | } | |
537 | } | |
538 | if (!this->keymat->derive_ike_keys(this->keymat, this->proposal, this->dh, | |
539 | nonce_i, nonce_r, id, prf_alg, skd)) | |
540 | { | |
541 | return FALSE; | |
542 | } | |
23f9e7a1 MW |
543 | charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, chunk_empty, |
544 | nonce_i, nonce_r, this->old_sa, NULL); | |
ddef4552 MW |
545 | return TRUE; |
546 | } | |
547 | ||
c73694e7 AS |
548 | METHOD(task_t, build_r, status_t, |
549 | private_ike_init_t *this, message_t *message) | |
ddef4552 | 550 | { |
c60c7694 MW |
551 | /* check if we have everything we need */ |
552 | if (this->proposal == NULL || | |
553 | this->other_nonce.len == 0 || this->my_nonce.len == 0) | |
554 | { | |
a985db3f | 555 | DBG1(DBG_IKE, "received proposals inacceptable"); |
c60c7694 MW |
556 | message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); |
557 | return FAILED; | |
558 | } | |
5dffdea1 | 559 | this->ike_sa->set_proposal(this->ike_sa, this->proposal); |
7daf5226 | 560 | |
1fd5383e | 561 | if (this->dh == NULL || |
6a4ff35c | 562 | !this->proposal->has_dh_group(this->proposal, this->dh_group)) |
c60c7694 | 563 | { |
3c7e72f5 | 564 | u_int16_t group; |
7daf5226 | 565 | |
1fd5383e | 566 | if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, |
3c7e72f5 | 567 | &group, NULL)) |
1fd5383e | 568 | { |
a985db3f MW |
569 | DBG1(DBG_IKE, "DH group %N inacceptable, requesting %N", |
570 | diffie_hellman_group_names, this->dh_group, | |
571 | diffie_hellman_group_names, group); | |
1fd5383e MW |
572 | this->dh_group = group; |
573 | group = htons(group); | |
574 | message->add_notify(message, FALSE, INVALID_KE_PAYLOAD, | |
575 | chunk_from_thing(group)); | |
576 | } | |
577 | else | |
578 | { | |
a985db3f | 579 | DBG1(DBG_IKE, "no acceptable proposal found"); |
1fd5383e | 580 | } |
c60c7694 MW |
581 | return FAILED; |
582 | } | |
7daf5226 | 583 | |
a777155f MW |
584 | if (this->dh_failed) |
585 | { | |
586 | DBG1(DBG_IKE, "applying DH public value failed"); | |
587 | message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); | |
588 | return FAILED; | |
589 | } | |
590 | ||
ddef4552 | 591 | if (!derive_keys(this, this->other_nonce, this->my_nonce)) |
c60c7694 | 592 | { |
a985db3f | 593 | DBG1(DBG_IKE, "key derivation failed"); |
c60c7694 MW |
594 | message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); |
595 | return FAILED; | |
596 | } | |
520d58e0 MW |
597 | if (!build_payloads(this, message)) |
598 | { | |
42431690 | 599 | message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); |
520d58e0 MW |
600 | return FAILED; |
601 | } | |
c60c7694 MW |
602 | return SUCCESS; |
603 | } | |
604 | ||
00080d2b MW |
605 | /** |
606 | * Raise alerts for received notify errors | |
607 | */ | |
608 | static void raise_alerts(private_ike_init_t *this, notify_type_t type) | |
609 | { | |
610 | linked_list_t *list; | |
611 | ||
612 | switch (type) | |
613 | { | |
614 | case NO_PROPOSAL_CHOSEN: | |
615 | list = this->config->get_proposals(this->config); | |
616 | charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_IKE, list); | |
617 | list->destroy_offset(list, offsetof(proposal_t, destroy)); | |
618 | break; | |
619 | default: | |
620 | break; | |
621 | } | |
622 | } | |
623 | ||
c73694e7 AS |
624 | METHOD(task_t, process_i, status_t, |
625 | private_ike_init_t *this, message_t *message) | |
c60c7694 | 626 | { |
a44bb934 | 627 | enumerator_t *enumerator; |
c60c7694 | 628 | payload_t *payload; |
7daf5226 | 629 | |
ef33a4ab | 630 | /* check for erroneous notifies */ |
a44bb934 MW |
631 | enumerator = message->create_payload_enumerator(message); |
632 | while (enumerator->enumerate(enumerator, &payload)) | |
c60c7694 | 633 | { |
3ecfc83c | 634 | if (payload->get_type(payload) == PLV2_NOTIFY) |
c60c7694 MW |
635 | { |
636 | notify_payload_t *notify = (notify_payload_t*)payload; | |
637 | notify_type_t type = notify->get_notify_type(notify); | |
7daf5226 | 638 | |
c60c7694 MW |
639 | switch (type) |
640 | { | |
641 | case INVALID_KE_PAYLOAD: | |
642 | { | |
643 | chunk_t data; | |
1fd5383e | 644 | diffie_hellman_group_t bad_group; |
7daf5226 | 645 | |
1fd5383e | 646 | bad_group = this->dh_group; |
c60c7694 MW |
647 | data = notify->get_notification_data(notify); |
648 | this->dh_group = ntohs(*((u_int16_t*)data.ptr)); | |
1fd5383e MW |
649 | DBG1(DBG_IKE, "peer didn't accept DH group %N, " |
650 | "it requested %N", diffie_hellman_group_names, | |
651 | bad_group, diffie_hellman_group_names, this->dh_group); | |
7daf5226 | 652 | |
1fd5383e MW |
653 | if (this->old_sa == NULL) |
654 | { /* reset the IKE_SA if we are not rekeying */ | |
655 | this->ike_sa->reset(this->ike_sa); | |
c60c7694 | 656 | } |
7daf5226 | 657 | |
a44bb934 | 658 | enumerator->destroy(enumerator); |
f12d8cf7 | 659 | this->retry++; |
c60c7694 MW |
660 | return NEED_MORE; |
661 | } | |
e5a7f1cd MW |
662 | case NAT_DETECTION_SOURCE_IP: |
663 | case NAT_DETECTION_DESTINATION_IP: | |
664 | /* skip, handled in ike_natd_t */ | |
665 | break; | |
a44bb934 MW |
666 | case MULTIPLE_AUTH_SUPPORTED: |
667 | /* handled in ike_auth_t */ | |
668 | break; | |
e5a7f1cd MW |
669 | case COOKIE: |
670 | { | |
a6bdc731 | 671 | chunk_free(&this->cookie); |
e5a7f1cd MW |
672 | this->cookie = chunk_clone(notify->get_notification_data(notify)); |
673 | this->ike_sa->reset(this->ike_sa); | |
a44bb934 | 674 | enumerator->destroy(enumerator); |
196b28a4 | 675 | DBG2(DBG_IKE, "received %N notify", notify_type_names, type); |
f12d8cf7 | 676 | this->retry++; |
e5a7f1cd MW |
677 | return NEED_MORE; |
678 | } | |
c60c7694 MW |
679 | default: |
680 | { | |
30d8e8d0 | 681 | if (type <= 16383) |
c60c7694 | 682 | { |
a985db3f | 683 | DBG1(DBG_IKE, "received %N notify error", |
c60c7694 | 684 | notify_type_names, type); |
a44bb934 | 685 | enumerator->destroy(enumerator); |
00080d2b | 686 | raise_alerts(this, type); |
484a06bc | 687 | return FAILED; |
c60c7694 | 688 | } |
196b28a4 | 689 | DBG2(DBG_IKE, "received %N notify", |
e5a7f1cd MW |
690 | notify_type_names, type); |
691 | break; | |
c60c7694 MW |
692 | } |
693 | } | |
694 | } | |
695 | } | |
a44bb934 | 696 | enumerator->destroy(enumerator); |
7daf5226 | 697 | |
c60c7694 MW |
698 | process_payloads(this, message); |
699 | ||
700 | /* check if we have everything */ | |
701 | if (this->proposal == NULL || | |
702 | this->other_nonce.len == 0 || this->my_nonce.len == 0) | |
703 | { | |
a985db3f | 704 | DBG1(DBG_IKE, "peers proposal selection invalid"); |
c60c7694 MW |
705 | return FAILED; |
706 | } | |
5dffdea1 | 707 | this->ike_sa->set_proposal(this->ike_sa, this->proposal); |
7daf5226 | 708 | |
1fd5383e | 709 | if (this->dh == NULL || |
6a4ff35c | 710 | !this->proposal->has_dh_group(this->proposal, this->dh_group)) |
c60c7694 | 711 | { |
a985db3f | 712 | DBG1(DBG_IKE, "peer DH group selection invalid"); |
c60c7694 MW |
713 | return FAILED; |
714 | } | |
7daf5226 | 715 | |
a777155f MW |
716 | if (this->dh_failed) |
717 | { | |
718 | DBG1(DBG_IKE, "applying DH public value failed"); | |
719 | return FAILED; | |
720 | } | |
721 | ||
ddef4552 | 722 | if (!derive_keys(this, this->my_nonce, this->other_nonce)) |
c60c7694 | 723 | { |
a985db3f | 724 | DBG1(DBG_IKE, "key derivation failed"); |
c60c7694 MW |
725 | return FAILED; |
726 | } | |
727 | return SUCCESS; | |
728 | } | |
729 | ||
c73694e7 AS |
730 | METHOD(task_t, get_type, task_type_t, |
731 | private_ike_init_t *this) | |
c60c7694 | 732 | { |
a09972df | 733 | return TASK_IKE_INIT; |
c60c7694 MW |
734 | } |
735 | ||
c73694e7 AS |
736 | METHOD(task_t, migrate, void, |
737 | private_ike_init_t *this, ike_sa_t *ike_sa) | |
c60c7694 MW |
738 | { |
739 | DESTROY_IF(this->proposal); | |
c60c7694 | 740 | chunk_free(&this->other_nonce); |
7daf5226 | 741 | |
c60c7694 | 742 | this->ike_sa = ike_sa; |
a0563846 | 743 | this->keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa); |
c60c7694 | 744 | this->proposal = NULL; |
a777155f | 745 | this->dh_failed = FALSE; |
a59a0367 MW |
746 | if (this->dh && this->dh->get_dh_group(this->dh) != this->dh_group) |
747 | { /* reset DH value only if group changed (INVALID_KE_PAYLOAD) */ | |
748 | this->dh->destroy(this->dh); | |
b24be296 MW |
749 | this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, |
750 | this->dh_group); | |
a59a0367 | 751 | } |
c60c7694 MW |
752 | } |
753 | ||
c73694e7 AS |
754 | METHOD(task_t, destroy, void, |
755 | private_ike_init_t *this) | |
c60c7694 | 756 | { |
a64cc8f7 | 757 | DESTROY_IF(this->dh); |
c60c7694 | 758 | DESTROY_IF(this->proposal); |
c60c7694 MW |
759 | chunk_free(&this->my_nonce); |
760 | chunk_free(&this->other_nonce); | |
e5a7f1cd | 761 | chunk_free(&this->cookie); |
c60c7694 MW |
762 | free(this); |
763 | } | |
764 | ||
c73694e7 AS |
765 | METHOD(ike_init_t, get_lower_nonce, chunk_t, |
766 | private_ike_init_t *this) | |
767 | { | |
768 | if (memcmp(this->my_nonce.ptr, this->other_nonce.ptr, | |
769 | min(this->my_nonce.len, this->other_nonce.len)) < 0) | |
770 | { | |
771 | return this->my_nonce; | |
772 | } | |
773 | else | |
774 | { | |
775 | return this->other_nonce; | |
776 | } | |
777 | } | |
778 | ||
c60c7694 MW |
779 | /* |
780 | * Described in header. | |
781 | */ | |
782 | ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa) | |
783 | { | |
c73694e7 AS |
784 | private_ike_init_t *this; |
785 | ||
786 | INIT(this, | |
787 | .public = { | |
788 | .task = { | |
789 | .get_type = _get_type, | |
790 | .migrate = _migrate, | |
791 | .destroy = _destroy, | |
792 | }, | |
793 | .get_lower_nonce = _get_lower_nonce, | |
794 | }, | |
795 | .ike_sa = ike_sa, | |
796 | .initiator = initiator, | |
797 | .dh_group = MODP_NONE, | |
a0563846 | 798 | .keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa), |
c73694e7 | 799 | .old_sa = old_sa, |
fff3576b TB |
800 | .signature_authentication = lib->settings->get_bool(lib->settings, |
801 | "%s.signature_authentication", TRUE, lib->ns), | |
c73694e7 | 802 | ); |
c60c7694 | 803 | |
c60c7694 MW |
804 | if (initiator) |
805 | { | |
c73694e7 AS |
806 | this->public.task.build = _build_i; |
807 | this->public.task.process = _process_i; | |
c60c7694 MW |
808 | } |
809 | else | |
810 | { | |
c73694e7 AS |
811 | this->public.task.build = _build_r; |
812 | this->public.task.process = _process_r; | |
c60c7694 | 813 | } |
7daf5226 | 814 | |
c60c7694 MW |
815 | return &this->public; |
816 | } |