Annotation of embedaddon/strongswan/src/libcharon/plugins/stroke/stroke_ca.c, revision 1.1.1.1
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: public_key_t *public;
179: certificate_t **out;
180:
181: VA_ARGS_VGET(args, out);
182:
183: while (orig->enumerate(orig, &cacert))
184: {
185: certificate_t *cert = cacert->cert;
186:
187: if (data->cert != CERT_ANY && data->cert != cert->get_type(cert))
188: {
189: continue;
190: }
191: public = cert->get_public_key(cert);
192: if (public)
193: {
194: if (data->key == KEY_ANY || data->key == public->get_type(public))
195: {
196: if (data->id && public->has_fingerprint(public,
197: data->id->get_encoding(data->id)))
198: {
199: public->destroy(public);
200: *out = cert;
201: return TRUE;
202: }
203: }
204: else
205: {
206: public->destroy(public);
207: continue;
208: }
209: public->destroy(public);
210: }
211: else if (data->key != KEY_ANY)
212: {
213: continue;
214: }
215: if (!data->id || cert->has_subject(cert, data->id))
216: {
217: *out = cert;
218: return TRUE;
219: }
220: }
221: return FALSE;
222: }
223:
224: METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
225: private_stroke_ca_t *this, certificate_type_t cert, key_type_t key,
226: identification_t *id, bool trusted)
227: {
228: enumerator_t *enumerator;
229: cert_data_t *data;
230:
231: INIT(data,
232: .this = this,
233: .cert = cert,
234: .key = key,
235: .id = id,
236: );
237:
238: this->lock->read_lock(this->lock);
239: enumerator = this->certs->create_enumerator(this->certs);
240: return enumerator_create_filter(enumerator, certs_filter, data,
241: cert_data_destroy);
242: }
243:
244: /**
245: * data to pass to create_inner_cdp
246: */
247: typedef struct {
248: private_stroke_ca_t *this;
249: certificate_type_t type;
250: identification_t *id;
251: } cdp_data_t;
252:
253: /**
254: * destroy cdp enumerator data and unlock list
255: */
256: static void cdp_data_destroy(cdp_data_t *data)
257: {
258: data->this->lock->unlock(data->this->lock);
259: free(data);
260: }
261:
262: /**
263: * inner enumerator constructor for CDP URIs
264: */
265: static enumerator_t *create_inner_cdp(ca_section_t *section, cdp_data_t *data)
266: {
267: public_key_t *public;
268: enumerator_t *enumerator = NULL;
269: linked_list_t *list;
270:
271: if (data->type == CERT_X509_OCSP_RESPONSE)
272: {
273: list = section->ocsp;
274: }
275: else
276: {
277: list = section->crl;
278: }
279:
280: public = section->cert->get_public_key(section->cert);
281: if (public)
282: {
283: if (!data->id)
284: {
285: enumerator = list->create_enumerator(list);
286: }
287: else
288: {
289: if (public->has_fingerprint(public, data->id->get_encoding(data->id)))
290: {
291: enumerator = list->create_enumerator(list);
292: }
293: }
294: public->destroy(public);
295: }
296: return enumerator;
297: }
298:
299: /**
300: * inner enumerator constructor for "Hash and URL"
301: */
302: static enumerator_t *create_inner_cdp_hashandurl(ca_section_t *section, cdp_data_t *data)
303: {
304: enumerator_t *enumerator = NULL;
305:
306: if (!data->id || !section->certuribase)
307: {
308: return NULL;
309: }
310:
311: if (section->cert->has_subject(section->cert, data->id) != ID_MATCH_NONE)
312: {
313: enumerator = enumerator_create_single(strdup(section->certuribase),
314: free);
315: }
316: return enumerator;
317: }
318:
319: METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*,
320: private_stroke_ca_t *this, certificate_type_t type, identification_t *id)
321: {
322: cdp_data_t *data;
323:
324: switch (type)
325: { /* we serve CRLs, OCSP responders and URLs for "Hash and URL" */
326: case CERT_X509:
327: case CERT_X509_CRL:
328: case CERT_X509_OCSP_RESPONSE:
329: case CERT_ANY:
330: break;
331: default:
332: return NULL;
333: }
334: data = malloc_thing(cdp_data_t);
335: data->this = this;
336: data->type = type;
337: data->id = id;
338:
339: this->lock->read_lock(this->lock);
340: return enumerator_create_nested(this->sections->create_enumerator(this->sections),
341: (type == CERT_X509) ? (void*)create_inner_cdp_hashandurl : (void*)create_inner_cdp,
342: data, (void*)cdp_data_destroy);
343: }
344:
345: CALLBACK(match_cert, bool,
346: ca_cert_t *item, va_list args)
347: {
348: certificate_t *cert;
349:
350: VA_ARGS_VGET(args, cert);
351: return cert->equals(cert, item->cert);
352: }
353:
354: /**
355: * Match automatically added certificates and remove/destroy them if they are
356: * not referenced by CA sections.
357: */
358: static bool remove_auto_certs(ca_cert_t *item, void *not_used)
359: {
360: if (item->automatic)
361: {
362: item->automatic = FALSE;
363: if (!item->count)
364: {
365: ca_cert_destroy(item);
366: return TRUE;
367: }
368: }
369: return FALSE;
370: }
371:
372: /**
373: * Find the given certificate that was referenced by a section and remove it
374: * unless it was also loaded automatically or is used by other CA sections.
375: */
376: static bool remove_cert(ca_cert_t *item, certificate_t *cert)
377: {
378: if (item->count && cert->equals(cert, item->cert))
379: {
380: if (--item->count == 0 && !item->automatic)
381: {
382: ca_cert_destroy(item);
383: return TRUE;
384: }
385: }
386: return FALSE;
387: }
388:
389: /**
390: * Adds a certificate to the certificate store
391: */
392: static certificate_t *add_cert_internal(private_stroke_ca_t *this,
393: certificate_t *cert, bool automatic)
394: {
395: ca_cert_t *found;
396:
397: if (this->certs->find_first(this->certs, match_cert, (void**)&found, cert))
398: {
399: cert->destroy(cert);
400: cert = found->cert->get_ref(found->cert);
401: }
402: else
403: {
404: INIT(found,
405: .cert = cert->get_ref(cert)
406: );
407: this->certs->insert_first(this->certs, found);
408: }
409: if (automatic)
410: {
411: found->automatic = TRUE;
412: }
413: else
414: {
415: found->count++;
416: }
417: return cert;
418: }
419:
420: METHOD(stroke_ca_t, add, void,
421: private_stroke_ca_t *this, stroke_msg_t *msg)
422: {
423: certificate_t *cert;
424: ca_section_t *ca;
425:
426: if (msg->add_ca.cacert == NULL)
427: {
428: DBG1(DBG_CFG, "missing cacert parameter");
429: return;
430: }
431: cert = stroke_load_ca_cert(msg->add_ca.cacert);
432: if (cert)
433: {
434: ca = ca_section_create(msg->add_ca.name, msg->add_ca.cacert);
435: if (msg->add_ca.crluri)
436: {
437: ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri));
438: }
439: if (msg->add_ca.crluri2)
440: {
441: ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri2));
442: }
443: if (msg->add_ca.ocspuri)
444: {
445: ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri));
446: }
447: if (msg->add_ca.ocspuri2)
448: {
449: ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri2));
450: }
451: if (msg->add_ca.certuribase)
452: {
453: ca->certuribase = strdup(msg->add_ca.certuribase);
454: }
455: this->lock->write_lock(this->lock);
456: ca->cert = add_cert_internal(this, cert, FALSE);
457: this->sections->insert_last(this->sections, ca);
458: this->lock->unlock(this->lock);
459: DBG1(DBG_CFG, "added ca '%s'", msg->add_ca.name);
460: }
461: }
462:
463: METHOD(stroke_ca_t, del, void,
464: private_stroke_ca_t *this, stroke_msg_t *msg)
465: {
466: enumerator_t *enumerator;
467: ca_section_t *ca = NULL;
468:
469: this->lock->write_lock(this->lock);
470: enumerator = this->sections->create_enumerator(this->sections);
471: while (enumerator->enumerate(enumerator, &ca))
472: {
473: if (streq(ca->name, msg->del_ca.name))
474: {
475: this->sections->remove_at(this->sections, enumerator);
476: break;
477: }
478: ca = NULL;
479: }
480: enumerator->destroy(enumerator);
481: if (ca)
482: {
483: this->certs->remove(this->certs, ca->cert, (void*)remove_cert);
484: }
485: this->lock->unlock(this->lock);
486: if (!ca)
487: {
488: DBG1(DBG_CFG, "no ca named '%s' found\n", msg->del_ca.name);
489: return;
490: }
491: ca_section_destroy(ca);
492:
493: lib->credmgr->flush_cache(lib->credmgr, CERT_ANY);
494: }
495:
496: METHOD(stroke_ca_t, get_cert_ref, certificate_t*,
497: private_stroke_ca_t *this, certificate_t *cert)
498: {
499: ca_cert_t *found;
500:
501: this->lock->read_lock(this->lock);
502: if (this->certs->find_first(this->certs, match_cert, (void**)&found, cert))
503: {
504: cert->destroy(cert);
505: cert = found->cert->get_ref(found->cert);
506: }
507: this->lock->unlock(this->lock);
508: return cert;
509: }
510:
511: METHOD(stroke_ca_t, reload_certs, void,
512: private_stroke_ca_t *this)
513: {
514: enumerator_t *enumerator;
515: certificate_t *cert;
516: ca_section_t *ca;
517: certificate_type_t type = CERT_X509;
518:
519: /* holding the write lock while loading/parsing certificates is not optimal,
520: * however, there usually are not that many ca sections configured */
521: this->lock->write_lock(this->lock);
522: if (this->sections->get_count(this->sections))
523: {
524: DBG1(DBG_CFG, "rereading ca certificates in ca sections");
525: }
526: enumerator = this->sections->create_enumerator(this->sections);
527: while (enumerator->enumerate(enumerator, &ca))
528: {
529: cert = stroke_load_ca_cert(ca->path);
530: if (cert)
531: {
532: if (cert->equals(cert, ca->cert))
533: {
534: cert->destroy(cert);
535: }
536: else
537: {
538: this->certs->remove(this->certs, ca->cert, (void*)remove_cert);
539: ca->cert->destroy(ca->cert);
540: ca->cert = add_cert_internal(this, cert, FALSE);
541: }
542: }
543: else
544: {
545: DBG1(DBG_CFG, "failed to reload certificate '%s', removing ca '%s'",
546: ca->path, ca->name);
547: this->sections->remove_at(this->sections, enumerator);
548: this->certs->remove(this->certs, ca->cert, (void*)remove_cert);
549: ca_section_destroy(ca);
550: type = CERT_ANY;
551: }
552: }
553: enumerator->destroy(enumerator);
554: this->lock->unlock(this->lock);
555: lib->credmgr->flush_cache(lib->credmgr, type);
556: }
557:
558: METHOD(stroke_ca_t, replace_certs, void,
559: private_stroke_ca_t *this, mem_cred_t *certs)
560: {
561: enumerator_t *enumerator;
562: certificate_t *cert;
563:
564: enumerator = certs->set.create_cert_enumerator(&certs->set, CERT_X509,
565: KEY_ANY, NULL, TRUE);
566: this->lock->write_lock(this->lock);
567: this->certs->remove(this->certs, NULL, (void*)remove_auto_certs);
568: while (enumerator->enumerate(enumerator, &cert))
569: {
570: cert = add_cert_internal(this, cert->get_ref(cert), TRUE);
571: cert->destroy(cert);
572: }
573: this->lock->unlock(this->lock);
574: enumerator->destroy(enumerator);
575: lib->credmgr->flush_cache(lib->credmgr, CERT_X509);
576: }
577: /**
578: * list crl or ocsp URIs
579: */
580: static void list_uris(linked_list_t *list, char *label, FILE *out)
581: {
582: bool first = TRUE;
583: char *uri;
584: enumerator_t *enumerator;
585:
586: enumerator = list->create_enumerator(list);
587: while (enumerator->enumerate(enumerator, (void**)&uri))
588: {
589: if (first)
590: {
591: fprintf(out, "%s", label);
592: first = FALSE;
593: }
594: else
595: {
596: fprintf(out, " ");
597: }
598: fprintf(out, "'%s'\n", uri);
599: }
600: enumerator->destroy(enumerator);
601: }
602:
603: METHOD(stroke_ca_t, list, void,
604: private_stroke_ca_t *this, stroke_msg_t *msg, FILE *out)
605: {
606: bool first = TRUE;
607: ca_section_t *section;
608: enumerator_t *enumerator;
609:
610: this->lock->read_lock(this->lock);
611: enumerator = this->sections->create_enumerator(this->sections);
612: while (enumerator->enumerate(enumerator, (void**)§ion))
613: {
614: certificate_t *cert = section->cert;
615: public_key_t *public = cert->get_public_key(cert);
616: chunk_t chunk;
617:
618: if (first)
619: {
620: fprintf(out, "\n");
621: fprintf(out, "List of CA Information Sections:\n");
622: first = FALSE;
623: }
624: fprintf(out, "\n");
625: fprintf(out, " authname: \"%Y\"\n", cert->get_subject(cert));
626:
627: /* list authkey and keyid */
628: if (public)
629: {
630: if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk))
631: {
632: fprintf(out, " authkey: %#B\n", &chunk);
633: }
634: if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &chunk))
635: {
636: fprintf(out, " keyid: %#B\n", &chunk);
637: }
638: public->destroy(public);
639: }
640: list_uris(section->crl, " crluris: ", out);
641: list_uris(section->ocsp, " ocspuris: ", out);
642: if (section->certuribase)
643: {
644: fprintf(out, " certuribase: '%s'\n", section->certuribase);
645: }
646: }
647: enumerator->destroy(enumerator);
648: this->lock->unlock(this->lock);
649: }
650:
651: METHOD(stroke_ca_t, destroy, void,
652: private_stroke_ca_t *this)
653: {
654: this->sections->destroy_function(this->sections, (void*)ca_section_destroy);
655: this->certs->destroy_function(this->certs, (void*)ca_cert_destroy);
656: this->lock->destroy(this->lock);
657: free(this);
658: }
659:
660: /*
661: * see header file
662: */
663: stroke_ca_t *stroke_ca_create()
664: {
665: private_stroke_ca_t *this;
666:
667: INIT(this,
668: .public = {
669: .set = {
670: .create_private_enumerator = (void*)return_null,
671: .create_cert_enumerator = _create_cert_enumerator,
672: .create_shared_enumerator = (void*)return_null,
673: .create_cdp_enumerator = _create_cdp_enumerator,
674: .cache_cert = (void*)nop,
675: },
676: .add = _add,
677: .del = _del,
678: .list = _list,
679: .get_cert_ref = _get_cert_ref,
680: .reload_certs = _reload_certs,
681: .replace_certs = _replace_certs,
682: .destroy = _destroy,
683: },
684: .sections = linked_list_create(),
685: .certs = linked_list_create(),
686: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
687: );
688:
689: return &this->public;
690: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>