diff --git a/src/libcharon/plugins/vici/Makefile.am b/src/libcharon/plugins/vici/Makefile.am index f152482a4..9540c2063 100644 --- a/src/libcharon/plugins/vici/Makefile.am +++ b/src/libcharon/plugins/vici/Makefile.am @@ -19,6 +19,7 @@ libstrongswan_vici_la_SOURCES = \ vici_message.h vici_message.c \ vici_builder.h vici_builder.c \ vici_dispatcher.h vici_dispatcher.c \ + vici_cert_info.c vici_cert_info.h \ vici_query.h vici_query.c \ vici_control.h vici_control.c \ vici_config.h vici_config.c \ @@ -40,6 +41,7 @@ libvici_la_SOURCES = \ vici_message.c vici_message.h \ vici_builder.c vici_builder.h \ vici_version.c vici_version.h \ + vici_cert_info.c vici_cert_info.h \ libvici.c libvici.h libvici_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la diff --git a/src/libcharon/plugins/vici/vici_cert_info.c b/src/libcharon/plugins/vici/vici_cert_info.c new file mode 100644 index 000000000..ce079603b --- /dev/null +++ b/src/libcharon/plugins/vici/vici_cert_info.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2015 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "vici_cert_info.h" + +static vici_cert_info_t vici_cert_infos[] = { + { "any", "", CERT_ANY, + X509_NONE }, + { "x509", "X.509 End Entity Certificate", CERT_X509, + X509_NONE }, + { "x509ca", "X.509 CA Certificate", CERT_X509, + X509_CA }, + { "x509aa", "X.509 AA Certificate", CERT_X509, + X509_AA }, + { "x509ocsp", "X.509 OCSP Signer Certificate", CERT_X509, + X509_OCSP_SIGNER }, + { "x509ac", "X.509 Attribute Certificate", CERT_X509_AC, + X509_NONE }, + { "x509crl", "X.509 CRL", CERT_X509_CRL, + X509_NONE }, + { "ocsp", "OCSP Response", CERT_X509_OCSP_RESPONSE, + X509_NONE } +}; + +/* See header. */ +vici_cert_info_t* vici_cert_info_retrieve(char *type_str) +{ + int i; + + for (i = 0; i < countof(vici_cert_infos); i++) + { + if (strcaseeq(type_str, vici_cert_infos[i].type_str)) + { + return &vici_cert_infos[i]; + } + } + return NULL; +} diff --git a/src/libcharon/plugins/vici/vici_cert_info.h b/src/libcharon/plugins/vici/vici_cert_info.h new file mode 100644 index 000000000..31d4b466f --- /dev/null +++ b/src/libcharon/plugins/vici/vici_cert_info.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2015 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup vici_cert_info vici_cert_info + * @{ @ingroup vici + */ + +#ifndef VICI_CERT_INFO_H_ +#define VICI_CERT_INFO_H_ + +typedef struct vici_cert_info_t vici_cert_info_t; + +#include +#include + +/** + * Information on vici certificate types + */ +struct vici_cert_info_t { + + /** + * Certificate type string used in vici messages + */ + char *type_str; + + /** + * Caption describing the certificate type + */ + char *caption; + + /** + * Base certificate type + */ + certificate_type_t type; + + /** + * X.509 flag + */ + x509_flag_t flag; + +}; + +/** + * Retrieve information on a given certificate type + * + * @param type_str Vici certificate type string + * @return Information record or NULL if not found + */ +vici_cert_info_t* vici_cert_info_retrieve(char *type_str); + +#endif /** VICI_CERT_INFO_H_ @}*/ diff --git a/src/libcharon/plugins/vici/vici_query.c b/src/libcharon/plugins/vici/vici_query.c index bec9d565a..d5d973f6b 100644 --- a/src/libcharon/plugins/vici/vici_query.c +++ b/src/libcharon/plugins/vici/vici_query.c @@ -41,8 +41,7 @@ #include "vici_query.h" #include "vici_builder.h" #include "vici_version.h" - -#include +#include "vici_cert_info.h" #include #include @@ -821,7 +820,7 @@ typedef struct { */ static void enum_x509(private_vici_query_t *this, u_int id, linked_list_t *certs, cert_filter_t *filter, - x509_flag_t flag) + x509_flag_t flag, char *cert_type) { enumerator_t *enumerator; certificate_t *cert; @@ -830,7 +829,7 @@ static void enum_x509(private_vici_query_t *this, u_int id, x509_flag_t mask; x509_t *x509; - if (filter->type != CERT_ANY && filter->version == VICI_2_0 && + if (filter->type != CERT_ANY && filter->version != VICI_1_0 && filter->flag != flag) { return; @@ -849,8 +848,16 @@ static void enum_x509(private_vici_query_t *this, u_int id, if (cert->get_encoding(cert, CERT_ASN1_DER, &encoding)) { b = vici_builder_create(); - b->add_kv(b, "type", "%N", - certificate_type_names, cert->get_type(cert)); + if (filter->version == VICI_1_0) + { + b->add_kv(b, "type", "%N", certificate_type_names, + cert->get_type(cert)); + } + else + { + b->add_kv(b, "vici", "%N", vici_version_names, VICI_VERSION); + b->add_kv(b, "type", "%s", cert_type); + } if (has_privkey(cert)) { b->add_kv(b, "has_privkey", "yes"); @@ -869,7 +876,8 @@ static void enum_x509(private_vici_query_t *this, u_int id, * Enumerate all non-X.509 certificate types */ static void enum_others(private_vici_query_t *this, u_int id, - linked_list_t *certs, cert_filter_t *filter) + linked_list_t *certs, cert_filter_t *filter, + char *cert_type) { enumerator_t *enumerator; certificate_t *cert; @@ -882,8 +890,16 @@ static void enum_others(private_vici_query_t *this, u_int id, if (cert->get_encoding(cert, CERT_ASN1_DER, &encoding)) { b = vici_builder_create(); - b->add_kv(b, "type", "%N", - certificate_type_names, cert->get_type(cert)); + if (filter->version == VICI_1_0) + { + b->add_kv(b, "type", "%N", certificate_type_names, + cert->get_type(cert)); + } + else + { + b->add_kv(b, "vici", "%N", vici_version_names, VICI_VERSION); + b->add_kv(b, "type", "%s", cert_type); + } b->add(b, VICI_KEY_VALUE, "data", encoding); free(encoding.ptr); @@ -898,7 +914,8 @@ static void enum_others(private_vici_query_t *this, u_int id, * Enumerate all certificates of a given type */ static void enum_certs(private_vici_query_t *this, u_int id, - cert_filter_t *filter, certificate_type_t type) + cert_filter_t *filter, certificate_type_t type, + char *cert_type) { enumerator_t *e1, *e2; certificate_t *cert, *current; @@ -937,14 +954,14 @@ static void enum_certs(private_vici_query_t *this, u_int id, if (type == CERT_X509) { - enum_x509(this, id, certs, filter, X509_NONE); - enum_x509(this, id, certs, filter, X509_CA); - enum_x509(this, id, certs, filter, X509_AA); - enum_x509(this, id, certs, filter, X509_OCSP_SIGNER); + enum_x509(this, id, certs, filter, X509_NONE, "x509"); + enum_x509(this, id, certs, filter, X509_CA, "x509ca"); + enum_x509(this, id, certs, filter, X509_AA, "x509ac"); + enum_x509(this, id, certs, filter, X509_OCSP_SIGNER, "x509ocsp"); } else { - enum_others(this, id, certs, filter); + enum_others(this, id, certs, filter, cert_type); } certs->destroy_offset(certs, offsetof(certificate_t, destroy)); } @@ -979,40 +996,13 @@ CALLBACK(list_certs, vici_message_t*, } else /* VICI 2.0 */ { - if (strcaseeq(str, "any")) + vici_cert_info_t *cert_info; + + cert_info = vici_cert_info_retrieve(str); + if (cert_info) { - filter.type = CERT_ANY; - } - else if (strcaseeq(str, "x509")) - { - filter.type = CERT_X509; - } - else if (strcaseeq(str, "x509ca")) - { - filter.type = CERT_X509; - filter.flag = X509_CA; - } - else if (strcaseeq(str, "x509aa")) - { - filter.type = CERT_X509; - filter.flag = X509_AA; - } - else if (strcaseeq(str, "x509ocsp")) - { - filter.type = CERT_X509; - filter.flag = X509_OCSP_SIGNER; - } - else if (strcaseeq(str, "x509crl")) - { - filter.type = CERT_X509_CRL; - } - else if (strcaseeq(str, "x509ac")) - { - filter.type = CERT_X509_AC; - } - else if (strcaseeq(str, "ocsp")) - { - filter.type = CERT_X509_OCSP_RESPONSE; + filter.type = cert_info->type; + filter.flag = cert_info->flag; } else { @@ -1026,10 +1016,10 @@ CALLBACK(list_certs, vici_message_t*, { filter.subject = identification_create_from_string(str); } - enum_certs(this, id, &filter, CERT_X509); - enum_certs(this, id, &filter, CERT_X509_AC); - enum_certs(this, id, &filter, CERT_X509_CRL); - enum_certs(this, id, &filter, CERT_X509_OCSP_RESPONSE); + enum_certs(this, id, &filter, CERT_X509, "x509"); + enum_certs(this, id, &filter, CERT_X509_AC, "x509ac"); + enum_certs(this, id, &filter, CERT_X509_CRL, "x509crl"); + enum_certs(this, id, &filter, CERT_X509_OCSP_RESPONSE, "ocsp"); DESTROY_IF(filter.subject); finalize: @@ -1146,6 +1136,7 @@ CALLBACK(version, vici_message_t*, b = vici_builder_create(); + b->add_kv(b, "vici", "%N", vici_version_names, VICI_VERSION); b->add_kv(b, "daemon", "%s", lib->ns); b->add_kv(b, "version", "%s", VERSION); diff --git a/src/swanctl/commands/list_certs.c b/src/swanctl/commands/list_certs.c index 167f8d848..bb08649c8 100644 --- a/src/swanctl/commands/list_certs.c +++ b/src/swanctl/commands/list_certs.c @@ -29,8 +29,16 @@ #include #include +#include +#include + #include "command.h" +/** + * Current certificate type info + */ +static vici_cert_info_t *current_cert_info = NULL; + /** * Print PEM encoding of a certificate */ @@ -115,44 +123,43 @@ static void print_x509(x509_t *x509) enumerator->destroy(enumerator); flags = x509->get_flags(x509); - printf("flags: "); - if (flags & X509_CA) + if (flags != X509_NONE) { - printf("CA "); + printf("flags: "); + if (flags & X509_CA) + { + printf("CA "); + } + if (flags & X509_CRL_SIGN) + { + printf("CRLSign "); + } + if (flags & X509_OCSP_SIGNER) + { + printf("ocspSigning "); + } + if (flags & X509_SERVER_AUTH) + { + printf("serverAuth "); + } + if (flags & X509_CLIENT_AUTH) + { + printf("clientAuth "); + } + if (flags & X509_IKE_INTERMEDIATE) + { + printf("ikeIntermediate "); + } + if (flags & X509_MS_SMARTCARD_LOGON) + { + printf("msSmartcardLogon"); + } + if (flags & X509_SELF_SIGNED) + { + printf("self-signed "); + } + printf("\n"); } - if (flags & X509_CRL_SIGN) - { - printf("CRLSign "); - } - if (flags & X509_AA) - { - printf("AA "); - } - if (flags & X509_OCSP_SIGNER) - { - printf("OCSP "); - } - if (flags & X509_AA) - { - printf("AA "); - } - if (flags & X509_SERVER_AUTH) - { - printf("serverAuth "); - } - if (flags & X509_CLIENT_AUTH) - { - printf("clientAuth "); - } - if (flags & X509_IKE_INTERMEDIATE) - { - printf("iKEIntermediate "); - } - if (flags & X509_SELF_SIGNED) - { - printf("self-signed "); - } - printf("\n"); first = TRUE; enumerator = x509->create_crl_uri_enumerator(x509); @@ -486,8 +493,8 @@ static void print_cert(certificate_t *cert, bool has_privkey) now = time(NULL); - printf("cert: %N\n", certificate_type_names, cert->get_type(cert)); - if (cert->get_type(cert) != CERT_X509_CRL) + if (cert->get_type(cert) != CERT_X509_CRL && + cert->get_type(cert) != CERT_X509_OCSP_RESPONSE) { printf("subject: \"%Y\"\n", cert->get_subject(cert)); } @@ -541,49 +548,75 @@ static void print_cert(certificate_t *cert, bool has_privkey) CALLBACK(list_cb, void, command_format_options_t *format, char *name, vici_res_t *res) { + certificate_t *cert; + vici_version_t version; + vici_cert_info_t *cert_info; + bool has_privkey, first = FALSE; + char *version_str, *type_str; + void *buf; + int len; + if (*format & COMMAND_FORMAT_RAW) { vici_dump(res, "list-cert event", *format & COMMAND_FORMAT_PRETTY, stdout); + return; } - else - { - certificate_type_t type; - certificate_t *cert; - void *buf; - int len; - bool has_privkey; - buf = vici_find(res, &len, "data"); - has_privkey = streq(vici_find_str(res, "no", "has_privkey"), "yes"); - if (enum_from_name(certificate_type_names, - vici_find_str(res, "ANY", "type"), &type) && - type != CERT_ANY && buf) + version_str = vici_find_str(res, "1.0", "vici"); + if (!enum_from_name(vici_version_names, version_str, &version) || + version == VICI_1_0) + { + fprintf(stderr, "unsupported vici version '%s'\n", version_str); + return; + } + + buf = vici_find(res, &len, "data"); + if (!buf) + { + fprintf(stderr, "received incomplete certificate data\n"); + return; + } + has_privkey = streq(vici_find_str(res, "no", "has_privkey"), "yes"); + + type_str = vici_find_str(res, "any", "type"); + cert_info = vici_cert_info_retrieve(type_str); + if (!cert_info || cert_info->type == CERT_ANY) + { + fprintf(stderr, "unsupported certificate type '%s'\n", type_str); + return; + } + + /* Detect change of certificate type */ + if (cert_info != current_cert_info) + { + first = TRUE; + current_cert_info = cert_info; + } + + /* Parse certificate data blob */ + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, cert_info->type, + BUILD_BLOB_ASN1_DER, chunk_create(buf, len), + BUILD_END); + if (cert) + { + if (*format & COMMAND_FORMAT_PEM) { - cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, type, - BUILD_BLOB_ASN1_DER, chunk_create(buf, len), - BUILD_END); - if (cert) - { - if (*format & COMMAND_FORMAT_PEM) - { - print_pem(cert); - } - else - { - print_cert(cert, has_privkey); - } - cert->destroy(cert); - } - else - { - fprintf(stderr, "parsing certificate failed\n"); - } + print_pem(cert); } else { - fprintf(stderr, "received incomplete certificate data\n"); + if (first) + { + printf("List of %ss:\n\n", cert_info->caption); + } + print_cert(cert, has_privkey); } + cert->destroy(cert); + } + else + { + fprintf(stderr, "parsing certificate failed\n"); } } @@ -631,6 +664,8 @@ static int list_certs(vici_conn_t *conn) return ret; } req = vici_begin("list-certs"); + vici_add_version(req, VICI_VERSION); + if (type) { vici_add_key_valuef(req, "type", "%s", type); @@ -639,6 +674,7 @@ static int list_certs(vici_conn_t *conn) { vici_add_key_valuef(req, "subject", "%s", subject); } + res = vici_submit(req, conn); if (!res) { @@ -662,8 +698,9 @@ static void __attribute__ ((constructor))reg() { command_register((command_t) { list_certs, 'x', "list-certs", "list stored certificates", - {"[--subject ] [--type X509|X509_AC|X509_CRL] [--pem] " - "[--raw|--pretty]"}, + {"[--subject ] " + "[--type x509|x509ca|x509aa|x509ac|x509crl|x509ocsp|ocsp] " + "[--pem] [--raw|--pretty]"}, { {"help", 'h', 0, "show usage information"}, {"subject", 's', 1, "filter by certificate subject"}, diff --git a/src/swanctl/commands/version.c b/src/swanctl/commands/version.c index 0c499e4cc..32dd77e31 100644 --- a/src/swanctl/commands/version.c +++ b/src/swanctl/commands/version.c @@ -2,6 +2,9 @@ * Copyright (C) 2014 Martin Willi * Copyright (C) 2014 revosec AG * + * Copyright (C) 2015 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your @@ -15,6 +18,8 @@ #include "command.h" +#include + #include static int version(vici_conn_t *conn) @@ -51,7 +56,8 @@ static int version(vici_conn_t *conn) if (!daemon) { - printf("strongSwan swanctl %s\n", VERSION); + printf("strongSwan swanctl %s vici %N\n", VERSION, + vici_version_names, VICI_VERSION); return 0; } @@ -69,12 +75,13 @@ static int version(vici_conn_t *conn) } else { - printf("strongSwan %s %s (%s, %s, %s)\n", - vici_find_str(res, "", "version"), - vici_find_str(res, "", "daemon"), - vici_find_str(res, "", "sysname"), - vici_find_str(res, "", "release"), - vici_find_str(res, "", "machine")); + printf("strongSwan %s vici %s %s (%s, %s, %s)\n", + vici_find_str(res, "" , "version"), + vici_find_str(res, "1.0", "vici"), + vici_find_str(res, "" , "daemon"), + vici_find_str(res, "" , "sysname"), + vici_find_str(res, "" , "release"), + vici_find_str(res, "" , "machine")); } vici_free_res(res); return 0; diff --git a/testing/tests/swanctl/ocsp-multi-level/evaltest.dat b/testing/tests/swanctl/ocsp-multi-level/evaltest.dat index 48776c47c..db10ac184 100644 --- a/testing/tests/swanctl/ocsp-multi-level/evaltest.dat +++ b/testing/tests/swanctl/ocsp-multi-level/evaltest.dat @@ -1,8 +1,8 @@ -moon:: swanctl --list-certs --type X509_OCSP_RESPONSE 2> /dev/null::subject.*ocsp.research.strongswan.org::YES -moon:: swanctl --list-certs --type X509_OCSP_RESPONSE 2> /dev/null::subject.*ocsp.sales.strongswan.org::YES -moon:: swanctl --list-certs --type X509_OCSP_RESPONSE 2> /dev/null::subject.*ocsp.strongswan.org::YES -carol::swanctl --list-certs --type X509_OCSP_RESPONSE 2> /dev/null::subject.*ocsp.strongswan.org::YES -dave:: swanctl --list-certs --type X509_OCSP_RESPONSE 2> /dev/null::subject.*ocsp.strongswan.org::YES +moon:: swanctl --list-certs --type ocsp 2> /dev/null::issuer.*ocsp.research.strongswan.org::YES +moon:: swanctl --list-certs --type ocsp 2> /dev/null::issuer.*ocsp.sales.strongswan.org::YES +moon:: swanctl --list-certs --type ocsp 2> /dev/null::issuer.*ocsp.strongswan.org::YES +carol::swanctl --list-certs --type ocsp 2> /dev/null::issuer.*ocsp.strongswan.org::YES +dave:: swanctl --list-certs --type ocsp 2> /dev/null::issuer.*ocsp.strongswan.org::YES moon:: cat /var/log/daemon.log::ocsp response correctly signed by.*ocsp.research.strongswan.org::YES moon:: cat /var/log/daemon.log::ocsp response correctly signed by.*ocsp.sales.strongswan.org::YES moon:: cat /var/log/daemon.log::ocsp response correctly signed by.*ocsp.strongswan.org::YES