Annotation of embedaddon/strongswan/src/libcharon/plugins/vici/vici_authority.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2016-2019 Tobias Brunner
3: * Copyright (C) 2015 Andreas Steffen
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: #define _GNU_SOURCE
18:
19: #include "vici_authority.h"
20: #include "vici_builder.h"
21:
22: #include <threading/rwlock.h>
23: #include <collections/linked_list.h>
24: #include <credentials/certificates/x509.h>
25: #include <utils/debug.h>
26:
27: #include <stdio.h>
28:
29: typedef struct private_vici_authority_t private_vici_authority_t;
30:
31: /**
32: * Private data of an vici_authority_t object.
33: */
34: struct private_vici_authority_t {
35:
36: /**
37: * Public vici_authority_t interface.
38: */
39: vici_authority_t public;
40:
41: /**
42: * Dispatcher
43: */
44: vici_dispatcher_t *dispatcher;
45:
46: /**
47: * credential backend managed by VICI used for our ca certificates
48: */
49: vici_cred_t *cred;
50:
51: /**
52: * List of certification authorities
53: */
54: linked_list_t *authorities;
55:
56: /**
57: * rwlock to lock access to certification authorities
58: */
59: rwlock_t *lock;
60:
61: };
62:
63: typedef struct authority_t authority_t;
64:
65: /**
66: * loaded certification authorities
67: */
68: struct authority_t {
69:
70: /**
71: * Name of the certification authority
72: */
73: char *name;
74:
75: /**
76: * Reference to CA certificate
77: */
78: certificate_t *cert;
79:
80: /**
81: * CRL URIs
82: */
83: linked_list_t *crl_uris;
84:
85: /**
86: * OCSP URIs
87: */
88: linked_list_t *ocsp_uris;
89:
90: /**
91: * Base URI used for certificates from this CA
92: */
93: char *cert_uri_base;
94: };
95:
96: /**
97: * create a new certification authority
98: */
99: static authority_t *authority_create(char *name)
100: {
101: authority_t *authority;
102:
103: INIT(authority,
104: .name = strdup(name),
105: .crl_uris = linked_list_create(),
106: .ocsp_uris = linked_list_create(),
107: );
108:
109: return authority;
110: }
111:
112: /**
113: * destroy a certification authority
114: */
115: static void authority_destroy(authority_t *this)
116: {
117: this->crl_uris->destroy_function(this->crl_uris, free);
118: this->ocsp_uris->destroy_function(this->ocsp_uris, free);
119: DESTROY_IF(this->cert);
120: free(this->cert_uri_base);
121: free(this->name);
122: free(this);
123: }
124:
125:
126: /**
127: * Create a (error) reply message
128: */
129: static vici_message_t* create_reply(char *fmt, ...)
130: {
131: vici_builder_t *builder;
132: va_list args;
133:
134: builder = vici_builder_create();
135: builder->add_kv(builder, "success", fmt ? "no" : "yes");
136: if (fmt)
137: {
138: va_start(args, fmt);
139: builder->vadd_kv(builder, "errmsg", fmt, args);
140: va_end(args);
141: }
142: return builder->finalize(builder);
143: }
144:
145: /**
146: * A rule to parse a key/value or list item
147: */
148: typedef struct {
149: /** name of the key/value or list */
150: char *name;
151: /** function to parse value */
152: bool (*parse)(void *out, chunk_t value);
153: /** result, passed to parse() */
154: void *out;
155: } parse_rule_t;
156:
157: /**
158: * Parse key/values using a rule-set
159: */
160: static bool parse_rules(parse_rule_t *rules, int count, char *name,
161: chunk_t value, vici_message_t **reply)
162: {
163: int i;
164:
165: for (i = 0; i < count; i++)
166: {
167: if (streq(name, rules[i].name))
168: {
169: if (rules[i].parse(rules[i].out, value))
170: {
171: return TRUE;
172: }
173: *reply = create_reply("invalid value for: %s, authority discarded",
174: name);
175: return FALSE;
176: }
177: }
178: *reply = create_reply("unknown option: %s, authority discarded", name);
179: return FALSE;
180: }
181:
182: /**
183: * Parse callback data, passed to each callback
184: */
185: typedef struct {
186: private_vici_authority_t *this;
187: vici_message_t *reply;
188: } request_data_t;
189:
190: /**
191: * Data associated with an authority load
192: */
193: typedef struct {
194: request_data_t *request;
195: authority_t *authority;
196: char *handle;
197: uint32_t slot;
198: char *module;
199: char *file;
200: } load_data_t;
201:
202: /**
203: * Clean up data associated with an authority load
204: */
205: static void free_load_data(load_data_t *data)
206: {
207: if (data->authority)
208: {
209: authority_destroy(data->authority);
210: }
211: free(data->handle);
212: free(data->module);
213: free(data->file);
214: free(data);
215: }
216:
217: /**
218: * Parse a string
219: */
220: CALLBACK(parse_string, bool,
221: char **str, chunk_t v)
222: {
223: if (!chunk_printable(v, NULL, ' '))
224: {
225: return FALSE;
226: }
227: *str = strndup(v.ptr, v.len);
228:
229: return TRUE;
230: }
231:
232: /**
233: * Parse a uint32_t
234: */
235: CALLBACK(parse_uint32, bool,
236: uint32_t *out, chunk_t v)
237: {
238: char buf[16], *end;
239: u_long l;
240:
241: if (!vici_stringify(v, buf, sizeof(buf)))
242: {
243: return FALSE;
244: }
245: l = strtoul(buf, &end, 0);
246: if (*end == 0)
247: {
248: *out = l;
249: return TRUE;
250: }
251: return FALSE;
252: }
253:
254: /**
255: * Parse list of URIs
256: */
257: CALLBACK(parse_uris, bool,
258: linked_list_t *out, chunk_t v)
259: {
260: char *uri;
261:
262: if (!chunk_printable(v, NULL, ' '))
263: {
264: return FALSE;
265: }
266: uri = strndup(v.ptr, v.len);
267: out->insert_last(out, uri);
268:
269: return TRUE;
270: }
271:
272: /**
273: * Parse a CA certificate
274: */
275: CALLBACK(parse_cacert, bool,
276: certificate_t **cacert, chunk_t v)
277: {
278: certificate_t *cert;
279: x509_t *x509;
280:
281: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
282: BUILD_BLOB_PEM, v, BUILD_END);
283: if (!cert)
284: {
285: return create_reply("parsing %N certificate failed",
286: certificate_type_names, CERT_X509);
287: }
288: x509 = (x509_t*)cert;
289:
290: if ((x509->get_flags(x509) & X509_CA) != X509_CA)
291: {
292: cert->destroy(cert);
293: return create_reply("certificate without CA flag, rejected");
294: }
295: *cacert = cert;
296:
297: return TRUE;
298: }
299:
300: CALLBACK(authority_kv, bool,
301: load_data_t *data, vici_message_t *message, char *name, chunk_t value)
302: {
303: parse_rule_t rules[] = {
304: { "cacert", parse_cacert, &data->authority->cert },
305: { "file", parse_string, &data->file },
306: { "handle", parse_string, &data->handle },
307: { "slot", parse_uint32, &data->slot },
308: { "module", parse_string, &data->module },
309: { "cert_uri_base", parse_string, &data->authority->cert_uri_base },
310: };
311:
312: return parse_rules(rules, countof(rules), name, value,
313: &data->request->reply);
314: }
315:
316: CALLBACK(authority_li, bool,
317: load_data_t *data, vici_message_t *message, char *name, chunk_t value)
318: {
319: parse_rule_t rules[] = {
320: { "crl_uris", parse_uris, data->authority->crl_uris },
321: { "ocsp_uris", parse_uris, data->authority->ocsp_uris },
322: };
323:
324: return parse_rules(rules, countof(rules), name, value,
325: &data->request->reply);
326: }
327:
328: static void log_authority_data(authority_t *authority)
329: {
330: enumerator_t *enumerator;
331: identification_t *subject;
332: bool first = TRUE;
333: char *uri;
334:
335: subject = authority->cert->get_subject(authority->cert);
336: DBG2(DBG_CFG, " cacert = %Y", subject);
337:
338: enumerator = authority->crl_uris->create_enumerator(authority->crl_uris);
339: while (enumerator->enumerate(enumerator, &uri))
340: {
341: if (first)
342: {
343: DBG2(DBG_CFG, " crl_uris = %s", uri);
344: first = FALSE;
345: }
346: else
347: {
348: DBG2(DBG_CFG, " %s", uri);
349: }
350: }
351: enumerator->destroy(enumerator);
352:
353: first = TRUE;
354: enumerator = authority->ocsp_uris->create_enumerator(authority->ocsp_uris);
355: while (enumerator->enumerate(enumerator, &uri))
356: {
357: if (first)
358: {
359: DBG2(DBG_CFG, " ocsp_uris = %s", uri);
360: first = FALSE;
361: }
362: else
363: {
364: DBG2(DBG_CFG, " %s", uri);
365: }
366: }
367: enumerator->destroy(enumerator);
368:
369: if (authority->cert_uri_base)
370: {
371: DBG2(DBG_CFG, " cert_uri_base = %s", authority->cert_uri_base);
372: }
373: }
374:
375: CALLBACK(authority_sn, bool,
376: request_data_t *request, vici_message_t *message,
377: vici_parse_context_t *ctx, char *name)
378: {
379: enumerator_t *enumerator;
380: linked_list_t *authorities;
381: authority_t *authority;
382: vici_cred_t *cred;
383: load_data_t *data;
384: chunk_t handle;
385:
386: INIT(data,
387: .request = request,
388: .authority = authority_create(name),
389: .slot = -1,
390: );
391:
392: DBG2(DBG_CFG, " authority %s:", name);
393:
394: if (!message->parse(message, ctx, NULL, authority_kv, authority_li, data))
395: {
396: free_load_data(data);
397: return FALSE;
398: }
399: if (!data->authority->cert)
400: {
401: if (data->file)
402: {
403: data->authority->cert = lib->creds->create(lib->creds,
404: CRED_CERTIFICATE, CERT_X509,
405: BUILD_FROM_FILE, data->file, BUILD_END);
406: }
407: else if (data->handle)
408: {
409: handle = chunk_from_hex(chunk_from_str(data->handle), NULL);
410: if (data->slot != -1)
411: {
412: data->authority->cert = lib->creds->create(lib->creds,
413: CRED_CERTIFICATE, CERT_X509,
414: BUILD_PKCS11_KEYID, handle,
415: BUILD_PKCS11_SLOT, data->slot,
416: data->module ? BUILD_PKCS11_MODULE : BUILD_END,
417: data->module, BUILD_END);
418: }
419: else
420: {
421: data->authority->cert = lib->creds->create(lib->creds,
422: CRED_CERTIFICATE, CERT_X509,
423: BUILD_PKCS11_KEYID, handle,
424: data->module ? BUILD_PKCS11_MODULE : BUILD_END,
425: data->module, BUILD_END);
426: }
427: chunk_free(&handle);
428: }
429: }
430: if (!data->authority->cert)
431: {
432: request->reply = create_reply("CA certificate missing: %s", name);
433: free_load_data(data);
434: return FALSE;
435: }
436: log_authority_data(data->authority);
437:
438: request->this->lock->write_lock(request->this->lock);
439:
440: authorities = request->this->authorities;
441: enumerator = authorities->create_enumerator(authorities);
442: while (enumerator->enumerate(enumerator, &authority))
443: {
444: if (streq(authority->name, name))
445: {
446: /* remove the old authority definition */
447: authorities->remove_at(authorities, enumerator);
448: authority_destroy(authority);
449: break;
450: }
451: }
452: enumerator->destroy(enumerator);
453: authorities->insert_last(authorities, data->authority);
454:
455: cred = request->this->cred;
456: data->authority->cert = cred->add_cert(cred, data->authority->cert);
457: data->authority = NULL;
458:
459: request->this->lock->unlock(request->this->lock);
460: free_load_data(data);
461:
462: return TRUE;
463: }
464:
465: CALLBACK(load_authority, vici_message_t*,
466: private_vici_authority_t *this, char *name, u_int id, vici_message_t *message)
467: {
468: request_data_t request = {
469: .this = this,
470: };
471:
472: if (!message->parse(message, NULL, authority_sn, NULL, NULL, &request))
473: {
474: if (request.reply)
475: {
476: return request.reply;
477: }
478: return create_reply("parsing request failed");
479: }
480: return create_reply(NULL);
481: }
482:
483: CALLBACK(unload_authority, vici_message_t*,
484: private_vici_authority_t *this, char *name, u_int id, vici_message_t *message)
485: {
486: enumerator_t *enumerator;
487: authority_t *authority;
488: char *authority_name;
489: bool found = FALSE;
490:
491: authority_name = message->get_str(message, NULL, "name");
492: if (!authority_name)
493: {
494: return create_reply("unload: missing authority name");
495: }
496:
497: this->lock->write_lock(this->lock);
498: enumerator = this->authorities->create_enumerator(this->authorities);
499: while (enumerator->enumerate(enumerator, &authority))
500: {
501: if (streq(authority->name, authority_name))
502: {
503: this->authorities->remove_at(this->authorities, enumerator);
504: authority_destroy(authority);
505: found = TRUE;
506: break;
507: }
508: }
509: enumerator->destroy(enumerator);
510: this->lock->unlock(this->lock);
511:
512: if (!found)
513: {
514: return create_reply("unload: authority '%s' not found", authority_name);
515: }
516: return create_reply(NULL);
517: }
518:
519: CALLBACK(get_authorities, vici_message_t*,
520: private_vici_authority_t *this, char *name, u_int id,
521: vici_message_t *message)
522: {
523: vici_builder_t *builder;
524: enumerator_t *enumerator;
525: authority_t *authority;
526:
527: builder = vici_builder_create();
528: builder->begin_list(builder, "authorities");
529:
530: this->lock->read_lock(this->lock);
531: enumerator = this->authorities->create_enumerator(this->authorities);
532: while (enumerator->enumerate(enumerator, &authority))
533: {
534: builder->add_li(builder, "%s", authority->name);
535: }
536: enumerator->destroy(enumerator);
537: this->lock->unlock(this->lock);
538:
539: builder->end_list(builder);
540:
541: return builder->finalize(builder);
542: }
543:
544: CALLBACK(list_authorities, vici_message_t*,
545: private_vici_authority_t *this, char *name, u_int id, vici_message_t *request)
546: {
547: enumerator_t *enumerator, *e;
548: authority_t *authority;
549: vici_builder_t *b;
550: char *str, *uri;
551:
552: str = request->get_str(request, NULL, "name");
553:
554: this->lock->read_lock(this->lock);
555: enumerator = this->authorities->create_enumerator(this->authorities);
556: while (enumerator->enumerate(enumerator, &authority))
557: {
558: if (str && !streq(str, authority->name))
559: {
560: continue;
561: }
562: b = vici_builder_create();
563:
564: /* open authority section */
565: b->begin_section(b, authority->name);
566:
567: /* subject DN of cacert */
568: b->add_kv(b, "cacert", "%Y",
569: authority->cert->get_subject(authority->cert));
570:
571: /* list of crl_uris */
572: b->begin_list(b, "crl_uris");
573: e = authority->crl_uris->create_enumerator(authority->crl_uris);
574: while (e->enumerate(e, &uri))
575: {
576: b->add_li(b, "%s", uri);
577: }
578: e->destroy(e);
579: b->end_list(b);
580:
581: /* list of ocsp_uris */
582: b->begin_list(b, "ocsp_uris");
583: e = authority->ocsp_uris->create_enumerator(authority->ocsp_uris);
584: while (e->enumerate(e, &uri))
585: {
586: b->add_li(b, "%s", uri);
587: }
588: e->destroy(e);
589: b->end_list(b);
590:
591: /* cert_uri_base */
592: if (authority->cert_uri_base)
593: {
594: b->add_kv(b, "cert_uri_base", "%s", authority->cert_uri_base);
595: }
596:
597: /* close authority and raise event */
598: b->end_section(b);
599: this->dispatcher->raise_event(this->dispatcher, "list-authority", id,
600: b->finalize(b));
601: }
602: enumerator->destroy(enumerator);
603: this->lock->unlock(this->lock);
604:
605: b = vici_builder_create();
606: return b->finalize(b);
607: }
608:
609: static void manage_command(private_vici_authority_t *this,
610: char *name, vici_command_cb_t cb, bool reg)
611: {
612: this->dispatcher->manage_command(this->dispatcher, name,
613: reg ? cb : NULL, this);
614: }
615:
616: /**
617: * (Un-)register dispatcher functions
618: */
619: static void manage_commands(private_vici_authority_t *this, bool reg)
620: {
621: this->dispatcher->manage_event(this->dispatcher, "list-authority", reg);
622:
623: manage_command(this, "load-authority", load_authority, reg);
624: manage_command(this, "unload-authority", unload_authority, reg);
625: manage_command(this, "get-authorities", get_authorities, reg);
626: manage_command(this, "list-authorities", list_authorities, reg);
627: }
628:
629: /**
630: * data to pass to create_inner_cdp
631: */
632: typedef struct {
633: private_vici_authority_t *this;
634: certificate_type_t type;
635: identification_t *id;
636: } cdp_data_t;
637:
638: /**
639: * destroy cdp enumerator data and unlock list
640: */
641: static void cdp_data_destroy(cdp_data_t *data)
642: {
643: data->this->lock->unlock(data->this->lock);
644: free(data);
645: }
646:
647: /**
648: * inner enumerator constructor for CDP URIs
649: */
650: static enumerator_t *create_inner_cdp(authority_t *authority, cdp_data_t *data)
651: {
652: public_key_t *public;
653: enumerator_t *enumerator = NULL;
654: linked_list_t *list;
655:
656: if (data->type == CERT_X509_OCSP_RESPONSE)
657: {
658: list = authority->ocsp_uris;
659: }
660: else
661: {
662: list = authority->crl_uris;
663: }
664:
665: public = authority->cert->get_public_key(authority->cert);
666: if (public)
667: {
668: if (!data->id)
669: {
670: enumerator = list->create_enumerator(list);
671: }
672: else
673: {
674: if (public->has_fingerprint(public, data->id->get_encoding(data->id)))
675: {
676: enumerator = list->create_enumerator(list);
677: }
678: }
679: public->destroy(public);
680: }
681: return enumerator;
682: }
683:
684: /**
685: * inner enumerator constructor for "Hash and URL"
686: */
687: static enumerator_t *create_inner_cdp_hashandurl(authority_t *authority,
688: cdp_data_t *data)
689: {
690: enumerator_t *enumerator = NULL;
691:
692: if (!data->id || !authority->cert_uri_base)
693: {
694: return NULL;
695: }
696:
697: if (authority->cert->has_subject(authority->cert, data->id) != ID_MATCH_NONE)
698: {
699: enumerator = enumerator_create_single(strdup(authority->cert_uri_base),
700: free);
701: }
702: return enumerator;
703: }
704:
705: METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*,
706: private_vici_authority_t *this, certificate_type_t type,
707: identification_t *id)
708: {
709: cdp_data_t *data;
710:
711: switch (type)
712: { /* we serve CRLs, OCSP responders and URLs for "Hash and URL" */
713: case CERT_X509:
714: case CERT_X509_CRL:
715: case CERT_X509_OCSP_RESPONSE:
716: case CERT_ANY:
717: break;
718: default:
719: return NULL;
720: }
721: data = malloc_thing(cdp_data_t);
722: data->this = this;
723: data->type = type;
724: data->id = id;
725:
726: this->lock->read_lock(this->lock);
727:
728: return enumerator_create_nested(
729: this->authorities->create_enumerator(this->authorities),
730: (type == CERT_X509) ? (void*)create_inner_cdp_hashandurl :
731: (void*)create_inner_cdp, data, (void*)cdp_data_destroy);
732: }
733:
734: METHOD(vici_authority_t, destroy, void,
735: private_vici_authority_t *this)
736: {
737: manage_commands(this, FALSE);
738:
739: this->authorities->destroy_function(this->authorities,
740: (void*)authority_destroy);
741: this->lock->destroy(this->lock);
742: free(this);
743: }
744:
745: /**
746: * See header
747: */
748: vici_authority_t *vici_authority_create(vici_dispatcher_t *dispatcher,
749: vici_cred_t *cred)
750: {
751: private_vici_authority_t *this;
752:
753: INIT(this,
754: .public = {
755: .set = {
756: .create_private_enumerator = (void*)return_null,
757: .create_cert_enumerator = (void*)return_null,
758: .create_shared_enumerator = (void*)return_null,
759: .create_cdp_enumerator = _create_cdp_enumerator,
760: .cache_cert = (void*)nop,
761: },
762: .destroy = _destroy,
763: },
764: .dispatcher = dispatcher,
765: .cred = cred,
766: .authorities = linked_list_create(),
767: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
768: );
769:
770: manage_commands(this, TRUE);
771:
772: return &this->public;
773: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>