11de24135ae2280544b2c86d11529089ccdf5829
[strongswan.git] / src / charon / plugins / stroke / stroke_ca.c
1 /*
2 * Copyright (C) 2008 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
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>.
10 *
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
14 * for more details.
15 *
16 * $Id$
17 */
18
19 #include "stroke_ca.h"
20 #include "stroke_cred.h"
21
22 #include <utils/mutex.h>
23 #include <utils/linked_list.h>
24 #include <crypto/hashers/hasher.h>
25
26 #include <daemon.h>
27
28 typedef struct private_stroke_ca_t private_stroke_ca_t;
29
30 /**
31 * private data of stroke_ca
32 */
33 struct private_stroke_ca_t {
34
35 /**
36 * public functions
37 */
38 stroke_ca_t public;
39
40 /**
41 * mutex to lock access to list
42 */
43 mutex_t *mutex;
44
45 /**
46 * list of starters CA sections and its certificates (ca_section_t)
47 */
48 linked_list_t *sections;
49
50 /**
51 * stroke credentials, stores our CA certificates
52 */
53 stroke_cred_t *cred;
54 };
55
56 typedef struct ca_section_t ca_section_t;
57
58 /**
59 * loaded ipsec.conf CA sections
60 */
61 struct ca_section_t {
62
63 /**
64 * name of the CA section
65 */
66 char *name;
67
68 /**
69 * reference to cert in trusted_credential_t
70 */
71 certificate_t *cert;
72
73 /**
74 * CRL URIs
75 */
76 linked_list_t *crl;
77
78 /**
79 * OCSP URIs
80 */
81 linked_list_t *ocsp;
82
83 /**
84 * Hashes of certificates issued by this CA
85 */
86 linked_list_t *hashes;
87
88 /**
89 * Base URI used for certificates from this CA
90 */
91 char *certuribase;
92 };
93
94 /**
95 * create a new CA section
96 */
97 static ca_section_t *ca_section_create(char *name, certificate_t *cert)
98 {
99 ca_section_t *ca = malloc_thing(ca_section_t);
100
101 ca->name = strdup(name);
102 ca->crl = linked_list_create();
103 ca->ocsp = linked_list_create();
104 ca->cert = cert;
105 ca->hashes = linked_list_create();
106 ca->certuribase = NULL;
107 return ca;
108 }
109
110 /**
111 * destroy a ca section entry
112 */
113 static void ca_section_destroy(ca_section_t *this)
114 {
115 this->crl->destroy_function(this->crl, free);
116 this->ocsp->destroy_function(this->ocsp, free);
117 this->hashes->destroy_offset(this->hashes, offsetof(identification_t, destroy));
118 free(this->certuribase);
119 free(this->name);
120 free(this);
121 }
122
123 /**
124 * data to pass to create_inner_cdp
125 */
126 typedef struct {
127 private_stroke_ca_t *this;
128 certificate_type_t type;
129 identification_t *id;
130 } cdp_data_t;
131
132 /**
133 * destroy cdp enumerator data and unlock list
134 */
135 static void cdp_data_destroy(cdp_data_t *data)
136 {
137 data->this->mutex->unlock(data->this->mutex);
138 free(data);
139 }
140
141 /**
142 * inner enumerator constructor for CDP URIs
143 */
144 static enumerator_t *create_inner_cdp(ca_section_t *section, cdp_data_t *data)
145 {
146 public_key_t *public;
147 identification_t *keyid;
148 enumerator_t *enumerator = NULL;
149 linked_list_t *list;
150
151 if (data->type == CERT_X509_OCSP_RESPONSE)
152 {
153 list = section->ocsp;
154 }
155 else
156 {
157 list = section->crl;
158 }
159
160 public = section->cert->get_public_key(section->cert);
161 if (public)
162 {
163 if (!data->id)
164 {
165 enumerator = list->create_enumerator(list);
166 }
167 else
168 {
169 keyid = public->get_id(public, data->id->get_type(data->id));
170 if (keyid && keyid->matches(keyid, data->id))
171 {
172 enumerator = list->create_enumerator(list);
173 }
174 }
175 public->destroy(public);
176 }
177 return enumerator;
178 }
179
180 /**
181 * inner enumerator constructor for "Hash and URL"
182 */
183 static enumerator_t *create_inner_cdp_hashandurl(ca_section_t *section, cdp_data_t *data)
184 {
185 enumerator_t *enumerator = NULL, *hash_enum;
186 identification_t *current;
187
188 if (!data->id || !section->certuribase)
189 {
190 return NULL;
191 }
192
193 hash_enum = section->hashes->create_enumerator(section->hashes);
194 while (hash_enum->enumerate(hash_enum, &current))
195 {
196 if (current->matches(current, data->id))
197 {
198 char *url, *hash;
199
200 url = malloc(strlen(section->certuribase) + 40 + 1);
201 strcpy(url, section->certuribase);
202 hash = chunk_to_hex(current->get_encoding(current), NULL, FALSE).ptr;
203 strncat(url, hash, 40);
204 free(hash);
205
206 enumerator = enumerator_create_single(url, free);
207 break;
208 }
209 }
210 hash_enum->destroy(hash_enum);
211 return enumerator;
212 }
213
214 /**
215 * Implementation of credential_set_t.create_cdp_enumerator.
216 */
217 static enumerator_t *create_cdp_enumerator(private_stroke_ca_t *this,
218 certificate_type_t type, identification_t *id)
219 {
220 cdp_data_t *data;
221
222 switch (type)
223 { /* we serve CRLs, OCSP responders and URLs for "Hash and URL" */
224 case CERT_X509:
225 case CERT_X509_CRL:
226 case CERT_X509_OCSP_RESPONSE:
227 case CERT_ANY:
228 break;
229 default:
230 return NULL;
231 }
232 data = malloc_thing(cdp_data_t);
233 data->this = this;
234 data->type = type;
235 data->id = id;
236
237 this->mutex->lock(this->mutex);
238 return enumerator_create_nested(this->sections->create_enumerator(this->sections),
239 (type == CERT_X509) ? (void*)create_inner_cdp_hashandurl : (void*)create_inner_cdp,
240 data, (void*)cdp_data_destroy);
241 }
242 /**
243 * Implementation of stroke_ca_t.add.
244 */
245 static void add(private_stroke_ca_t *this, stroke_msg_t *msg)
246 {
247 certificate_t *cert;
248 ca_section_t *ca;
249
250 if (msg->add_ca.cacert == NULL)
251 {
252 DBG1(DBG_CFG, "missing cacert parameter");
253 return;
254 }
255 cert = this->cred->load_ca(this->cred, msg->add_ca.cacert);
256 if (cert)
257 {
258 ca = ca_section_create(msg->add_ca.name, cert);
259 if (msg->add_ca.crluri)
260 {
261 ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri));
262 }
263 if (msg->add_ca.crluri2)
264 {
265 ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri2));
266 }
267 if (msg->add_ca.ocspuri)
268 {
269 ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri));
270 }
271 if (msg->add_ca.ocspuri2)
272 {
273 ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri2));
274 }
275 if (msg->add_ca.certuribase)
276 {
277 ca->certuribase = strdup(msg->add_ca.certuribase);
278 }
279 this->mutex->lock(this->mutex);
280 this->sections->insert_last(this->sections, ca);
281 this->mutex->unlock(this->mutex);
282 DBG1(DBG_CFG, "added ca '%s'", msg->add_ca.name);
283 }
284 }
285
286 /**
287 * Implementation of stroke_ca_t.del.
288 */
289 static void del(private_stroke_ca_t *this, stroke_msg_t *msg)
290 {
291 enumerator_t *enumerator;
292 ca_section_t *ca = NULL;
293
294 this->mutex->lock(this->mutex);
295 enumerator = this->sections->create_enumerator(this->sections);
296 while (enumerator->enumerate(enumerator, &ca))
297 {
298 if (streq(ca->name, msg->del_ca.name))
299 {
300 this->sections->remove_at(this->sections, enumerator);
301 break;
302 }
303 ca = NULL;
304 }
305 enumerator->destroy(enumerator);
306 this->mutex->unlock(this->mutex);
307 if (ca == NULL)
308 {
309 DBG1(DBG_CFG, "no ca named '%s' found\n", msg->del_ca.name);
310 return;
311 }
312 ca_section_destroy(ca);
313 /* TODO: flush cached certs */
314 }
315
316 /**
317 * list crl or ocsp URIs
318 */
319 static void list_uris(linked_list_t *list, char *label, FILE *out)
320 {
321 bool first = TRUE;
322 char *uri;
323 enumerator_t *enumerator;
324
325 enumerator = list->create_enumerator(list);
326 while (enumerator->enumerate(enumerator, (void**)&uri))
327 {
328 if (first)
329 {
330 fprintf(out, label);
331 first = FALSE;
332 }
333 else
334 {
335 fprintf(out, " ");
336 }
337 fprintf(out, "'%s'\n", uri);
338 }
339 enumerator->destroy(enumerator);
340 }
341
342 /**
343 * Implementation of stroke_ca_t.check_for_hash_and_url.
344 */
345 static void check_for_hash_and_url(private_stroke_ca_t *this, certificate_t* cert)
346 {
347 ca_section_t *section;
348 enumerator_t *enumerator;
349
350 hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
351 if (hasher == NULL)
352 {
353 DBG1(DBG_IKE, "unable to use hash-and-url: sha1 not supported");
354 return;
355 }
356
357 this->mutex->lock(this->mutex);
358 enumerator = this->sections->create_enumerator(this->sections);
359 while (enumerator->enumerate(enumerator, (void**)&section))
360 {
361 if (section->certuribase && cert->issued_by(cert, section->cert))
362 {
363 chunk_t hash, encoded = cert->get_encoding(cert);
364 hasher->allocate_hash(hasher, encoded, &hash);
365 section->hashes->insert_last(section->hashes,
366 identification_create_from_encoding(ID_CERT_DER_SHA1, hash));
367 chunk_free(&hash);
368 chunk_free(&encoded);
369 break;
370 }
371 }
372 enumerator->destroy(enumerator);
373 this->mutex->unlock(this->mutex);
374
375 hasher->destroy(hasher);
376 }
377
378 /**
379 * Implementation of stroke_ca_t.list.
380 */
381 static void list(private_stroke_ca_t *this, stroke_msg_t *msg, FILE *out)
382 {
383 bool first = TRUE;
384 ca_section_t *section;
385 enumerator_t *enumerator;
386
387 this->mutex->lock(this->mutex);
388 enumerator = this->sections->create_enumerator(this->sections);
389 while (enumerator->enumerate(enumerator, (void**)&section))
390 {
391 certificate_t *cert = section->cert;
392 public_key_t *public = cert->get_public_key(cert);
393
394 if (first)
395 {
396 fprintf(out, "\n");
397 fprintf(out, "List of CA Information Sections:\n");
398 first = FALSE;
399 }
400 fprintf(out, "\n");
401 fprintf(out, " authname: \"%D\"\n", cert->get_subject(cert));
402
403 /* list authkey and keyid */
404 if (public)
405 {
406 fprintf(out, " authkey: %D\n",
407 public->get_id(public, ID_PUBKEY_SHA1));
408 fprintf(out, " keyid: %D\n",
409 public->get_id(public, ID_PUBKEY_INFO_SHA1));
410 public->destroy(public);
411 }
412 list_uris(section->crl, " crluris: ", out);
413 list_uris(section->ocsp, " ocspuris: ", out);
414 fprintf(out, " certuribase: '%s'\n", section->certuribase);
415 }
416 enumerator->destroy(enumerator);
417 this->mutex->unlock(this->mutex);
418 }
419
420 /**
421 * Implementation of stroke_ca_t.destroy
422 */
423 static void destroy(private_stroke_ca_t *this)
424 {
425 this->sections->destroy_function(this->sections, (void*)ca_section_destroy);
426 this->mutex->destroy(this->mutex);
427 free(this);
428 }
429
430 /*
431 * see header file
432 */
433 stroke_ca_t *stroke_ca_create(stroke_cred_t *cred)
434 {
435 private_stroke_ca_t *this = malloc_thing(private_stroke_ca_t);
436
437 this->public.set.create_private_enumerator = (void*)return_null;
438 this->public.set.create_cert_enumerator = (void*)return_null;
439 this->public.set.create_shared_enumerator = (void*)return_null;
440 this->public.set.create_cdp_enumerator = (void*)create_cdp_enumerator;
441 this->public.set.cache_cert = (void*)nop;
442 this->public.add = (void(*)(stroke_ca_t*, stroke_msg_t *msg))add;
443 this->public.del = (void(*)(stroke_ca_t*, stroke_msg_t *msg))del;
444 this->public.list = (void(*)(stroke_ca_t*, stroke_msg_t *msg, FILE *out))list;
445 this->public.check_for_hash_and_url = (void(*)(stroke_ca_t*, certificate_t*))check_for_hash_and_url;
446 this->public.destroy = (void(*)(stroke_ca_t*))destroy;
447
448 this->sections = linked_list_create();
449 this->mutex = mutex_create(MUTEX_RECURSIVE);
450 this->cred = cred;
451
452 return &this->public;
453 }
454