2 * Copyright (C) 2012 Reto Buerki
3 * Copyright (C) 2012 Adrian-Ken Rueegsegger
5 * Copyright (C) secunet Security Networks AG
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>.
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
22 #include <collections/array.h>
23 #include <collections/hashtable.h>
24 #include <encoding/payloads/auth_payload.h>
25 #include <utils/chunk.h>
26 #include <tkm/types.h>
27 #include <tkm/constants.h>
28 #include <tkm/client.h>
31 #include "tkm_listener.h"
32 #include "tkm_keymat.h"
33 #include "tkm_utils.h"
35 typedef struct private_tkm_listener_t private_tkm_listener_t
;
37 static hashtable_t
*ca_map
= NULL
;
40 * Private data of a tkm_listener_t object.
42 struct private_tkm_listener_t
{
45 * Public tkm_listener_t interface.
47 tkm_listener_t
public;
52 * Return id of remote identity.
54 * TODO: Replace this with the lookup for the remote identity id.
56 * Currently the reqid of the first child SA in peer config of IKE SA is
57 * returned. Might choose wrong reqid if IKE SA has multiple child configs
58 * with different reqids.
60 * @param peer_cfg Remote peer config
61 * @return remote identity id if found, 0 otherwise
63 static ri_id_type
get_remote_identity_id(peer_cfg_t
*peer
)
65 ri_id_type remote_id
= 0;
67 enumerator_t
* children
;
69 children
= peer
->create_child_cfg_enumerator(peer
);
71 /* pick the reqid of the first child, no need to enumerate all children. */
72 children
->enumerate(children
, &child
);
73 remote_id
= child
->get_reqid(child
);
74 children
->destroy(children
);
80 * Build a TKM certificate chain context with given cc id.
82 * @param ike_sa IKE SA containing auth config to build certificate chain from
83 * @param cc_id Certificate chain ID
84 * @return TRUE if certificate chain was built successfully,
87 static bool build_cert_chain(const ike_sa_t
* const ike_sa
, cc_id_type cc_id
)
93 DBG1(DBG_IKE
, "building certificate chain context %llu for IKE SA %s",
94 cc_id
, ike_sa
->get_name((ike_sa_t
*)ike_sa
));
96 rounds
= ike_sa
->create_auth_cfg_enumerator((ike_sa_t
*)ike_sa
, FALSE
);
97 while (rounds
->enumerate(rounds
, &auth
))
99 cert
= auth
->get(auth
, AUTH_RULE_CA_CERT
);
103 enumerator_t
*enumerator
;
105 public_key_t
*pubkey
;
106 certificate_type ca_cert
;
107 chunk_t enc_ca_cert
, fp
;
108 array_t
*im_certs
= NULL
;
111 pubkey
= cert
->get_public_key(cert
);
114 DBG1(DBG_IKE
, "unable to get CA certificate pubkey");
115 rounds
->destroy(rounds
);
118 if (!pubkey
->get_fingerprint(pubkey
, KEYID_PUBKEY_SHA1
, &fp
))
120 DBG1(DBG_IKE
, "unable to extract CA certificate fingerprint");
121 rounds
->destroy(rounds
);
122 pubkey
->destroy(pubkey
);
125 pubkey
->destroy(pubkey
);
127 raw_id
= ca_map
->get(ca_map
, &fp
);
128 if (!raw_id
|| *raw_id
== 0)
130 DBG1(DBG_IKE
, "error mapping CA certificate (fp: %#B) to "
132 rounds
->destroy(rounds
);
137 if (!cert
->get_encoding(cert
, CERT_ASN1_DER
, &enc_ca_cert
))
139 DBG1(DBG_IKE
, "unable to extract encoded CA certificate");
140 rounds
->destroy(rounds
);
144 chunk_to_sequence(&enc_ca_cert
, &ca_cert
,
145 sizeof(certificate_type
));
146 chunk_free(&enc_ca_cert
);
148 if (ike_cc_check_ca(cc_id
, ca_id
, ca_cert
) != TKM_OK
)
150 DBG1(DBG_IKE
, "CA certificate (fp: %#B, cc_id: %llu) does not"
151 " match trusted CA (ca_id: %llu)", &fp
, cc_id
, ca_id
);
152 rounds
->destroy(rounds
);
156 /* process intermediate CA certificates in reverse order */
157 enumerator
= auth
->create_enumerator(auth
);
158 while (enumerator
->enumerate(enumerator
, &rule
, &cert
))
160 if (rule
== AUTH_RULE_IM_CERT
)
162 array_insert_create(&im_certs
, ARRAY_TAIL
, cert
);
165 enumerator
->destroy(enumerator
);
167 while (array_remove(im_certs
, ARRAY_TAIL
, &cert
))
170 certificate_type im_cert
;
172 if (!cert
->get_encoding(cert
, CERT_ASN1_DER
, &enc_im_cert
))
174 DBG1(DBG_IKE
, "unable to extract encoded intermediate CA"
176 rounds
->destroy(rounds
);
177 array_destroy(im_certs
);
181 chunk_to_sequence(&enc_im_cert
, &im_cert
,
182 sizeof(certificate_type
));
183 chunk_free(&enc_im_cert
);
184 if (ike_cc_add_certificate(cc_id
, 1, im_cert
) != TKM_OK
)
186 DBG1(DBG_IKE
, "error adding intermediate certificate to"
187 " cert chain (cc_id: %llu)", cc_id
);
188 rounds
->destroy(rounds
);
189 array_destroy(im_certs
);
193 array_destroy(im_certs
);
195 /* finally add user certificate and check chain */
196 cert
= auth
->get(auth
, AUTH_RULE_SUBJECT_CERT
);
199 chunk_t enc_user_cert
;
201 certificate_type user_cert
;
203 /* set user certificate */
204 if (!cert
->get_encoding(cert
, CERT_ASN1_DER
, &enc_user_cert
))
206 DBG1(DBG_IKE
, "unable to extract encoded user certificate");
207 rounds
->destroy(rounds
);
211 chunk_to_sequence(&enc_user_cert
, &user_cert
, sizeof(certificate_type
));
212 chunk_free(&enc_user_cert
);
213 if (ike_cc_add_certificate(cc_id
, 1, user_cert
) != TKM_OK
)
215 DBG1(DBG_IKE
, "error adding user certificate to cert chain"
216 " (cc_id: %llu)", cc_id
);
217 rounds
->destroy(rounds
);
221 ri_id
= get_remote_identity_id(ike_sa
->get_peer_cfg((ike_sa_t
*)ike_sa
));
222 if (ike_cc_check_chain(cc_id
, ri_id
) != TKM_OK
)
224 DBG1(DBG_IKE
, "error checking cert chain (cc_id: %llu)", cc_id
);
225 rounds
->destroy(rounds
);
229 rounds
->destroy(rounds
);
234 DBG1(DBG_IKE
, "no subject certificate for remote peer");
239 DBG1(DBG_IKE
, "no CA certificate");
243 rounds
->destroy(rounds
);
247 METHOD(listener_t
, alert
, bool,
248 private_tkm_listener_t
*this, ike_sa_t
*ike_sa
,
249 alert_t alert
, va_list args
)
251 if (alert
== ALERT_KEEP_ON_CHILD_SA_FAILURE
)
253 tkm_keymat_t
*keymat
;
257 is_first
= va_arg(args
, int);
263 keymat
= (tkm_keymat_t
*)ike_sa
->get_keymat(ike_sa
);
264 isa_id
= keymat
->get_isa_id(keymat
);
266 DBG1(DBG_IKE
, "TKM alert listener called for ISA context %llu", isa_id
);
267 if (ike_isa_skip_create_first(isa_id
) != TKM_OK
)
269 DBG1(DBG_IKE
, "Skip of first child SA creation failed for ISA "
270 "context %llu", isa_id
);
277 METHOD(listener_t
, authorize
, bool,
278 private_tkm_listener_t
*this, ike_sa_t
*ike_sa
,
279 bool final
, bool *success
)
281 tkm_keymat_t
*keymat
;
284 chunk_t
*auth
, *other_init_msg
;
285 signature_type signature
;
286 init_message_type init_msg
;
295 keymat
= (tkm_keymat_t
*)ike_sa
->get_keymat(ike_sa
);
296 isa_id
= keymat
->get_isa_id(keymat
);
297 DBG1(DBG_IKE
, "TKM authorize listener called for ISA context %llu", isa_id
);
299 cc_id
= tkm
->idmgr
->acquire_id(tkm
->idmgr
, TKM_CTX_CC
);
302 DBG1(DBG_IKE
, "unable to acquire CC context id");
305 if (!build_cert_chain(ike_sa
, cc_id
))
307 DBG1(DBG_IKE
, "unable to build certificate chain");
311 auth
= keymat
->get_auth_payload(keymat
);
314 DBG1(DBG_IKE
, "no AUTHENTICATION data available");
318 other_init_msg
= keymat
->get_peer_init_msg(keymat
);
319 if (!other_init_msg
->ptr
)
321 DBG1(DBG_IKE
, "no peer init message available");
325 chunk_to_sequence(auth
, &signature
, sizeof(signature_type
));
326 chunk_to_sequence(other_init_msg
, &init_msg
, sizeof(init_message_type
));
328 if (ike_isa_auth(isa_id
, cc_id
, init_msg
, signature
) != TKM_OK
)
330 DBG1(DBG_IKE
, "TKM based authentication failed"
331 " for ISA context %llu", isa_id
);
336 DBG1(DBG_IKE
, "TKM based authentication successful"
337 " for ISA context %llu", isa_id
);
342 if (ike_cc_reset(cc_id
) != TKM_OK
)
344 DBG1(DBG_IKE
, "unable to reset CC context %llu", cc_id
);
346 tkm
->idmgr
->release_id(tkm
->idmgr
, TKM_CTX_CC
, cc_id
);
347 return TRUE
; /* stay registered */
350 METHOD(listener_t
, message
, bool,
351 private_tkm_listener_t
*this, ike_sa_t
*ike_sa
,
352 message_t
*message
, bool incoming
, bool plain
)
354 tkm_keymat_t
*keymat
;
356 auth_payload_t
*auth_payload
;
358 if (!incoming
|| !plain
|| message
->get_exchange_type(message
) != IKE_AUTH
)
363 keymat
= (tkm_keymat_t
*)ike_sa
->get_keymat(ike_sa
);
364 isa_id
= keymat
->get_isa_id(keymat
);
365 DBG1(DBG_IKE
, "saving AUTHENTICATION payload for authorize hook"
366 " (ISA context %llu)", isa_id
);
368 auth_payload
= (auth_payload_t
*)message
->get_payload(message
,
374 auth_data
= auth_payload
->get_data(auth_payload
);
375 keymat
->set_auth_payload(keymat
, &auth_data
);
379 DBG1(DBG_IKE
, "unable to extract AUTHENTICATION payload, authorize will"
386 METHOD(tkm_listener_t
, destroy
, void,
387 private_tkm_listener_t
*this)
395 tkm_listener_t
*tkm_listener_create()
397 private_tkm_listener_t
*this;
402 .authorize
= _authorize
,
410 return &this->public;
413 static u_int
hash(const chunk_t
*key
)
415 return chunk_hash(*key
);
418 static bool equals(const chunk_t
*key
, const chunk_t
*other_key
)
420 return chunk_equals(*key
, *other_key
);
423 static u_int
id_hash(const uint64_t *key
)
425 return chunk_hash(chunk_create((u_char
*)key
, sizeof(uint64_t)));
428 static bool id_equals(const uint64_t *key
, const uint64_t *other_key
)
430 return *key
== *other_key
;
434 * Described in header.
436 int register_ca_mapping()
438 char *section
, *tkm_ca_id_str
, *key_fp_str
;
442 enumerator_t
*enumerator
;
445 ca_map
= hashtable_create((hashtable_hash_t
)hash
,
446 (hashtable_equals_t
)equals
, 8);
447 id_map
= hashtable_create((hashtable_hash_t
)id_hash
,
448 (hashtable_equals_t
)id_equals
, 8);
450 enumerator
= lib
->settings
->create_section_enumerator(lib
->settings
,
453 while (enumerator
->enumerate(enumerator
, §ion
))
455 tkm_ca_id_str
= lib
->settings
->get_str(lib
->settings
,
456 "%s.ca_mapping.%s.id", NULL
,
458 tkm_ca_id
= malloc_thing(uint64_t);
459 *tkm_ca_id
= settings_value_as_uint64(tkm_ca_id_str
, 0);
461 key_fp_str
= lib
->settings
->get_str(lib
->settings
,
462 "%s.ca_mapping.%s.fingerprint", NULL
,
466 key_fp
= malloc_thing(chunk_t
);
467 *key_fp
= chunk_from_hex(chunk_from_str(key_fp_str
), NULL
);
470 if (!*tkm_ca_id
|| !key_fp_str
|| !key_fp
->len
||
471 id_map
->get(id_map
, tkm_ca_id
) != NULL
)
473 DBG1(DBG_CFG
, "error adding CA ID mapping '%s': ID %s, FP '%s'",
474 section
, tkm_ca_id_str
, key_fp_str
);
485 DBG2(DBG_CFG
, "adding CA ID mapping '%s': ID %" PRIu64
", FP '%#B'",
486 section
, *tkm_ca_id
, key_fp
);
487 ca_map
->put(ca_map
, key_fp
, tkm_ca_id
);
488 /* track CA IDs for uniqueness, set value to not-NULL */
489 id_map
->put(id_map
, tkm_ca_id
, id_map
);
492 enumerator
->destroy(enumerator
);
493 id_map
->destroy(id_map
);
495 return err
? 0 : ca_map
->get_count(ca_map
);
499 * Described in header.
501 void destroy_ca_mapping()
503 enumerator_t
*enumerator
;
509 enumerator
= ca_map
->create_enumerator(ca_map
);
510 while (enumerator
->enumerate(enumerator
, &key
, &value
))
516 enumerator
->destroy(enumerator
);
517 ca_map
->destroy(ca_map
);