]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/charon-tkm/src/tkm/tkm_listener.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / charon-tkm / src / tkm / tkm_listener.c
1 /*
2 * Copyright (C) 2012 Reto Buerki
3 * Copyright (C) 2012 Adrian-Ken Rueegsegger
4 *
5 * Copyright (C) secunet Security Networks AG
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 <stdarg.h>
19 #include <inttypes.h>
20
21 #include <daemon.h>
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>
29
30 #include "tkm.h"
31 #include "tkm_listener.h"
32 #include "tkm_keymat.h"
33 #include "tkm_utils.h"
34
35 typedef struct private_tkm_listener_t private_tkm_listener_t;
36
37 static hashtable_t *ca_map = NULL;
38
39 /**
40 * Private data of a tkm_listener_t object.
41 */
42 struct private_tkm_listener_t {
43
44 /**
45 * Public tkm_listener_t interface.
46 */
47 tkm_listener_t public;
48
49 };
50
51 /**
52 * Return id of remote identity.
53 *
54 * TODO: Replace this with the lookup for the remote identity id.
55 *
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.
59 *
60 * @param peer_cfg Remote peer config
61 * @return remote identity id if found, 0 otherwise
62 */
63 static ri_id_type get_remote_identity_id(peer_cfg_t *peer)
64 {
65 ri_id_type remote_id = 0;
66 child_cfg_t *child;
67 enumerator_t* children;
68
69 children = peer->create_child_cfg_enumerator(peer);
70
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);
75
76 return remote_id;
77 }
78
79 /**
80 * Build a TKM certificate chain context with given cc id.
81 *
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,
85 * FALSE otherwise
86 */
87 static bool build_cert_chain(const ike_sa_t * const ike_sa, cc_id_type cc_id)
88 {
89 auth_cfg_t *auth;
90 certificate_t *cert;
91 enumerator_t *rounds;
92
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));
95
96 rounds = ike_sa->create_auth_cfg_enumerator((ike_sa_t *)ike_sa, FALSE);
97 while (rounds->enumerate(rounds, &auth))
98 {
99 cert = auth->get(auth, AUTH_RULE_CA_CERT);
100 if (cert)
101 {
102 auth_rule_t rule;
103 enumerator_t *enumerator;
104 ca_id_type ca_id;
105 public_key_t *pubkey;
106 certificate_type ca_cert;
107 chunk_t enc_ca_cert, fp;
108 array_t *im_certs = NULL;
109 uint64_t *raw_id;
110
111 pubkey = cert->get_public_key(cert);
112 if (!pubkey)
113 {
114 DBG1(DBG_IKE, "unable to get CA certificate pubkey");
115 rounds->destroy(rounds);
116 return FALSE;
117 }
118 if (!pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &fp))
119 {
120 DBG1(DBG_IKE, "unable to extract CA certificate fingerprint");
121 rounds->destroy(rounds);
122 pubkey->destroy(pubkey);
123 return FALSE;
124 }
125 pubkey->destroy(pubkey);
126
127 raw_id = ca_map->get(ca_map, &fp);
128 if (!raw_id || *raw_id == 0)
129 {
130 DBG1(DBG_IKE, "error mapping CA certificate (fp: %#B) to "
131 "ID", &fp);
132 rounds->destroy(rounds);
133 return FALSE;
134 }
135 ca_id = *raw_id;
136
137 if (!cert->get_encoding(cert, CERT_ASN1_DER, &enc_ca_cert))
138 {
139 DBG1(DBG_IKE, "unable to extract encoded CA certificate");
140 rounds->destroy(rounds);
141 return FALSE;
142 }
143
144 chunk_to_sequence(&enc_ca_cert, &ca_cert,
145 sizeof(certificate_type));
146 chunk_free(&enc_ca_cert);
147
148 if (ike_cc_check_ca(cc_id, ca_id, ca_cert) != TKM_OK)
149 {
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);
153 return FALSE;
154 }
155
156 /* process intermediate CA certificates in reverse order */
157 enumerator = auth->create_enumerator(auth);
158 while (enumerator->enumerate(enumerator, &rule, &cert))
159 {
160 if (rule == AUTH_RULE_IM_CERT)
161 {
162 array_insert_create(&im_certs, ARRAY_TAIL, cert);
163 }
164 }
165 enumerator->destroy(enumerator);
166
167 while (array_remove(im_certs, ARRAY_TAIL, &cert))
168 {
169 chunk_t enc_im_cert;
170 certificate_type im_cert;
171
172 if (!cert->get_encoding(cert, CERT_ASN1_DER, &enc_im_cert))
173 {
174 DBG1(DBG_IKE, "unable to extract encoded intermediate CA"
175 " certificate");
176 rounds->destroy(rounds);
177 array_destroy(im_certs);
178 return FALSE;
179 }
180
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)
185 {
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);
190 return FALSE;
191 }
192 }
193 array_destroy(im_certs);
194
195 /* finally add user certificate and check chain */
196 cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
197 if (cert)
198 {
199 chunk_t enc_user_cert;
200 ri_id_type ri_id;
201 certificate_type user_cert;
202
203 /* set user certificate */
204 if (!cert->get_encoding(cert, CERT_ASN1_DER, &enc_user_cert))
205 {
206 DBG1(DBG_IKE, "unable to extract encoded user certificate");
207 rounds->destroy(rounds);
208 return FALSE;
209 }
210
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)
214 {
215 DBG1(DBG_IKE, "error adding user certificate to cert chain"
216 " (cc_id: %llu)", cc_id);
217 rounds->destroy(rounds);
218 return FALSE;
219 }
220
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)
223 {
224 DBG1(DBG_IKE, "error checking cert chain (cc_id: %llu)", cc_id);
225 rounds->destroy(rounds);
226 return FALSE;
227 }
228
229 rounds->destroy(rounds);
230 return TRUE;
231 }
232 else
233 {
234 DBG1(DBG_IKE, "no subject certificate for remote peer");
235 }
236 }
237 else
238 {
239 DBG1(DBG_IKE, "no CA certificate");
240 }
241 }
242
243 rounds->destroy(rounds);
244 return FALSE;
245 }
246
247 METHOD(listener_t, alert, bool,
248 private_tkm_listener_t *this, ike_sa_t *ike_sa,
249 alert_t alert, va_list args)
250 {
251 if (alert == ALERT_KEEP_ON_CHILD_SA_FAILURE)
252 {
253 tkm_keymat_t *keymat;
254 isa_id_type isa_id;
255 int is_first;
256
257 is_first = va_arg(args, int);
258 if (!is_first)
259 {
260 return TRUE;
261 }
262
263 keymat = (tkm_keymat_t*)ike_sa->get_keymat(ike_sa);
264 isa_id = keymat->get_isa_id(keymat);
265
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)
268 {
269 DBG1(DBG_IKE, "Skip of first child SA creation failed for ISA "
270 "context %llu", isa_id);
271 }
272 }
273
274 return TRUE;
275 }
276
277 METHOD(listener_t, authorize, bool,
278 private_tkm_listener_t *this, ike_sa_t *ike_sa,
279 bool final, bool *success)
280 {
281 tkm_keymat_t *keymat;
282 isa_id_type isa_id;
283 cc_id_type cc_id;
284 chunk_t *auth, *other_init_msg;
285 signature_type signature;
286 init_message_type init_msg;
287
288 if (!final)
289 {
290 return TRUE;
291 }
292
293 *success = FALSE;
294
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);
298
299 cc_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_CC);
300 if (!cc_id)
301 {
302 DBG1(DBG_IKE, "unable to acquire CC context id");
303 return TRUE;
304 }
305 if (!build_cert_chain(ike_sa, cc_id))
306 {
307 DBG1(DBG_IKE, "unable to build certificate chain");
308 goto cc_reset;
309 }
310
311 auth = keymat->get_auth_payload(keymat);
312 if (!auth->ptr)
313 {
314 DBG1(DBG_IKE, "no AUTHENTICATION data available");
315 goto cc_reset;
316 }
317
318 other_init_msg = keymat->get_peer_init_msg(keymat);
319 if (!other_init_msg->ptr)
320 {
321 DBG1(DBG_IKE, "no peer init message available");
322 goto cc_reset;
323 }
324
325 chunk_to_sequence(auth, &signature, sizeof(signature_type));
326 chunk_to_sequence(other_init_msg, &init_msg, sizeof(init_message_type));
327
328 if (ike_isa_auth(isa_id, cc_id, init_msg, signature) != TKM_OK)
329 {
330 DBG1(DBG_IKE, "TKM based authentication failed"
331 " for ISA context %llu", isa_id);
332 goto cc_reset;
333 }
334 else
335 {
336 DBG1(DBG_IKE, "TKM based authentication successful"
337 " for ISA context %llu", isa_id);
338 *success = TRUE;
339 }
340
341 cc_reset:
342 if (ike_cc_reset(cc_id) != TKM_OK)
343 {
344 DBG1(DBG_IKE, "unable to reset CC context %llu", cc_id);
345 }
346 tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_CC, cc_id);
347 return TRUE; /* stay registered */
348 }
349
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)
353 {
354 tkm_keymat_t *keymat;
355 isa_id_type isa_id;
356 auth_payload_t *auth_payload;
357
358 if (!incoming || !plain || message->get_exchange_type(message) != IKE_AUTH)
359 {
360 return TRUE;
361 }
362
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);
367
368 auth_payload = (auth_payload_t*)message->get_payload(message,
369 PLV2_AUTH);
370 if (auth_payload)
371 {
372 chunk_t auth_data;
373
374 auth_data = auth_payload->get_data(auth_payload);
375 keymat->set_auth_payload(keymat, &auth_data);
376 }
377 else
378 {
379 DBG1(DBG_IKE, "unable to extract AUTHENTICATION payload, authorize will"
380 " fail");
381 }
382
383 return TRUE;
384 }
385
386 METHOD(tkm_listener_t, destroy, void,
387 private_tkm_listener_t *this)
388 {
389 free(this);
390 }
391
392 /**
393 * See header
394 */
395 tkm_listener_t *tkm_listener_create()
396 {
397 private_tkm_listener_t *this;
398
399 INIT(this,
400 .public = {
401 .listener = {
402 .authorize = _authorize,
403 .message = _message,
404 .alert = _alert,
405 },
406 .destroy = _destroy,
407 },
408 );
409
410 return &this->public;
411 }
412
413 static u_int hash(const chunk_t *key)
414 {
415 return chunk_hash(*key);
416 }
417
418 static bool equals(const chunk_t *key, const chunk_t *other_key)
419 {
420 return chunk_equals(*key, *other_key);
421 }
422
423 static u_int id_hash(const uint64_t *key)
424 {
425 return chunk_hash(chunk_create((u_char*)key, sizeof(uint64_t)));
426 }
427
428 static bool id_equals(const uint64_t *key, const uint64_t *other_key)
429 {
430 return *key == *other_key;
431 }
432
433 /*
434 * Described in header.
435 */
436 int register_ca_mapping()
437 {
438 char *section, *tkm_ca_id_str, *key_fp_str;
439 chunk_t *key_fp;
440 uint64_t *tkm_ca_id;
441 hashtable_t *id_map;
442 enumerator_t *enumerator;
443 bool err = FALSE;
444
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);
449
450 enumerator = lib->settings->create_section_enumerator(lib->settings,
451 "%s.ca_mapping",
452 lib->ns);
453 while (enumerator->enumerate(enumerator, &section))
454 {
455 tkm_ca_id_str = lib->settings->get_str(lib->settings,
456 "%s.ca_mapping.%s.id", NULL,
457 lib->ns, section);
458 tkm_ca_id = malloc_thing(uint64_t);
459 *tkm_ca_id = settings_value_as_uint64(tkm_ca_id_str, 0);
460
461 key_fp_str = lib->settings->get_str(lib->settings,
462 "%s.ca_mapping.%s.fingerprint", NULL,
463 lib->ns, section);
464 if (key_fp_str)
465 {
466 key_fp = malloc_thing(chunk_t);
467 *key_fp = chunk_from_hex(chunk_from_str(key_fp_str), NULL);
468 }
469
470 if (!*tkm_ca_id || !key_fp_str || !key_fp->len ||
471 id_map->get(id_map, tkm_ca_id) != NULL)
472 {
473 DBG1(DBG_CFG, "error adding CA ID mapping '%s': ID %s, FP '%s'",
474 section, tkm_ca_id_str, key_fp_str);
475 free(tkm_ca_id);
476 if (key_fp_str)
477 {
478 chunk_free(key_fp);
479 free(key_fp);
480 }
481 err = TRUE;
482 }
483 else
484 {
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);
490 }
491 }
492 enumerator->destroy(enumerator);
493 id_map->destroy(id_map);
494
495 return err ? 0 : ca_map->get_count(ca_map);
496 }
497
498 /*
499 * Described in header.
500 */
501 void destroy_ca_mapping()
502 {
503 enumerator_t *enumerator;
504 chunk_t *key;
505 uint64_t *value;
506
507 if (ca_map)
508 {
509 enumerator = ca_map->create_enumerator(ca_map);
510 while (enumerator->enumerate(enumerator, &key, &value))
511 {
512 chunk_free(key);
513 free(key);
514 free(value);
515 }
516 enumerator->destroy(enumerator);
517 ca_map->destroy(ca_map);
518 }
519 ca_map = NULL;
520 }