2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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
18 #include <sa/ikev2/keymat_v2.h>
19 #include <sa/ikev1/keymat_v1.h>
21 typedef struct private_ha_ike_t private_ha_ike_t
;
24 * Private data of an ha_ike_t object.
26 struct private_ha_ike_t
{
29 * Public ha_ike_t interface.
34 * socket we use for syncing
39 * tunnel securing sync messages
50 * Return condition if it is set on ike_sa
52 static ike_condition_t
copy_condition(ike_sa_t
*ike_sa
, ike_condition_t cond
)
54 if (ike_sa
->has_condition(ike_sa
, cond
))
62 * Return extension if it is supported by peers IKE_SA
64 static ike_extension_t
copy_extension(ike_sa_t
*ike_sa
, ike_extension_t ext
)
66 if (ike_sa
->supports_extension(ike_sa
, ext
))
73 METHOD(listener_t
, ike_keys
, bool,
74 private_ha_ike_t
*this, ike_sa_t
*ike_sa
, diffie_hellman_t
*dh
,
75 chunk_t dh_other
, chunk_t nonce_i
, chunk_t nonce_r
, ike_sa_t
*rekey
,
83 if (this->tunnel
&& this->tunnel
->is_sa(this->tunnel
, ike_sa
))
84 { /* do not sync SA between nodes */
87 if (!dh
->get_shared_secret(dh
, &secret
))
92 m
= ha_message_create(HA_IKE_ADD
);
93 m
->add_attribute(m
, HA_IKE_VERSION
, ike_sa
->get_version(ike_sa
));
94 m
->add_attribute(m
, HA_IKE_ID
, ike_sa
->get_id(ike_sa
));
96 if (rekey
&& rekey
->get_version(rekey
) == IKEV2
)
101 keymat
= (keymat_v2_t
*)rekey
->get_keymat(rekey
);
102 m
->add_attribute(m
, HA_IKE_REKEY_ID
, rekey
->get_id(rekey
));
103 m
->add_attribute(m
, HA_ALG_OLD_PRF
, keymat
->get_skd(keymat
, &skd
));
104 m
->add_attribute(m
, HA_OLD_SKD
, skd
);
107 proposal
= ike_sa
->get_proposal(ike_sa
);
108 if (proposal
->get_algorithm(proposal
, ENCRYPTION_ALGORITHM
, &alg
, &len
))
110 m
->add_attribute(m
, HA_ALG_ENCR
, alg
);
113 m
->add_attribute(m
, HA_ALG_ENCR_LEN
, len
);
116 if (proposal
->get_algorithm(proposal
, INTEGRITY_ALGORITHM
, &alg
, NULL
))
118 m
->add_attribute(m
, HA_ALG_INTEG
, alg
);
120 if (proposal
->get_algorithm(proposal
, PSEUDO_RANDOM_FUNCTION
, &alg
, NULL
))
122 m
->add_attribute(m
, HA_ALG_PRF
, alg
);
124 if (proposal
->get_algorithm(proposal
, DIFFIE_HELLMAN_GROUP
, &alg
, NULL
))
126 m
->add_attribute(m
, HA_ALG_DH
, alg
);
128 m
->add_attribute(m
, HA_NONCE_I
, nonce_i
);
129 m
->add_attribute(m
, HA_NONCE_R
, nonce_r
);
130 m
->add_attribute(m
, HA_SECRET
, secret
);
131 chunk_clear(&secret
);
132 if (ike_sa
->get_version(ike_sa
) == IKEV1
)
134 if (dh
->get_my_public_value(dh
, &secret
))
136 m
->add_attribute(m
, HA_LOCAL_DH
, secret
);
139 m
->add_attribute(m
, HA_REMOTE_DH
, dh_other
);
142 m
->add_attribute(m
, HA_PSK
, shared
->get_key(shared
));
145 m
->add_attribute(m
, HA_REMOTE_ADDR
, ike_sa
->get_other_host(ike_sa
));
147 this->socket
->push(this->socket
, m
);
148 this->cache
->cache(this->cache
, ike_sa
, m
);
153 METHOD(listener_t
, ike_updown
, bool,
154 private_ha_ike_t
*this, ike_sa_t
*ike_sa
, bool up
)
158 if (ike_sa
->get_state(ike_sa
) == IKE_PASSIVE
)
159 { /* only sync active IKE_SAs */
162 if (this->tunnel
&& this->tunnel
->is_sa(this->tunnel
, ike_sa
))
163 { /* do not sync SA between nodes */
169 enumerator_t
*enumerator
;
170 peer_cfg_t
*peer_cfg
;
171 u_int32_t extension
, condition
;
174 identification_t
*eap_id
;
176 peer_cfg
= ike_sa
->get_peer_cfg(ike_sa
);
178 condition
= copy_condition(ike_sa
, COND_NAT_ANY
)
179 | copy_condition(ike_sa
, COND_NAT_HERE
)
180 | copy_condition(ike_sa
, COND_NAT_THERE
)
181 | copy_condition(ike_sa
, COND_NAT_FAKE
)
182 | copy_condition(ike_sa
, COND_EAP_AUTHENTICATED
)
183 | copy_condition(ike_sa
, COND_CERTREQ_SEEN
)
184 | copy_condition(ike_sa
, COND_ORIGINAL_INITIATOR
)
185 | copy_condition(ike_sa
, COND_STALE
)
186 | copy_condition(ike_sa
, COND_INIT_CONTACT_SEEN
)
187 | copy_condition(ike_sa
, COND_XAUTH_AUTHENTICATED
);
189 extension
= copy_extension(ike_sa
, EXT_NATT
)
190 | copy_extension(ike_sa
, EXT_MOBIKE
)
191 | copy_extension(ike_sa
, EXT_HASH_AND_URL
)
192 | copy_extension(ike_sa
, EXT_MULTIPLE_AUTH
)
193 | copy_extension(ike_sa
, EXT_STRONGSWAN
)
194 | copy_extension(ike_sa
, EXT_EAP_ONLY_AUTHENTICATION
)
195 | copy_extension(ike_sa
, EXT_MS_WINDOWS
)
196 | copy_extension(ike_sa
, EXT_XAUTH
)
197 | copy_extension(ike_sa
, EXT_DPD
);
199 id
= ike_sa
->get_id(ike_sa
);
201 m
= ha_message_create(HA_IKE_UPDATE
);
202 m
->add_attribute(m
, HA_IKE_ID
, id
);
203 m
->add_attribute(m
, HA_LOCAL_ID
, ike_sa
->get_my_id(ike_sa
));
204 m
->add_attribute(m
, HA_REMOTE_ID
, ike_sa
->get_other_id(ike_sa
));
205 eap_id
= ike_sa
->get_other_eap_id(ike_sa
);
206 if (!eap_id
->equals(eap_id
, ike_sa
->get_other_id(ike_sa
)))
208 m
->add_attribute(m
, HA_REMOTE_EAP_ID
, eap_id
);
210 m
->add_attribute(m
, HA_LOCAL_ADDR
, ike_sa
->get_my_host(ike_sa
));
211 m
->add_attribute(m
, HA_REMOTE_ADDR
, ike_sa
->get_other_host(ike_sa
));
212 m
->add_attribute(m
, HA_CONDITIONS
, condition
);
213 m
->add_attribute(m
, HA_EXTENSIONS
, extension
);
214 m
->add_attribute(m
, HA_CONFIG_NAME
, peer_cfg
->get_name(peer_cfg
));
215 enumerator
= ike_sa
->create_peer_address_enumerator(ike_sa
);
216 while (enumerator
->enumerate(enumerator
, (void**)&addr
))
218 m
->add_attribute(m
, HA_PEER_ADDR
, addr
);
220 enumerator
->destroy(enumerator
);
224 m
= ha_message_create(HA_IKE_DELETE
);
225 m
->add_attribute(m
, HA_IKE_ID
, ike_sa
->get_id(ike_sa
));
227 this->socket
->push(this->socket
, m
);
228 this->cache
->cache(this->cache
, ike_sa
, m
);
232 METHOD(listener_t
, ike_rekey
, bool,
233 private_ha_ike_t
*this, ike_sa_t
*old
, ike_sa_t
*new)
235 ike_updown(this, old
, FALSE
);
236 ike_updown(this, new, TRUE
);
240 METHOD(listener_t
, ike_state_change
, bool,
241 private_ha_ike_t
*this, ike_sa_t
*ike_sa
, ike_sa_state_t
new)
243 /* delete any remaining cache entry if IKE_SA gets destroyed */
244 if (new == IKE_DESTROYING
)
246 this->cache
->delete(this->cache
, ike_sa
);
252 * Send a virtual IP sync message for remote VIPs
254 static void sync_vips(private_ha_ike_t
*this, ike_sa_t
*ike_sa
)
256 ha_message_t
*m
= NULL
;
257 enumerator_t
*enumerator
;
260 enumerator
= ike_sa
->create_virtual_ip_enumerator(ike_sa
, FALSE
);
261 while (enumerator
->enumerate(enumerator
, &vip
))
265 m
= ha_message_create(HA_IKE_UPDATE
);
266 m
->add_attribute(m
, HA_IKE_ID
, ike_sa
->get_id(ike_sa
));
268 m
->add_attribute(m
, HA_REMOTE_VIP
, vip
);
270 enumerator
->destroy(enumerator
);
274 this->socket
->push(this->socket
, m
);
275 this->cache
->cache(this->cache
, ike_sa
, m
);
279 METHOD(listener_t
, message_hook
, bool,
280 private_ha_ike_t
*this, ike_sa_t
*ike_sa
, message_t
*message
,
281 bool incoming
, bool plain
)
283 if (this->tunnel
&& this->tunnel
->is_sa(this->tunnel
, ike_sa
))
284 { /* do not sync SA between nodes */
288 if (plain
&& ike_sa
->get_version(ike_sa
) == IKEV2
)
290 if (message
->get_exchange_type(message
) != IKE_SA_INIT
&&
291 message
->get_request(message
))
292 { /* we sync on requests, but skip it on IKE_SA_INIT */
297 m
= ha_message_create(HA_IKE_MID_RESPONDER
);
301 m
= ha_message_create(HA_IKE_MID_INITIATOR
);
303 m
->add_attribute(m
, HA_IKE_ID
, ike_sa
->get_id(ike_sa
));
304 m
->add_attribute(m
, HA_MID
, message
->get_message_id(message
) + 1);
305 this->socket
->push(this->socket
, m
);
306 this->cache
->cache(this->cache
, ike_sa
, m
);
308 if (ike_sa
->get_state(ike_sa
) == IKE_ESTABLISHED
&&
309 message
->get_exchange_type(message
) == IKE_AUTH
&&
310 !message
->get_request(message
))
311 { /* After IKE_SA has been established, sync peers virtual IP.
312 * We cannot sync it in the state_change hook, it is installed later.
313 * TODO: where to sync local VIP? */
314 sync_vips(this, ike_sa
);
317 if (ike_sa
->get_version(ike_sa
) == IKEV1
)
323 /* we need the last block (or expected next IV) of Phase 1, which gets
324 * upated after successful en-/decryption depending on direction */
325 if (incoming
== plain
)
327 if (message
->get_message_id(message
) == 0)
329 keymat
= (keymat_v1_t
*)ike_sa
->get_keymat(ike_sa
);
330 if (keymat
->get_iv(keymat
, 0, &iv
))
332 m
= ha_message_create(HA_IKE_IV
);
333 m
->add_attribute(m
, HA_IKE_ID
, ike_sa
->get_id(ike_sa
));
334 m
->add_attribute(m
, HA_IV
, iv
);
335 this->socket
->push(this->socket
, m
);
336 this->cache
->cache(this->cache
, ike_sa
, m
);
340 if (!plain
&& !incoming
&&
341 message
->get_exchange_type(message
) == TRANSACTION
)
343 sync_vips(this, ike_sa
);
346 if (plain
&& ike_sa
->get_version(ike_sa
) == IKEV1
&&
347 message
->get_exchange_type(message
) == INFORMATIONAL_V1
)
350 notify_payload_t
*notify
;
354 notify
= message
->get_notify(message
, DPD_R_U_THERE
);
357 data
= notify
->get_notification_data(notify
);
360 seq
= untoh32(data
.ptr
);
363 m
= ha_message_create(HA_IKE_MID_RESPONDER
);
367 m
= ha_message_create(HA_IKE_MID_INITIATOR
);
369 m
->add_attribute(m
, HA_IKE_ID
, ike_sa
->get_id(ike_sa
));
370 m
->add_attribute(m
, HA_MID
, seq
+ 1);
371 this->socket
->push(this->socket
, m
);
372 this->cache
->cache(this->cache
, ike_sa
, m
);
379 METHOD(ha_ike_t
, destroy
, void,
380 private_ha_ike_t
*this)
388 ha_ike_t
*ha_ike_create(ha_socket_t
*socket
, ha_tunnel_t
*tunnel
,
391 private_ha_ike_t
*this;
396 .ike_keys
= _ike_keys
,
397 .ike_updown
= _ike_updown
,
398 .ike_rekey
= _ike_rekey
,
399 .ike_state_change
= _ike_state_change
,
400 .message
= _message_hook
,
409 return &this->public;