2 * Copyright (C) 2008 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 #include "stroke_ca.h"
18 #include "stroke_cred.h"
20 #include <threading/rwlock.h>
21 #include <collections/linked_list.h>
22 #include <crypto/hashers/hasher.h>
26 typedef struct private_stroke_ca_t private_stroke_ca_t
;
29 * private data of stroke_ca
31 struct private_stroke_ca_t
{
39 * read-write lock to lists
44 * list of starters CA sections and its certificates (ca_section_t)
46 linked_list_t
*sections
;
49 * stroke credentials, stores our CA certificates
54 typedef struct ca_section_t ca_section_t
;
57 * loaded ipsec.conf CA sections
62 * name of the CA section
67 * reference to cert in trusted_credential_t
82 * Hashes of certificates issued by this CA
84 linked_list_t
*hashes
;
87 * Base URI used for certificates from this CA
93 * create a new CA section
95 static ca_section_t
*ca_section_create(char *name
, certificate_t
*cert
)
97 ca_section_t
*ca
= malloc_thing(ca_section_t
);
99 ca
->name
= strdup(name
);
100 ca
->crl
= linked_list_create();
101 ca
->ocsp
= linked_list_create();
103 ca
->hashes
= linked_list_create();
104 ca
->certuribase
= NULL
;
109 * destroy a ca section entry
111 static void ca_section_destroy(ca_section_t
*this)
113 this->crl
->destroy_function(this->crl
, free
);
114 this->ocsp
->destroy_function(this->ocsp
, free
);
115 this->hashes
->destroy_offset(this->hashes
, offsetof(identification_t
, destroy
));
116 this->cert
->destroy(this->cert
);
117 free(this->certuribase
);
123 * Data for the certificate enumerator
126 private_stroke_ca_t
*this;
127 certificate_type_t cert
;
129 identification_t
*id
;
135 static void cert_data_destroy(cert_data_t
*data
)
137 data
->this->lock
->unlock(data
->this->lock
);
142 * filter function for certs enumerator
144 static bool certs_filter(cert_data_t
*data
, ca_section_t
**in
,
147 public_key_t
*public;
148 certificate_t
*cert
= (*in
)->cert
;
150 if (data
->cert
== CERT_ANY
|| data
->cert
== cert
->get_type(cert
))
152 public = cert
->get_public_key(cert
);
155 if (data
->key
== KEY_ANY
|| data
->key
== public->get_type(public))
157 if (data
->id
&& public->has_fingerprint(public,
158 data
->id
->get_encoding(data
->id
)))
160 public->destroy(public);
165 public->destroy(public);
167 else if (data
->key
!= KEY_ANY
)
171 if (data
->id
== NULL
|| cert
->has_subject(cert
, data
->id
))
180 METHOD(credential_set_t
, create_cert_enumerator
, enumerator_t
*,
181 private_stroke_ca_t
*this, certificate_type_t cert
, key_type_t key
,
182 identification_t
*id
, bool trusted
)
184 enumerator_t
*enumerator
;
194 this->lock
->read_lock(this->lock
);
195 enumerator
= this->sections
->create_enumerator(this->sections
);
196 return enumerator_create_filter(enumerator
, (void*)certs_filter
, data
,
197 (void*)cert_data_destroy
);
201 * data to pass to create_inner_cdp
204 private_stroke_ca_t
*this;
205 certificate_type_t type
;
206 identification_t
*id
;
210 * destroy cdp enumerator data and unlock list
212 static void cdp_data_destroy(cdp_data_t
*data
)
214 data
->this->lock
->unlock(data
->this->lock
);
219 * inner enumerator constructor for CDP URIs
221 static enumerator_t
*create_inner_cdp(ca_section_t
*section
, cdp_data_t
*data
)
223 public_key_t
*public;
224 enumerator_t
*enumerator
= NULL
;
227 if (data
->type
== CERT_X509_OCSP_RESPONSE
)
229 list
= section
->ocsp
;
236 public = section
->cert
->get_public_key(section
->cert
);
241 enumerator
= list
->create_enumerator(list
);
245 if (public->has_fingerprint(public, data
->id
->get_encoding(data
->id
)))
247 enumerator
= list
->create_enumerator(list
);
250 public->destroy(public);
256 * inner enumerator constructor for "Hash and URL"
258 static enumerator_t
*create_inner_cdp_hashandurl(ca_section_t
*section
, cdp_data_t
*data
)
260 enumerator_t
*enumerator
= NULL
, *hash_enum
;
261 identification_t
*current
;
263 if (!data
->id
|| !section
->certuribase
)
268 hash_enum
= section
->hashes
->create_enumerator(section
->hashes
);
269 while (hash_enum
->enumerate(hash_enum
, ¤t
))
271 if (current
->matches(current
, data
->id
))
275 url
= malloc(strlen(section
->certuribase
) + 40 + 1);
276 strcpy(url
, section
->certuribase
);
277 hash
= chunk_to_hex(current
->get_encoding(current
), NULL
, FALSE
).ptr
;
278 strncat(url
, hash
, 40);
281 enumerator
= enumerator_create_single(url
, free
);
285 hash_enum
->destroy(hash_enum
);
289 METHOD(credential_set_t
, create_cdp_enumerator
, enumerator_t
*,
290 private_stroke_ca_t
*this, certificate_type_t type
, identification_t
*id
)
295 { /* we serve CRLs, OCSP responders and URLs for "Hash and URL" */
298 case CERT_X509_OCSP_RESPONSE
:
304 data
= malloc_thing(cdp_data_t
);
309 this->lock
->read_lock(this->lock
);
310 return enumerator_create_nested(this->sections
->create_enumerator(this->sections
),
311 (type
== CERT_X509
) ?
(void*)create_inner_cdp_hashandurl
: (void*)create_inner_cdp
,
312 data
, (void*)cdp_data_destroy
);
315 METHOD(stroke_ca_t
, add
, void,
316 private_stroke_ca_t
*this, stroke_msg_t
*msg
)
321 if (msg
->add_ca
.cacert
== NULL
)
323 DBG1(DBG_CFG
, "missing cacert parameter");
326 cert
= this->cred
->load_ca(this->cred
, msg
->add_ca
.cacert
);
329 ca
= ca_section_create(msg
->add_ca
.name
, cert
);
330 if (msg
->add_ca
.crluri
)
332 ca
->crl
->insert_last(ca
->crl
, strdup(msg
->add_ca
.crluri
));
334 if (msg
->add_ca
.crluri2
)
336 ca
->crl
->insert_last(ca
->crl
, strdup(msg
->add_ca
.crluri2
));
338 if (msg
->add_ca
.ocspuri
)
340 ca
->ocsp
->insert_last(ca
->ocsp
, strdup(msg
->add_ca
.ocspuri
));
342 if (msg
->add_ca
.ocspuri2
)
344 ca
->ocsp
->insert_last(ca
->ocsp
, strdup(msg
->add_ca
.ocspuri2
));
346 if (msg
->add_ca
.certuribase
)
348 ca
->certuribase
= strdup(msg
->add_ca
.certuribase
);
350 this->lock
->write_lock(this->lock
);
351 this->sections
->insert_last(this->sections
, ca
);
352 this->lock
->unlock(this->lock
);
353 DBG1(DBG_CFG
, "added ca '%s'", msg
->add_ca
.name
);
357 METHOD(stroke_ca_t
, del
, void,
358 private_stroke_ca_t
*this, stroke_msg_t
*msg
)
360 enumerator_t
*enumerator
;
361 ca_section_t
*ca
= NULL
;
363 this->lock
->write_lock(this->lock
);
364 enumerator
= this->sections
->create_enumerator(this->sections
);
365 while (enumerator
->enumerate(enumerator
, &ca
))
367 if (streq(ca
->name
, msg
->del_ca
.name
))
369 this->sections
->remove_at(this->sections
, enumerator
);
374 enumerator
->destroy(enumerator
);
375 this->lock
->unlock(this->lock
);
378 DBG1(DBG_CFG
, "no ca named '%s' found\n", msg
->del_ca
.name
);
381 ca_section_destroy(ca
);
383 lib
->credmgr
->flush_cache(lib
->credmgr
, CERT_ANY
);
387 * list crl or ocsp URIs
389 static void list_uris(linked_list_t
*list
, char *label
, FILE *out
)
393 enumerator_t
*enumerator
;
395 enumerator
= list
->create_enumerator(list
);
396 while (enumerator
->enumerate(enumerator
, (void**)&uri
))
400 fprintf(out
, "%s", label
);
407 fprintf(out
, "'%s'\n", uri
);
409 enumerator
->destroy(enumerator
);
412 METHOD(stroke_ca_t
, check_for_hash_and_url
, void,
413 private_stroke_ca_t
*this, certificate_t
* cert
)
415 ca_section_t
*section
;
416 enumerator_t
*enumerator
;
418 hasher_t
*hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
);
421 DBG1(DBG_IKE
, "unable to use hash-and-url: sha1 not supported");
425 this->lock
->write_lock(this->lock
);
426 enumerator
= this->sections
->create_enumerator(this->sections
);
427 while (enumerator
->enumerate(enumerator
, (void**)§ion
))
429 if (section
->certuribase
&& cert
->issued_by(cert
, section
->cert
, NULL
))
431 chunk_t hash
, encoded
;
433 if (cert
->get_encoding(cert
, CERT_ASN1_DER
, &encoded
))
435 if (hasher
->allocate_hash(hasher
, encoded
, &hash
))
437 section
->hashes
->insert_last(section
->hashes
,
438 identification_create_from_encoding(ID_KEY_ID
, hash
));
441 chunk_free(&encoded
);
446 enumerator
->destroy(enumerator
);
447 this->lock
->unlock(this->lock
);
449 hasher
->destroy(hasher
);
452 METHOD(stroke_ca_t
, list
, void,
453 private_stroke_ca_t
*this, stroke_msg_t
*msg
, FILE *out
)
456 ca_section_t
*section
;
457 enumerator_t
*enumerator
;
459 this->lock
->read_lock(this->lock
);
460 enumerator
= this->sections
->create_enumerator(this->sections
);
461 while (enumerator
->enumerate(enumerator
, (void**)§ion
))
463 certificate_t
*cert
= section
->cert
;
464 public_key_t
*public = cert
->get_public_key(cert
);
470 fprintf(out
, "List of CA Information Sections:\n");
474 fprintf(out
, " authname: \"%Y\"\n", cert
->get_subject(cert
));
476 /* list authkey and keyid */
479 if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1
, &chunk
))
481 fprintf(out
, " authkey: %#B\n", &chunk
);
483 if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1
, &chunk
))
485 fprintf(out
, " keyid: %#B\n", &chunk
);
487 public->destroy(public);
489 list_uris(section
->crl
, " crluris: ", out
);
490 list_uris(section
->ocsp
, " ocspuris: ", out
);
491 if (section
->certuribase
)
493 fprintf(out
, " certuribase: '%s'\n", section
->certuribase
);
496 enumerator
->destroy(enumerator
);
497 this->lock
->unlock(this->lock
);
500 METHOD(stroke_ca_t
, destroy
, void,
501 private_stroke_ca_t
*this)
503 this->sections
->destroy_function(this->sections
, (void*)ca_section_destroy
);
504 this->lock
->destroy(this->lock
);
511 stroke_ca_t
*stroke_ca_create(stroke_cred_t
*cred
)
513 private_stroke_ca_t
*this;
518 .create_private_enumerator
= (void*)return_null
,
519 .create_cert_enumerator
= _create_cert_enumerator
,
520 .create_shared_enumerator
= (void*)return_null
,
521 .create_cdp_enumerator
= _create_cdp_enumerator
,
522 .cache_cert
= (void*)nop
,
527 .check_for_hash_and_url
= _check_for_hash_and_url
,
530 .sections
= linked_list_create(),
531 .lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
535 return &this->public;