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 to pass to create_inner_cdp
126 private_stroke_ca_t
*this;
127 certificate_type_t type
;
128 identification_t
*id
;
132 * destroy cdp enumerator data and unlock list
134 static void cdp_data_destroy(cdp_data_t
*data
)
136 data
->this->lock
->unlock(data
->this->lock
);
141 * inner enumerator constructor for CDP URIs
143 static enumerator_t
*create_inner_cdp(ca_section_t
*section
, cdp_data_t
*data
)
145 public_key_t
*public;
146 enumerator_t
*enumerator
= NULL
;
149 if (data
->type
== CERT_X509_OCSP_RESPONSE
)
151 list
= section
->ocsp
;
158 public = section
->cert
->get_public_key(section
->cert
);
163 enumerator
= list
->create_enumerator(list
);
167 if (public->has_fingerprint(public, data
->id
->get_encoding(data
->id
)))
169 enumerator
= list
->create_enumerator(list
);
172 public->destroy(public);
178 * inner enumerator constructor for "Hash and URL"
180 static enumerator_t
*create_inner_cdp_hashandurl(ca_section_t
*section
, cdp_data_t
*data
)
182 enumerator_t
*enumerator
= NULL
, *hash_enum
;
183 identification_t
*current
;
185 if (!data
->id
|| !section
->certuribase
)
190 hash_enum
= section
->hashes
->create_enumerator(section
->hashes
);
191 while (hash_enum
->enumerate(hash_enum
, ¤t
))
193 if (current
->matches(current
, data
->id
))
197 url
= malloc(strlen(section
->certuribase
) + 40 + 1);
198 strcpy(url
, section
->certuribase
);
199 hash
= chunk_to_hex(current
->get_encoding(current
), NULL
, FALSE
).ptr
;
200 strncat(url
, hash
, 40);
203 enumerator
= enumerator_create_single(url
, free
);
207 hash_enum
->destroy(hash_enum
);
211 METHOD(credential_set_t
, create_cdp_enumerator
, enumerator_t
*,
212 private_stroke_ca_t
*this, certificate_type_t type
, identification_t
*id
)
217 { /* we serve CRLs, OCSP responders and URLs for "Hash and URL" */
220 case CERT_X509_OCSP_RESPONSE
:
226 data
= malloc_thing(cdp_data_t
);
231 this->lock
->read_lock(this->lock
);
232 return enumerator_create_nested(this->sections
->create_enumerator(this->sections
),
233 (type
== CERT_X509
) ?
(void*)create_inner_cdp_hashandurl
: (void*)create_inner_cdp
,
234 data
, (void*)cdp_data_destroy
);
237 METHOD(stroke_ca_t
, add
, void,
238 private_stroke_ca_t
*this, stroke_msg_t
*msg
)
243 if (msg
->add_ca
.cacert
== NULL
)
245 DBG1(DBG_CFG
, "missing cacert parameter");
248 cert
= this->cred
->load_ca(this->cred
, msg
->add_ca
.cacert
);
251 ca
= ca_section_create(msg
->add_ca
.name
, cert
);
252 if (msg
->add_ca
.crluri
)
254 ca
->crl
->insert_last(ca
->crl
, strdup(msg
->add_ca
.crluri
));
256 if (msg
->add_ca
.crluri2
)
258 ca
->crl
->insert_last(ca
->crl
, strdup(msg
->add_ca
.crluri2
));
260 if (msg
->add_ca
.ocspuri
)
262 ca
->ocsp
->insert_last(ca
->ocsp
, strdup(msg
->add_ca
.ocspuri
));
264 if (msg
->add_ca
.ocspuri2
)
266 ca
->ocsp
->insert_last(ca
->ocsp
, strdup(msg
->add_ca
.ocspuri2
));
268 if (msg
->add_ca
.certuribase
)
270 ca
->certuribase
= strdup(msg
->add_ca
.certuribase
);
272 this->lock
->write_lock(this->lock
);
273 this->sections
->insert_last(this->sections
, ca
);
274 this->lock
->unlock(this->lock
);
275 DBG1(DBG_CFG
, "added ca '%s'", msg
->add_ca
.name
);
279 METHOD(stroke_ca_t
, del
, void,
280 private_stroke_ca_t
*this, stroke_msg_t
*msg
)
282 enumerator_t
*enumerator
;
283 ca_section_t
*ca
= NULL
;
285 this->lock
->write_lock(this->lock
);
286 enumerator
= this->sections
->create_enumerator(this->sections
);
287 while (enumerator
->enumerate(enumerator
, &ca
))
289 if (streq(ca
->name
, msg
->del_ca
.name
))
291 this->sections
->remove_at(this->sections
, enumerator
);
296 enumerator
->destroy(enumerator
);
297 this->lock
->unlock(this->lock
);
300 DBG1(DBG_CFG
, "no ca named '%s' found\n", msg
->del_ca
.name
);
303 ca_section_destroy(ca
);
305 lib
->credmgr
->flush_cache(lib
->credmgr
, CERT_ANY
);
309 * list crl or ocsp URIs
311 static void list_uris(linked_list_t
*list
, char *label
, FILE *out
)
315 enumerator_t
*enumerator
;
317 enumerator
= list
->create_enumerator(list
);
318 while (enumerator
->enumerate(enumerator
, (void**)&uri
))
322 fprintf(out
, "%s", label
);
329 fprintf(out
, "'%s'\n", uri
);
331 enumerator
->destroy(enumerator
);
334 METHOD(stroke_ca_t
, check_for_hash_and_url
, void,
335 private_stroke_ca_t
*this, certificate_t
* cert
)
337 ca_section_t
*section
;
338 enumerator_t
*enumerator
;
340 hasher_t
*hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
);
343 DBG1(DBG_IKE
, "unable to use hash-and-url: sha1 not supported");
347 this->lock
->write_lock(this->lock
);
348 enumerator
= this->sections
->create_enumerator(this->sections
);
349 while (enumerator
->enumerate(enumerator
, (void**)§ion
))
351 if (section
->certuribase
&& cert
->issued_by(cert
, section
->cert
, NULL
))
353 chunk_t hash
, encoded
;
355 if (cert
->get_encoding(cert
, CERT_ASN1_DER
, &encoded
))
357 if (hasher
->allocate_hash(hasher
, encoded
, &hash
))
359 section
->hashes
->insert_last(section
->hashes
,
360 identification_create_from_encoding(ID_KEY_ID
, hash
));
363 chunk_free(&encoded
);
368 enumerator
->destroy(enumerator
);
369 this->lock
->unlock(this->lock
);
371 hasher
->destroy(hasher
);
374 METHOD(stroke_ca_t
, list
, void,
375 private_stroke_ca_t
*this, stroke_msg_t
*msg
, FILE *out
)
378 ca_section_t
*section
;
379 enumerator_t
*enumerator
;
381 this->lock
->read_lock(this->lock
);
382 enumerator
= this->sections
->create_enumerator(this->sections
);
383 while (enumerator
->enumerate(enumerator
, (void**)§ion
))
385 certificate_t
*cert
= section
->cert
;
386 public_key_t
*public = cert
->get_public_key(cert
);
392 fprintf(out
, "List of CA Information Sections:\n");
396 fprintf(out
, " authname: \"%Y\"\n", cert
->get_subject(cert
));
398 /* list authkey and keyid */
401 if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1
, &chunk
))
403 fprintf(out
, " authkey: %#B\n", &chunk
);
405 if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1
, &chunk
))
407 fprintf(out
, " keyid: %#B\n", &chunk
);
409 public->destroy(public);
411 list_uris(section
->crl
, " crluris: ", out
);
412 list_uris(section
->ocsp
, " ocspuris: ", out
);
413 if (section
->certuribase
)
415 fprintf(out
, " certuribase: '%s'\n", section
->certuribase
);
418 enumerator
->destroy(enumerator
);
419 this->lock
->unlock(this->lock
);
422 METHOD(stroke_ca_t
, destroy
, void,
423 private_stroke_ca_t
*this)
425 this->sections
->destroy_function(this->sections
, (void*)ca_section_destroy
);
426 this->lock
->destroy(this->lock
);
433 stroke_ca_t
*stroke_ca_create(stroke_cred_t
*cred
)
435 private_stroke_ca_t
*this;
440 .create_private_enumerator
= (void*)return_null
,
441 .create_cert_enumerator
= (void*)return_null
,
442 .create_shared_enumerator
= (void*)return_null
,
443 .create_cdp_enumerator
= _create_cdp_enumerator
,
444 .cache_cert
= (void*)nop
,
449 .check_for_hash_and_url
= _check_for_hash_and_url
,
452 .sections
= linked_list_create(),
453 .lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
457 return &this->public;