Use VICI 2.0 protocol version for certificate queries
authorAndreas Steffen <andreas.steffen@strongswan.org>
Thu, 3 Dec 2015 10:20:04 +0000 (11:20 +0100)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 11 Dec 2015 17:26:54 +0000 (18:26 +0100)
src/libcharon/plugins/vici/Makefile.am
src/libcharon/plugins/vici/vici_cert_info.c [new file with mode: 0644]
src/libcharon/plugins/vici/vici_cert_info.h [new file with mode: 0644]
src/libcharon/plugins/vici/vici_query.c
src/swanctl/commands/list_certs.c
src/swanctl/commands/version.c
testing/tests/swanctl/ocsp-multi-level/evaltest.dat

index f152482..9540c20 100644 (file)
@@ -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 (file)
index 0000000..ce07960
--- /dev/null
@@ -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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 (file)
index 0000000..31d4b46
--- /dev/null
@@ -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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 <credentials/certificates/certificate.h>
+#include <credentials/certificates/x509.h>
+
+/**
+ * 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_ @}*/
index bec9d56..d5d973f 100644 (file)
@@ -41,8 +41,7 @@
 #include "vici_query.h"
 #include "vici_builder.h"
 #include "vici_version.h"
-
-#include <credentials/certificates/x509.h>
+#include "vici_cert_info.h"
 
 #include <inttypes.h>
 #include <time.h>
@@ -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"))
-               {
-                       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"))
+               vici_cert_info_t *cert_info;
+
+               cert_info = vici_cert_info_retrieve(str);
+               if (cert_info)
                {
-                       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);
 
index 167f8d8..bb08649 100644 (file)
 #include <credentials/certificates/ac.h>
 #include <selectors/traffic_selector.h>
 
+#include <vici_version.h>
+#include <vici_cert_info.h>
+
 #include "command.h"
 
 /**
+ * Current certificate type info
+ */
+static vici_cert_info_t *current_cert_info = NULL;
+
+/**
  * Print PEM encoding of a certificate
  */
 static void print_pem(certificate_t *cert)
@@ -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)
-       {
-               printf("CA ");
-       }
-       if (flags & X509_CRL_SIGN)
-       {
-               printf("CRLSign ");
-       }
-       if (flags & X509_AA)
-       {
-               printf("AA ");
-       }
-       if (flags & X509_OCSP_SIGNER)
+       if (flags != X509_NONE)
        {
-               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("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");
        }
-       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
+
+       version_str = vici_find_str(res, "1.0", "vici");
+       if (!enum_from_name(vici_version_names, version_str, &version) ||
+               version == VICI_1_0)
        {
-               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)
-               {
-                       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");
-                       }
+               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)
+               {
+                       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 <dn/san>] [--type X509|X509_AC|X509_CRL] [--pem] "
-                "[--raw|--pretty]"},
+               {"[--subject <dn/san>] "
+                "[--type x509|x509ca|x509aa|x509ac|x509crl|x509ocsp|ocsp] "
+                "[--pem] [--raw|--pretty]"},
                {
                        {"help",                'h', 0, "show usage information"},
                        {"subject",             's', 1, "filter by certificate subject"},
index 0c499e4..32dd77e 100644 (file)
@@ -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 <vici_version.h>
+
 #include <errno.h>
 
 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;
index 48776c4..db10ac1 100644 (file)
@@ -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