2 * Copyright (C) 2012 Martin Willi
3 * Copyright (C) 2012 revosec AG
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "aggressive_mode.h"
21 #include <sa/ikev1/phase1.h>
22 #include <encoding/payloads/sa_payload.h>
23 #include <encoding/payloads/id_payload.h>
24 #include <encoding/payloads/hash_payload.h>
25 #include <sa/ikev1/tasks/xauth.h>
26 #include <sa/ikev1/tasks/mode_config.h>
27 #include <sa/ikev1/tasks/informational.h>
28 #include <sa/ikev1/tasks/isakmp_delete.h>
29 #include <processing/jobs/adopt_children_job.h>
31 typedef struct private_aggressive_mode_t private_aggressive_mode_t
;
34 * Private members of a aggressive_mode_t task.
36 struct private_aggressive_mode_t
{
39 * Public methods and task_t interface.
41 aggressive_mode_t
public;
49 * Are we the initiator?
54 * Common phase 1 helper class
59 * IKE config to establish
69 * selected IKE proposal
74 * Negotiated SA lifetime
79 * Negotiated authentication method
84 * Encoded ID payload, without fixed header
88 /** states of aggressive mode */
96 * Set IKE_SA to established state
98 static bool establish(private_aggressive_mode_t
*this)
100 if (!charon
->bus
->authorize(charon
->bus
, TRUE
))
102 DBG1(DBG_IKE
, "final authorization hook forbids IKE_SA, cancelling");
106 DBG0(DBG_IKE
, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
107 this->ike_sa
->get_name(this->ike_sa
),
108 this->ike_sa
->get_unique_id(this->ike_sa
),
109 this->ike_sa
->get_my_host(this->ike_sa
),
110 this->ike_sa
->get_my_id(this->ike_sa
),
111 this->ike_sa
->get_other_host(this->ike_sa
),
112 this->ike_sa
->get_other_id(this->ike_sa
));
114 this->ike_sa
->set_state(this->ike_sa
, IKE_ESTABLISHED
);
115 charon
->bus
->ike_updown(charon
->bus
, this->ike_sa
, TRUE
);
121 * Check for notify errors, return TRUE if error found
123 static bool has_notify_errors(private_aggressive_mode_t
*this, message_t
*message
)
125 enumerator_t
*enumerator
;
129 enumerator
= message
->create_payload_enumerator(message
);
130 while (enumerator
->enumerate(enumerator
, &payload
))
132 if (payload
->get_type(payload
) == NOTIFY_V1
)
134 notify_payload_t
*notify
;
137 notify
= (notify_payload_t
*)payload
;
138 type
= notify
->get_notify_type(notify
);
141 DBG1(DBG_IKE
, "received %N error notify",
142 notify_type_names
, type
);
147 DBG1(DBG_IKE
, "received %N notify", notify_type_names
, type
);
151 enumerator
->destroy(enumerator
);
157 * Queue a task sending a notify in an INFORMATIONAL exchange
159 static status_t
send_notify(private_aggressive_mode_t
*this, notify_type_t type
)
161 notify_payload_t
*notify
;
162 ike_sa_id_t
*ike_sa_id
;
163 u_int64_t spi_i
, spi_r
;
166 notify
= notify_payload_create_from_protocol_and_type(NOTIFY_V1
,
168 ike_sa_id
= this->ike_sa
->get_id(this->ike_sa
);
169 spi_i
= ike_sa_id
->get_initiator_spi(ike_sa_id
);
170 spi_r
= ike_sa_id
->get_responder_spi(ike_sa_id
);
171 spi
= chunk_cata("cc", chunk_from_thing(spi_i
), chunk_from_thing(spi_r
));
172 notify
->set_spi_data(notify
, spi
);
174 this->ike_sa
->queue_task(this->ike_sa
,
175 (task_t
*)informational_create(this->ike_sa
, notify
));
176 /* cancel all active/passive tasks in favour of informational */
177 this->ike_sa
->flush_queue(this->ike_sa
,
178 this->initiator ? TASK_QUEUE_ACTIVE
: TASK_QUEUE_PASSIVE
);
183 * Queue a delete task if authentication failed as initiator
185 static status_t
send_delete(private_aggressive_mode_t
*this)
187 this->ike_sa
->queue_task(this->ike_sa
,
188 (task_t
*)isakmp_delete_create(this->ike_sa
, TRUE
));
189 /* cancel all active tasks in favour of informational */
190 this->ike_sa
->flush_queue(this->ike_sa
,
191 this->initiator ? TASK_QUEUE_ACTIVE
: TASK_QUEUE_PASSIVE
);
195 METHOD(task_t
, build_i
, status_t
,
196 private_aggressive_mode_t
*this, message_t
*message
)
202 sa_payload_t
*sa_payload
;
203 id_payload_t
*id_payload
;
204 linked_list_t
*proposals
;
205 identification_t
*id
;
209 DBG0(DBG_IKE
, "initiating Aggressive Mode IKE_SA %s[%d] to %H",
210 this->ike_sa
->get_name(this->ike_sa
),
211 this->ike_sa
->get_unique_id(this->ike_sa
),
212 this->ike_sa
->get_other_host(this->ike_sa
));
213 this->ike_sa
->set_state(this->ike_sa
, IKE_CONNECTING
);
215 this->ike_cfg
= this->ike_sa
->get_ike_cfg(this->ike_sa
);
216 this->peer_cfg
= this->ike_sa
->get_peer_cfg(this->ike_sa
);
217 this->peer_cfg
->get_ref(this->peer_cfg
);
219 this->method
= this->ph1
->get_auth_method(this->ph1
, this->peer_cfg
);
220 if (this->method
== AUTH_NONE
)
222 DBG1(DBG_CFG
, "configuration uses unsupported authentication");
225 this->lifetime
= this->peer_cfg
->get_reauth_time(this->peer_cfg
,
228 { /* fall back to rekey time of no rekey time configured */
229 this->lifetime
= this->peer_cfg
->get_rekey_time(this->peer_cfg
,
232 this->lifetime
+= this->peer_cfg
->get_over_time(this->peer_cfg
);
233 proposals
= this->ike_cfg
->get_proposals(this->ike_cfg
);
234 sa_payload
= sa_payload_create_from_proposals_v1(proposals
,
235 this->lifetime
, 0, this->method
, MODE_NONE
, FALSE
);
236 proposals
->destroy_offset(proposals
, offsetof(proposal_t
, destroy
));
238 message
->add_payload(message
, &sa_payload
->payload_interface
);
240 group
= this->ike_cfg
->get_dh_group(this->ike_cfg
);
241 if (group
== MODP_NONE
)
243 DBG1(DBG_IKE
, "DH group selection failed");
246 if (!this->ph1
->create_dh(this->ph1
, group
))
248 DBG1(DBG_IKE
, "DH group %N not supported",
249 diffie_hellman_group_names
, group
);
252 if (!this->ph1
->add_nonce_ke(this->ph1
, message
))
256 id
= this->ph1
->get_id(this->ph1
, this->peer_cfg
, TRUE
);
259 DBG1(DBG_CFG
, "own identity not known");
262 this->ike_sa
->set_my_id(this->ike_sa
, id
->clone(id
));
263 id_payload
= id_payload_create_from_identification(ID_V1
, id
);
264 this->id_data
= id_payload
->get_encoded(id_payload
);
265 message
->add_payload(message
, &id_payload
->payload_interface
);
267 /* pregenerate message to store SA payload */
268 if (this->ike_sa
->generate_message(this->ike_sa
, message
,
271 DBG1(DBG_IKE
, "pregenerating SA payload failed");
274 packet
->destroy(packet
);
275 if (!this->ph1
->save_sa_payload(this->ph1
, message
))
277 DBG1(DBG_IKE
, "SA payload invalid");
280 this->state
= AM_AUTH
;
285 if (!this->ph1
->build_auth(this->ph1
, this->method
, message
,
288 this->id_data
= chunk_empty
;
289 return send_notify(this, AUTHENTICATION_FAILED
);
291 this->id_data
= chunk_empty
;
293 switch (this->method
)
295 case AUTH_XAUTH_INIT_PSK
:
296 case AUTH_XAUTH_INIT_RSA
:
297 case AUTH_HYBRID_INIT_RSA
:
298 /* wait for XAUTH request */
300 case AUTH_XAUTH_RESP_PSK
:
301 case AUTH_XAUTH_RESP_RSA
:
302 case AUTH_HYBRID_RESP_RSA
:
303 /* TODO-IKEv1: not yet */
306 if (!establish(this))
308 return send_notify(this, AUTHENTICATION_FAILED
);
312 if (this->peer_cfg
->get_virtual_ip(this->peer_cfg
))
314 this->ike_sa
->queue_task(this->ike_sa
,
315 (task_t
*)mode_config_create(this->ike_sa
, TRUE
));
324 METHOD(task_t
, process_r
, status_t
,
325 private_aggressive_mode_t
*this, message_t
*message
)
331 sa_payload_t
*sa_payload
;
332 id_payload_t
*id_payload
;
333 identification_t
*id
;
337 this->ike_cfg
= this->ike_sa
->get_ike_cfg(this->ike_sa
);
338 DBG0(DBG_IKE
, "%H is initiating a Aggressive Mode IKE_SA",
339 message
->get_source(message
));
340 this->ike_sa
->set_state(this->ike_sa
, IKE_CONNECTING
);
342 this->ike_sa
->update_hosts(this->ike_sa
,
343 message
->get_destination(message
),
344 message
->get_source(message
), TRUE
);
346 sa_payload
= (sa_payload_t
*)message
->get_payload(message
,
347 SECURITY_ASSOCIATION_V1
);
350 DBG1(DBG_IKE
, "SA payload missing");
351 return send_notify(this, INVALID_PAYLOAD_TYPE
);
353 if (!this->ph1
->save_sa_payload(this->ph1
, message
))
355 return send_notify(this, INVALID_PAYLOAD_TYPE
);
358 list
= sa_payload
->get_proposals(sa_payload
);
359 this->proposal
= this->ike_cfg
->select_proposal(this->ike_cfg
,
361 list
->destroy_offset(list
, offsetof(proposal_t
, destroy
));
364 DBG1(DBG_IKE
, "no proposal found");
365 return send_notify(this, NO_PROPOSAL_CHOSEN
);
367 this->ike_sa
->set_proposal(this->ike_sa
, this->proposal
);
369 this->method
= sa_payload
->get_auth_method(sa_payload
);
370 this->lifetime
= sa_payload
->get_lifetime(sa_payload
);
372 if (!this->proposal
->get_algorithm(this->proposal
,
373 DIFFIE_HELLMAN_GROUP
, &group
, NULL
))
375 DBG1(DBG_IKE
, "DH group selection failed");
376 return send_notify(this, INVALID_KEY_INFORMATION
);
378 if (!this->ph1
->create_dh(this->ph1
, group
))
380 DBG1(DBG_IKE
, "negotiated DH group not supported");
381 return send_notify(this, INVALID_KEY_INFORMATION
);
383 if (!this->ph1
->get_nonce_ke(this->ph1
, message
))
385 return send_notify(this, INVALID_PAYLOAD_TYPE
);
388 id_payload
= (id_payload_t
*)message
->get_payload(message
, ID_V1
);
391 DBG1(DBG_IKE
, "IDii payload missing");
392 return send_notify(this, INVALID_PAYLOAD_TYPE
);
395 id
= id_payload
->get_identification(id_payload
);
396 this->id_data
= id_payload
->get_encoded(id_payload
);
397 this->ike_sa
->set_other_id(this->ike_sa
, id
);
398 this->peer_cfg
= this->ph1
->select_config(this->ph1
,
399 this->method
, TRUE
, id
);
402 DBG1(DBG_IKE
, "no peer config found");
403 return send_notify(this, AUTHENTICATION_FAILED
);
405 this->ike_sa
->set_peer_cfg(this->ike_sa
, this->peer_cfg
);
407 this->state
= AM_AUTH
;
408 if (has_notify_errors(this, message
))
416 if (!this->ph1
->verify_auth(this->ph1
, this->method
, message
,
419 this->id_data
= chunk_empty
;
420 return send_delete(this);
422 this->id_data
= chunk_empty
;
424 if (!charon
->bus
->authorize(charon
->bus
, FALSE
))
426 DBG1(DBG_IKE
, "Aggressive Mode authorization hook forbids "
427 "IKE_SA, cancelling");
428 return send_delete(this);
431 switch (this->method
)
433 case AUTH_XAUTH_INIT_PSK
:
434 case AUTH_XAUTH_INIT_RSA
:
435 case AUTH_HYBRID_INIT_RSA
:
436 this->ike_sa
->queue_task(this->ike_sa
,
437 (task_t
*)xauth_create(this->ike_sa
, TRUE
));
439 case AUTH_XAUTH_RESP_PSK
:
440 case AUTH_XAUTH_RESP_RSA
:
441 case AUTH_HYBRID_RESP_RSA
:
442 /* TODO-IKEv1: not yet supported */
445 if (!establish(this))
447 return send_delete(this);
449 lib
->processor
->queue_job(lib
->processor
, (job_t
*)
450 adopt_children_job_create(
451 this->ike_sa
->get_id(this->ike_sa
)));
460 METHOD(task_t
, build_r
, status_t
,
461 private_aggressive_mode_t
*this, message_t
*message
)
463 if (this->state
== AM_AUTH
)
465 sa_payload_t
*sa_payload
;
466 id_payload_t
*id_payload
;
467 identification_t
*id
;
469 sa_payload
= sa_payload_create_from_proposal_v1(this->proposal
,
470 this->lifetime
, 0, this->method
, MODE_NONE
, FALSE
);
471 message
->add_payload(message
, &sa_payload
->payload_interface
);
473 if (!this->ph1
->add_nonce_ke(this->ph1
, message
))
475 return send_notify(this, INVALID_KEY_INFORMATION
);
477 if (!this->ph1
->create_hasher(this->ph1
))
479 return send_notify(this, NO_PROPOSAL_CHOSEN
);
481 if (!this->ph1
->derive_keys(this->ph1
, this->peer_cfg
, this->method
))
483 return send_notify(this, INVALID_KEY_INFORMATION
);
486 id
= this->ph1
->get_id(this->ph1
, this->peer_cfg
, TRUE
);
489 DBG1(DBG_CFG
, "own identity not known");
490 return send_notify(this, INVALID_ID_INFORMATION
);
492 this->ike_sa
->set_my_id(this->ike_sa
, id
->clone(id
));
494 id_payload
= id_payload_create_from_identification(ID_V1
, id
);
495 message
->add_payload(message
, &id_payload
->payload_interface
);
497 if (!this->ph1
->build_auth(this->ph1
, this->method
, message
,
498 id_payload
->get_encoded(id_payload
)))
500 return send_notify(this, AUTHENTICATION_FAILED
);
507 METHOD(task_t
, process_i
, status_t
,
508 private_aggressive_mode_t
*this, message_t
*message
)
510 if (this->state
== AM_AUTH
)
512 auth_method_t method
;
513 sa_payload_t
*sa_payload
;
514 id_payload_t
*id_payload
;
515 identification_t
*id
, *cid
;
519 sa_payload
= (sa_payload_t
*)message
->get_payload(message
,
520 SECURITY_ASSOCIATION_V1
);
523 DBG1(DBG_IKE
, "SA payload missing");
524 return send_notify(this, INVALID_PAYLOAD_TYPE
);
526 list
= sa_payload
->get_proposals(sa_payload
);
527 this->proposal
= this->ike_cfg
->select_proposal(this->ike_cfg
,
529 list
->destroy_offset(list
, offsetof(proposal_t
, destroy
));
532 DBG1(DBG_IKE
, "no proposal found");
533 return send_notify(this, NO_PROPOSAL_CHOSEN
);
535 this->ike_sa
->set_proposal(this->ike_sa
, this->proposal
);
537 lifetime
= sa_payload
->get_lifetime(sa_payload
);
538 if (lifetime
!= this->lifetime
)
540 DBG1(DBG_IKE
, "received lifetime %us does not match configured "
541 "lifetime %us", lifetime
, this->lifetime
);
543 this->lifetime
= lifetime
;
544 method
= sa_payload
->get_auth_method(sa_payload
);
545 if (method
!= this->method
)
547 DBG1(DBG_IKE
, "received %N authentication, but configured %N, "
548 "continue with configured", auth_method_names
, method
,
549 auth_method_names
, this->method
);
551 if (!this->ph1
->get_nonce_ke(this->ph1
, message
))
553 return send_notify(this, INVALID_PAYLOAD_TYPE
);
555 if (!this->ph1
->create_hasher(this->ph1
))
557 return send_notify(this, NO_PROPOSAL_CHOSEN
);
559 if (!this->ph1
->derive_keys(this->ph1
, this->peer_cfg
, this->method
))
561 return send_notify(this, INVALID_KEY_INFORMATION
);
564 id_payload
= (id_payload_t
*)message
->get_payload(message
, ID_V1
);
567 DBG1(DBG_IKE
, "IDir payload missing");
568 return send_delete(this);
570 id
= id_payload
->get_identification(id_payload
);
571 cid
= this->ph1
->get_id(this->ph1
, this->peer_cfg
, FALSE
);
572 if (cid
&& !id
->matches(id
, cid
))
574 DBG1(DBG_IKE
, "IDir '%Y' does not match to '%Y'", id
, cid
);
576 return send_notify(this, INVALID_ID_INFORMATION
);
578 this->ike_sa
->set_other_id(this->ike_sa
, id
);
580 if (!this->ph1
->verify_auth(this->ph1
, this->method
, message
,
581 id_payload
->get_encoded(id_payload
)))
583 return send_notify(this, AUTHENTICATION_FAILED
);
585 if (!charon
->bus
->authorize(charon
->bus
, FALSE
))
587 DBG1(DBG_IKE
, "Aggressive Mode authorization hook forbids IKE_SA, "
589 return send_notify(this, AUTHENTICATION_FAILED
);
597 METHOD(task_t
, get_type
, task_type_t
,
598 private_aggressive_mode_t
*this)
600 return TASK_AGGRESSIVE_MODE
;
603 METHOD(task_t
, migrate
, void,
604 private_aggressive_mode_t
*this, ike_sa_t
*ike_sa
)
606 DESTROY_IF(this->peer_cfg
);
607 DESTROY_IF(this->proposal
);
608 this->ph1
->destroy(this->ph1
);
609 chunk_free(&this->id_data
);
611 this->ike_sa
= ike_sa
;
612 this->state
= AM_INIT
;
613 this->peer_cfg
= NULL
;
614 this->proposal
= NULL
;
615 this->ph1
= phase1_create(ike_sa
, this->initiator
);
618 METHOD(task_t
, destroy
, void,
619 private_aggressive_mode_t
*this)
621 DESTROY_IF(this->peer_cfg
);
622 DESTROY_IF(this->proposal
);
623 this->ph1
->destroy(this->ph1
);
624 chunk_free(&this->id_data
);
629 * Described in header.
631 aggressive_mode_t
*aggressive_mode_create(ike_sa_t
*ike_sa
, bool initiator
)
633 private_aggressive_mode_t
*this;
638 .get_type
= _get_type
,
644 .ph1
= phase1_create(ike_sa
, initiator
),
645 .initiator
= initiator
,
651 this->public.task
.build
= _build_i
;
652 this->public.task
.process
= _process_i
;
656 this->public.task
.build
= _build_r
;
657 this->public.task
.process
= _process_r
;
660 return &this->public;