Annotation of embedaddon/strongswan/src/libcharon/plugins/stroke/stroke_ca.c, revision 1.1.1.2
1.1 misho 1: /*
2: * Copyright (C) 2008-2019 Tobias Brunner
3: * Copyright (C) 2008 Martin Willi
4: * HSR 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:
17: #include "stroke_ca.h"
18: #include "stroke_cred.h"
19:
20: #include <threading/rwlock.h>
21: #include <collections/linked_list.h>
22: #include <crypto/hashers/hasher.h>
23:
24: #include <daemon.h>
25:
26: typedef struct private_stroke_ca_t private_stroke_ca_t;
27: typedef struct ca_section_t ca_section_t;
28: typedef struct ca_cert_t ca_cert_t;
29:
30: /**
31: * Provided by stroke_cred.c
32: */
33: certificate_t *stroke_load_ca_cert(char *filename);
34:
35: /**
36: * private data of stroke_ca
37: */
38: struct private_stroke_ca_t {
39:
40: /**
41: * public functions
42: */
43: stroke_ca_t public;
44:
45: /**
46: * read-write lock to lists
47: */
48: rwlock_t *lock;
49:
50: /**
51: * list of CA sections and their certificates (ca_section_t)
52: */
53: linked_list_t *sections;
54:
55: /**
56: * list of all loaded CA certificates (ca_cert_t)
57: */
58: linked_list_t *certs;
59: };
60:
61:
62: /**
63: * loaded ipsec.conf CA sections
64: */
65: struct ca_section_t {
66:
67: /**
68: * name of the CA section
69: */
70: char *name;
71:
72: /**
73: * path/name of the certificate
74: */
75: char *path;
76:
77: /**
78: * reference to cert
79: */
80: certificate_t *cert;
81:
82: /**
83: * CRL URIs
84: */
85: linked_list_t *crl;
86:
87: /**
88: * OCSP URIs
89: */
90: linked_list_t *ocsp;
91:
92: /**
93: * Base URI used for certificates from this CA
94: */
95: char *certuribase;
96: };
97:
98: /**
99: * loaded CA certificate
100: */
101: struct ca_cert_t {
102:
103: /**
104: * reference to cert
105: */
106: certificate_t *cert;
107:
108: /**
109: * The number of CA sections referring to this certificate
110: */
111: u_int count;
112:
113: /**
114: * TRUE if this certificate was automatically loaded
115: */
116: bool automatic;
117: };
118:
119: /**
120: * create a new CA section
121: */
122: static ca_section_t *ca_section_create(char *name, char *path)
123: {
124: ca_section_t *ca = malloc_thing(ca_section_t);
125:
126: ca->name = strdup(name);
127: ca->path = strdup(path);
128: ca->crl = linked_list_create();
129: ca->ocsp = linked_list_create();
130: ca->certuribase = NULL;
131: return ca;
132: }
133:
134: /**
135: * destroy a ca section entry
136: */
137: static void ca_section_destroy(ca_section_t *this)
138: {
139: this->crl->destroy_function(this->crl, free);
140: this->ocsp->destroy_function(this->ocsp, free);
141: this->cert->destroy(this->cert);
142: free(this->certuribase);
143: free(this->path);
144: free(this->name);
145: free(this);
146: }
147:
148: /**
149: * Destroy a ca cert entry
150: */
151: static void ca_cert_destroy(ca_cert_t *this)
152: {
153: this->cert->destroy(this->cert);
154: free(this);
155: }
156:
157: /**
158: * Data for the certificate enumerator
159: */
160: typedef struct {
161: private_stroke_ca_t *this;
162: certificate_type_t cert;
163: key_type_t key;
164: identification_t *id;
165: } cert_data_t;
166:
167: CALLBACK(cert_data_destroy, void,
168: cert_data_t *data)
169: {
170: data->this->lock->unlock(data->this->lock);
171: free(data);
172: }
173:
174: CALLBACK(certs_filter, bool,
175: cert_data_t *data, enumerator_t *orig, va_list args)
176: {
177: ca_cert_t *cacert;
178: certificate_t **out;
179:
180: VA_ARGS_VGET(args, out);
181:
182: while (orig->enumerate(orig, &cacert))
183: {
1.1.1.2 ! misho 184: if (certificate_matches(cacert->cert, data->cert, data->key, data->id))
1.1 misho 185: {
1.1.1.2 ! misho 186: *out = cacert->cert;
1.1 misho 187: return TRUE;
188: }
189: }
190: return FALSE;
191: }
192:
193: METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
194: private_stroke_ca_t *this, certificate_type_t cert, key_type_t key,
195: identification_t *id, bool trusted)
196: {
197: enumerator_t *enumerator;
198: cert_data_t *data;
199:
200: INIT(data,
201: .this = this,
202: .cert = cert,
203: .key = key,
204: .id = id,
205: );
206:
207: this->lock->read_lock(this->lock);
208: enumerator = this->certs->create_enumerator(this->certs);
209: return enumerator_create_filter(enumerator, certs_filter, data,
210: cert_data_destroy);
211: }
212:
213: /**
214: * data to pass to create_inner_cdp
215: */
216: typedef struct {
217: private_stroke_ca_t *this;
218: certificate_type_t type;
219: identification_t *id;
220: } cdp_data_t;
221:
222: /**
223: * destroy cdp enumerator data and unlock list
224: */
225: static void cdp_data_destroy(cdp_data_t *data)
226: {
227: data->this->lock->unlock(data->this->lock);
228: free(data);
229: }
230:
231: /**
232: * inner enumerator constructor for CDP URIs
233: */
234: static enumerator_t *create_inner_cdp(ca_section_t *section, cdp_data_t *data)
235: {
236: public_key_t *public;
237: enumerator_t *enumerator = NULL;
238: linked_list_t *list;
239:
240: if (data->type == CERT_X509_OCSP_RESPONSE)
241: {
242: list = section->ocsp;
243: }
244: else
245: {
246: list = section->crl;
247: }
248:
249: public = section->cert->get_public_key(section->cert);
250: if (public)
251: {
252: if (!data->id)
253: {
254: enumerator = list->create_enumerator(list);
255: }
256: else
257: {
258: if (public->has_fingerprint(public, data->id->get_encoding(data->id)))
259: {
260: enumerator = list->create_enumerator(list);
261: }
262: }
263: public->destroy(public);
264: }
265: return enumerator;
266: }
267:
268: /**
269: * inner enumerator constructor for "Hash and URL"
270: */
271: static enumerator_t *create_inner_cdp_hashandurl(ca_section_t *section, cdp_data_t *data)
272: {
273: enumerator_t *enumerator = NULL;
274:
275: if (!data->id || !section->certuribase)
276: {
277: return NULL;
278: }
279:
280: if (section->cert->has_subject(section->cert, data->id) != ID_MATCH_NONE)
281: {
282: enumerator = enumerator_create_single(strdup(section->certuribase),
283: free);
284: }
285: return enumerator;
286: }
287:
288: METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*,
289: private_stroke_ca_t *this, certificate_type_t type, identification_t *id)
290: {
291: cdp_data_t *data;
292:
293: switch (type)
294: { /* we serve CRLs, OCSP responders and URLs for "Hash and URL" */
295: case CERT_X509:
296: case CERT_X509_CRL:
297: case CERT_X509_OCSP_RESPONSE:
298: case CERT_ANY:
299: break;
300: default:
301: return NULL;
302: }
303: data = malloc_thing(cdp_data_t);
304: data->this = this;
305: data->type = type;
306: data->id = id;
307:
308: this->lock->read_lock(this->lock);
309: return enumerator_create_nested(this->sections->create_enumerator(this->sections),
310: (type == CERT_X509) ? (void*)create_inner_cdp_hashandurl : (void*)create_inner_cdp,
311: data, (void*)cdp_data_destroy);
312: }
313:
314: CALLBACK(match_cert, bool,
315: ca_cert_t *item, va_list args)
316: {
317: certificate_t *cert;
318:
319: VA_ARGS_VGET(args, cert);
320: return cert->equals(cert, item->cert);
321: }
322:
323: /**
324: * Match automatically added certificates and remove/destroy them if they are
325: * not referenced by CA sections.
326: */
327: static bool remove_auto_certs(ca_cert_t *item, void *not_used)
328: {
329: if (item->automatic)
330: {
331: item->automatic = FALSE;
332: if (!item->count)
333: {
334: ca_cert_destroy(item);
335: return TRUE;
336: }
337: }
338: return FALSE;
339: }
340:
341: /**
342: * Find the given certificate that was referenced by a section and remove it
343: * unless it was also loaded automatically or is used by other CA sections.
344: */
345: static bool remove_cert(ca_cert_t *item, certificate_t *cert)
346: {
347: if (item->count && cert->equals(cert, item->cert))
348: {
349: if (--item->count == 0 && !item->automatic)
350: {
351: ca_cert_destroy(item);
352: return TRUE;
353: }
354: }
355: return FALSE;
356: }
357:
358: /**
359: * Adds a certificate to the certificate store
360: */
361: static certificate_t *add_cert_internal(private_stroke_ca_t *this,
362: certificate_t *cert, bool automatic)
363: {
364: ca_cert_t *found;
365:
366: if (this->certs->find_first(this->certs, match_cert, (void**)&found, cert))
367: {
368: cert->destroy(cert);
369: cert = found->cert->get_ref(found->cert);
370: }
371: else
372: {
373: INIT(found,
374: .cert = cert->get_ref(cert)
375: );
376: this->certs->insert_first(this->certs, found);
377: }
378: if (automatic)
379: {
380: found->automatic = TRUE;
381: }
382: else
383: {
384: found->count++;
385: }
386: return cert;
387: }
388:
389: METHOD(stroke_ca_t, add, void,
390: private_stroke_ca_t *this, stroke_msg_t *msg)
391: {
392: certificate_t *cert;
393: ca_section_t *ca;
394:
395: if (msg->add_ca.cacert == NULL)
396: {
397: DBG1(DBG_CFG, "missing cacert parameter");
398: return;
399: }
400: cert = stroke_load_ca_cert(msg->add_ca.cacert);
401: if (cert)
402: {
403: ca = ca_section_create(msg->add_ca.name, msg->add_ca.cacert);
404: if (msg->add_ca.crluri)
405: {
406: ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri));
407: }
408: if (msg->add_ca.crluri2)
409: {
410: ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri2));
411: }
412: if (msg->add_ca.ocspuri)
413: {
414: ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri));
415: }
416: if (msg->add_ca.ocspuri2)
417: {
418: ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri2));
419: }
420: if (msg->add_ca.certuribase)
421: {
422: ca->certuribase = strdup(msg->add_ca.certuribase);
423: }
424: this->lock->write_lock(this->lock);
425: ca->cert = add_cert_internal(this, cert, FALSE);
426: this->sections->insert_last(this->sections, ca);
427: this->lock->unlock(this->lock);
428: DBG1(DBG_CFG, "added ca '%s'", msg->add_ca.name);
429: }
430: }
431:
432: METHOD(stroke_ca_t, del, void,
433: private_stroke_ca_t *this, stroke_msg_t *msg)
434: {
435: enumerator_t *enumerator;
436: ca_section_t *ca = NULL;
437:
438: this->lock->write_lock(this->lock);
439: enumerator = this->sections->create_enumerator(this->sections);
440: while (enumerator->enumerate(enumerator, &ca))
441: {
442: if (streq(ca->name, msg->del_ca.name))
443: {
444: this->sections->remove_at(this->sections, enumerator);
445: break;
446: }
447: ca = NULL;
448: }
449: enumerator->destroy(enumerator);
450: if (ca)
451: {
452: this->certs->remove(this->certs, ca->cert, (void*)remove_cert);
453: }
454: this->lock->unlock(this->lock);
455: if (!ca)
456: {
457: DBG1(DBG_CFG, "no ca named '%s' found\n", msg->del_ca.name);
458: return;
459: }
460: ca_section_destroy(ca);
461:
462: lib->credmgr->flush_cache(lib->credmgr, CERT_ANY);
463: }
464:
465: METHOD(stroke_ca_t, get_cert_ref, certificate_t*,
466: private_stroke_ca_t *this, certificate_t *cert)
467: {
468: ca_cert_t *found;
469:
470: this->lock->read_lock(this->lock);
471: if (this->certs->find_first(this->certs, match_cert, (void**)&found, cert))
472: {
473: cert->destroy(cert);
474: cert = found->cert->get_ref(found->cert);
475: }
476: this->lock->unlock(this->lock);
477: return cert;
478: }
479:
480: METHOD(stroke_ca_t, reload_certs, void,
481: private_stroke_ca_t *this)
482: {
483: enumerator_t *enumerator;
484: certificate_t *cert;
485: ca_section_t *ca;
486: certificate_type_t type = CERT_X509;
487:
488: /* holding the write lock while loading/parsing certificates is not optimal,
489: * however, there usually are not that many ca sections configured */
490: this->lock->write_lock(this->lock);
491: if (this->sections->get_count(this->sections))
492: {
493: DBG1(DBG_CFG, "rereading ca certificates in ca sections");
494: }
495: enumerator = this->sections->create_enumerator(this->sections);
496: while (enumerator->enumerate(enumerator, &ca))
497: {
498: cert = stroke_load_ca_cert(ca->path);
499: if (cert)
500: {
501: if (cert->equals(cert, ca->cert))
502: {
503: cert->destroy(cert);
504: }
505: else
506: {
507: this->certs->remove(this->certs, ca->cert, (void*)remove_cert);
508: ca->cert->destroy(ca->cert);
509: ca->cert = add_cert_internal(this, cert, FALSE);
510: }
511: }
512: else
513: {
514: DBG1(DBG_CFG, "failed to reload certificate '%s', removing ca '%s'",
515: ca->path, ca->name);
516: this->sections->remove_at(this->sections, enumerator);
517: this->certs->remove(this->certs, ca->cert, (void*)remove_cert);
518: ca_section_destroy(ca);
519: type = CERT_ANY;
520: }
521: }
522: enumerator->destroy(enumerator);
523: this->lock->unlock(this->lock);
524: lib->credmgr->flush_cache(lib->credmgr, type);
525: }
526:
527: METHOD(stroke_ca_t, replace_certs, void,
528: private_stroke_ca_t *this, mem_cred_t *certs)
529: {
530: enumerator_t *enumerator;
531: certificate_t *cert;
532:
533: enumerator = certs->set.create_cert_enumerator(&certs->set, CERT_X509,
534: KEY_ANY, NULL, TRUE);
535: this->lock->write_lock(this->lock);
536: this->certs->remove(this->certs, NULL, (void*)remove_auto_certs);
537: while (enumerator->enumerate(enumerator, &cert))
538: {
539: cert = add_cert_internal(this, cert->get_ref(cert), TRUE);
540: cert->destroy(cert);
541: }
542: this->lock->unlock(this->lock);
543: enumerator->destroy(enumerator);
544: lib->credmgr->flush_cache(lib->credmgr, CERT_X509);
545: }
546: /**
547: * list crl or ocsp URIs
548: */
549: static void list_uris(linked_list_t *list, char *label, FILE *out)
550: {
551: bool first = TRUE;
552: char *uri;
553: enumerator_t *enumerator;
554:
555: enumerator = list->create_enumerator(list);
556: while (enumerator->enumerate(enumerator, (void**)&uri))
557: {
558: if (first)
559: {
560: fprintf(out, "%s", label);
561: first = FALSE;
562: }
563: else
564: {
565: fprintf(out, " ");
566: }
567: fprintf(out, "'%s'\n", uri);
568: }
569: enumerator->destroy(enumerator);
570: }
571:
572: METHOD(stroke_ca_t, list, void,
573: private_stroke_ca_t *this, stroke_msg_t *msg, FILE *out)
574: {
575: bool first = TRUE;
576: ca_section_t *section;
577: enumerator_t *enumerator;
578:
579: this->lock->read_lock(this->lock);
580: enumerator = this->sections->create_enumerator(this->sections);
581: while (enumerator->enumerate(enumerator, (void**)§ion))
582: {
583: certificate_t *cert = section->cert;
584: public_key_t *public = cert->get_public_key(cert);
585: chunk_t chunk;
586:
587: if (first)
588: {
589: fprintf(out, "\n");
590: fprintf(out, "List of CA Information Sections:\n");
591: first = FALSE;
592: }
593: fprintf(out, "\n");
594: fprintf(out, " authname: \"%Y\"\n", cert->get_subject(cert));
595:
596: /* list authkey and keyid */
597: if (public)
598: {
599: if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk))
600: {
601: fprintf(out, " authkey: %#B\n", &chunk);
602: }
603: if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &chunk))
604: {
605: fprintf(out, " keyid: %#B\n", &chunk);
606: }
607: public->destroy(public);
608: }
609: list_uris(section->crl, " crluris: ", out);
610: list_uris(section->ocsp, " ocspuris: ", out);
611: if (section->certuribase)
612: {
613: fprintf(out, " certuribase: '%s'\n", section->certuribase);
614: }
615: }
616: enumerator->destroy(enumerator);
617: this->lock->unlock(this->lock);
618: }
619:
620: METHOD(stroke_ca_t, destroy, void,
621: private_stroke_ca_t *this)
622: {
623: this->sections->destroy_function(this->sections, (void*)ca_section_destroy);
624: this->certs->destroy_function(this->certs, (void*)ca_cert_destroy);
625: this->lock->destroy(this->lock);
626: free(this);
627: }
628:
629: /*
630: * see header file
631: */
632: stroke_ca_t *stroke_ca_create()
633: {
634: private_stroke_ca_t *this;
635:
636: INIT(this,
637: .public = {
638: .set = {
639: .create_private_enumerator = (void*)return_null,
640: .create_cert_enumerator = _create_cert_enumerator,
641: .create_shared_enumerator = (void*)return_null,
642: .create_cdp_enumerator = _create_cdp_enumerator,
643: .cache_cert = (void*)nop,
644: },
645: .add = _add,
646: .del = _del,
647: .list = _list,
648: .get_cert_ref = _get_cert_ref,
649: .reload_certs = _reload_certs,
650: .replace_certs = _replace_certs,
651: .destroy = _destroy,
652: },
653: .sections = linked_list_create(),
654: .certs = linked_list_create(),
655: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
656: );
657:
658: return &this->public;
659: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>