vici: Certification Authority support added.

CDP and OCSP URIs for a one or multiple certification authorities
can be added via the VICI interface. swanctl allows to read
definitions from a new authorities section.
This commit is contained in:
Andreas Steffen
2015-07-21 13:02:30 +02:00
parent e194349148
commit 63d370387d
19 changed files with 1553 additions and 15 deletions
+2
View File
@@ -7,10 +7,12 @@ swanctl_SOURCES = \
commands/install.c \
commands/list_sas.c \
commands/list_pols.c \
commands/list_authorities.c \
commands/list_conns.c \
commands/list_certs.c \
commands/list_pools.c \
commands/load_all.c \
commands/load_authorities.h commands/load_authorities.c \
commands/load_conns.c commands/load_conns.h \
commands/load_creds.c commands/load_creds.h \
commands/load_pools.c commands/load_pools.h \
+1 -1
View File
@@ -211,7 +211,7 @@ int command_usage(char *error, ...)
{
for (i = 0; i < MAX_COMMANDS && cmds[i].cmd; i++)
{
fprintf(out, " swanctl --%-15s (-%c) %s\n",
fprintf(out, " swanctl --%-16s (-%c) %s\n",
cmds[i].cmd, cmds[i].op, cmds[i].description);
}
}
+1 -1
View File
@@ -27,7 +27,7 @@
/**
* Maximum number of commands (+1).
*/
#define MAX_COMMANDS 19
#define MAX_COMMANDS 21
/**
* Maximum number of options in a command (+3)
+169
View File
@@ -0,0 +1,169 @@
/*
* 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.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include "command.h"
#define LABELED_CRL_URI (1 << 0)
#define LABELED_OCSP_URI (1 << 1)
CALLBACK(authority_kv, int,
void *null, vici_res_t *res, char *name, void *value, int len)
{
chunk_t chunk;
chunk = chunk_create(value, len);
if (chunk_printable(chunk, NULL, ' '))
{
printf(" %s: %.*s\n", name, len, value);
}
return 0;
}
CALLBACK(authority_list, int,
int *labeled, vici_res_t *res, char *name, void *value, int len)
{
chunk_t chunk;
chunk = chunk_create(value, len);
if (chunk_printable(chunk, NULL, ' '))
{
if (streq(name, "crl_uris"))
{
printf(" %s %.*s\n",
(*labeled & LABELED_CRL_URI) ? " " : "crl_uris: ",
len, value);
*labeled |= LABELED_CRL_URI;
}
if (streq(name, "ocsp_uris"))
{
printf(" %s %.*s\n",
(*labeled & LABELED_OCSP_URI) ? " " : "ocsp_uris:",
len, value);
*labeled %= LABELED_OCSP_URI;
}
}
return 0;
}
CALLBACK(authorities, int,
void *null, vici_res_t *res, char *name)
{
int labeled = 0;
printf("%s:\n", name);
return vici_parse_cb(res, NULL, authority_kv, authority_list, &labeled);
}
CALLBACK(list_cb, void,
command_format_options_t *format, char *name, vici_res_t *res)
{
if (*format & COMMAND_FORMAT_RAW)
{
vici_dump(res, "list-authorities event", *format & COMMAND_FORMAT_PRETTY,
stdout);
}
else
{
if (vici_parse_cb(res, authorities, NULL, NULL, NULL) != 0)
{
fprintf(stderr, "parsing authority event failed: %s\n",
strerror(errno));
}
}
}
static int list_authorities(vici_conn_t *conn)
{
vici_req_t *req;
vici_res_t *res;
command_format_options_t format = COMMAND_FORMAT_NONE;
char *arg, *ca_name = NULL;;
int ret = 0;
while (TRUE)
{
switch (command_getopt(&arg))
{
case 'h':
return command_usage(NULL);
case 'n':
ca_name = arg;
continue;
case 'P':
format |= COMMAND_FORMAT_PRETTY;
/* fall through to raw */
case 'r':
format |= COMMAND_FORMAT_RAW;
continue;
case EOF:
break;
default:
return command_usage("invalid --list-authorities option");
}
break;
}
if (vici_register(conn, "list-authority", list_cb, &format) != 0)
{
ret = errno;
fprintf(stderr, "registering for authorities failed: %s\n",
strerror(errno));
return ret;
}
req = vici_begin("list-authorities");
if (ca_name)
{
vici_add_key_valuef(req, "name", "%s", ca_name);
}
res = vici_submit(req, conn);
if (!res)
{
ret = errno;
fprintf(stderr, "list-authorities request failed: %s\n", strerror(errno));
return ret;
}
if (format & COMMAND_FORMAT_RAW)
{
vici_dump(res, "list-authorities reply", format & COMMAND_FORMAT_PRETTY,
stdout);
}
vici_free_res(res);
return 0;
}
/**
* Register the command.
*/
static void __attribute__ ((constructor))reg()
{
command_register((command_t) {
list_authorities, 'B', "list-authorities",
"list loaded authority configurations",
{"[--raw|--pretty]"},
{
{"help", 'h', 0, "show usage information"},
{"name", 'n', 1, "filter by authority name"},
{"raw", 'r', 0, "dump raw response message"},
{"pretty", 'P', 0, "dump raw response message in pretty print"},
}
});
}
+7 -1
View File
@@ -22,6 +22,7 @@
#include "command.h"
#include "swanctl.h"
#include "load_creds.h"
#include "load_authorities.h"
#include "load_pools.h"
#include "load_conns.h"
@@ -71,6 +72,10 @@ static int load_all(vici_conn_t *conn)
ret = load_creds_cfg(conn, format, cfg, clear, noprompt);
}
if (ret == 0)
{
ret = load_authorities_cfg(conn, format, cfg);
}
if (ret == 0)
{
ret = load_pools_cfg(conn, format, cfg);
}
@@ -90,7 +95,8 @@ static int load_all(vici_conn_t *conn)
static void __attribute__ ((constructor))reg()
{
command_register((command_t) {
load_all, 'q', "load-all", "load credentials, pools and connections",
load_all, 'q', "load-all",
"load credentials, authorities, pools and connections",
{"[--raw|--pretty] [--clear] [--noprompt]"},
{
{"help", 'h', 0, "show usage information"},
+365
View File
@@ -0,0 +1,365 @@
/*
* 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.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include "command.h"
#include "swanctl.h"
#include "load_authorities.h"
/**
* Add a vici list from a comma separated string value
*/
static void add_list_key(vici_req_t *req, char *key, char *value)
{
enumerator_t *enumerator;
char *token;
vici_begin_list(req, key);
enumerator = enumerator_create_token(value, ",", " ");
while (enumerator->enumerate(enumerator, &token))
{
vici_add_list_itemf(req, "%s", token);
}
enumerator->destroy(enumerator);
vici_end_list(req);
}
/**
* Add a vici certificate blob value given by its file patch
*/
static bool add_file_key_value(vici_req_t *req, char *key, char *value)
{
chunk_t *map;
char *path, buf[PATH_MAX];
if (path_absolute(value))
{
path = value;
}
else
{
path = buf;
snprintf(path, PATH_MAX, "%s%s%s",
SWANCTL_X509CADIR, DIRECTORY_SEPARATOR, value);
}
map = chunk_map(path, FALSE);
if (map)
{
vici_add_key_value(req, key, map->ptr, map->len);
chunk_unmap(map);
return TRUE;
}
else
{
fprintf(stderr, "loading ca certificate '%s' failed: %s\n",
path, strerror(errno));
return FALSE;
}
}
/**
* Translate sletting key/values from a section into vici key-values/lists
*/
static bool add_key_values(vici_req_t *req, settings_t *cfg, char *section)
{
enumerator_t *enumerator;
char *key, *value;
bool ret = TRUE;
enumerator = cfg->create_key_value_enumerator(cfg, section);
while (enumerator->enumerate(enumerator, &key, &value))
{
/* pool subnet is encoded as key/value, all other attributes as list */
if (streq(key, "cacert"))
{
ret = add_file_key_value(req, key, value);
}
else if (streq(key, "cert_uri_base"))
{
vici_add_key_valuef(req, key, "%s", value);
}
else
{
add_list_key(req, key, value);
}
if (!ret)
{
break;
}
}
enumerator->destroy(enumerator);
return ret;
}
/**
* Load an authority configuration
*/
static bool load_authority(vici_conn_t *conn, settings_t *cfg,
char *section, command_format_options_t format)
{
vici_req_t *req;
vici_res_t *res;
bool ret = TRUE;
char buf[128];
snprintf(buf, sizeof(buf), "%s.%s", "authorities", section);
req = vici_begin("load-authority");
vici_begin_section(req, section);
if (!add_key_values(req, cfg, buf))
{
vici_free_req(req);
return FALSE;
}
vici_end_section(req);
res = vici_submit(req, conn);
if (!res)
{
fprintf(stderr, "load-authority request failed: %s\n", strerror(errno));
return FALSE;
}
if (format & COMMAND_FORMAT_RAW)
{
vici_dump(res, "load-authority reply", format & COMMAND_FORMAT_PRETTY,
stdout);
}
else if (!streq(vici_find_str(res, "no", "success"), "yes"))
{
fprintf(stderr, "loading authority '%s' failed: %s\n",
section, vici_find_str(res, "", "errmsg"));
ret = FALSE;
}
else
{
printf("loaded authority '%s'\n", section);
}
vici_free_res(res);
return ret;
}
CALLBACK(list_authority, int,
linked_list_t *list, vici_res_t *res, char *name, void *value, int len)
{
if (streq(name, "authorities"))
{
char *str;
if (asprintf(&str, "%.*s", len, value) != -1)
{
list->insert_last(list, str);
}
}
return 0;
}
/**
* Create a list of currently loaded authorities
*/
static linked_list_t* list_authorities(vici_conn_t *conn,
command_format_options_t format)
{
linked_list_t *list;
vici_res_t *res;
list = linked_list_create();
res = vici_submit(vici_begin("get-authorities"), conn);
if (res)
{
if (format & COMMAND_FORMAT_RAW)
{
vici_dump(res, "get-authorities reply", format & COMMAND_FORMAT_PRETTY,
stdout);
}
vici_parse_cb(res, NULL, NULL, list_authority, list);
vici_free_res(res);
}
return list;
}
/**
* Remove and free a string from a list
*/
static void remove_from_list(linked_list_t *list, char *str)
{
enumerator_t *enumerator;
char *current;
enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, &current))
{
if (streq(current, str))
{
list->remove_at(list, enumerator);
free(current);
}
}
enumerator->destroy(enumerator);
}
/**
* Unload a authority by name
*/
static bool unload_authority(vici_conn_t *conn, char *name,
command_format_options_t format)
{
vici_req_t *req;
vici_res_t *res;
bool ret = TRUE;
req = vici_begin("unload-authority");
vici_add_key_valuef(req, "name", "%s", name);
res = vici_submit(req, conn);
if (!res)
{
fprintf(stderr, "unload-authority request failed: %s\n", strerror(errno));
return FALSE;
}
if (format & COMMAND_FORMAT_RAW)
{
vici_dump(res, "unload-authority reply", format & COMMAND_FORMAT_PRETTY,
stdout);
}
else if (!streq(vici_find_str(res, "no", "success"), "yes"))
{
fprintf(stderr, "unloading authority '%s' failed: %s\n",
name, vici_find_str(res, "", "errmsg"));
ret = FALSE;
}
vici_free_res(res);
return ret;
}
/**
* See header.
*/
int load_authorities_cfg(vici_conn_t *conn, command_format_options_t format,
settings_t *cfg)
{
u_int found = 0, loaded = 0, unloaded = 0;
char *section;
enumerator_t *enumerator;
linked_list_t *authorities;
authorities = list_authorities(conn, format);
enumerator = cfg->create_section_enumerator(cfg, "authorities");
while (enumerator->enumerate(enumerator, &section))
{
remove_from_list(authorities, section);
found++;
if (load_authority(conn, cfg, section, format))
{
loaded++;
}
}
enumerator->destroy(enumerator);
/* unload all authorities in daemon, but not in file */
while (authorities->remove_first(authorities, (void**)&section) == SUCCESS)
{
if (unload_authority(conn, section, format))
{
unloaded++;
}
free(section);
}
authorities->destroy(authorities);
if (format & COMMAND_FORMAT_RAW)
{
return 0;
}
if (found == 0)
{
printf("no authorities found, %u unloaded\n", unloaded);
return 0;
}
if (loaded == found)
{
printf("successfully loaded %u authorities, %u unloaded\n",
loaded, unloaded);
return 0;
}
fprintf(stderr, "loaded %u of %u authorities, %u failed to load, "
"%u unloaded\n", loaded, found, found - loaded, unloaded);
return EINVAL;
}
static int load_authorities(vici_conn_t *conn)
{
command_format_options_t format = COMMAND_FORMAT_NONE;
settings_t *cfg;
char *arg;
int ret;
while (TRUE)
{
switch (command_getopt(&arg))
{
case 'h':
return command_usage(NULL);
case 'P':
format |= COMMAND_FORMAT_PRETTY;
/* fall through to raw */
case 'r':
format |= COMMAND_FORMAT_RAW;
continue;
case EOF:
break;
default:
return command_usage("invalid --load-authorities option");
}
break;
}
cfg = settings_create(SWANCTL_CONF);
if (!cfg)
{
fprintf(stderr, "parsing '%s' failed\n", SWANCTL_CONF);
return EINVAL;
}
ret = load_authorities_cfg(conn, format, cfg);
cfg->destroy(cfg);
return ret;
}
/**
* Register the command.
*/
static void __attribute__ ((constructor))reg()
{
command_register((command_t) {
load_authorities, 'b',
"load-authorities", "(re-)load authority configuration",
{"[--raw|--pretty]"},
{
{"help", 'h', 0, "show usage information"},
{"raw", 'r', 0, "dump raw response message"},
{"pretty", 'P', 0, "dump raw response message in pretty print"},
}
});
}
+26
View File
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2015 Andreas Stefffen
* 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 "command.h"
/**
* Load all certification authority definitions from configuration file
*
* @param conn vici connection to load to
* @param format output format
* @param cfg configuration to load from
*/
int load_authorities_cfg(vici_conn_t *conn, command_format_options_t format,
settings_t *cfg);
+7 -1
View File
@@ -53,9 +53,15 @@ list currently active IKE_SAs
.B "\-P, \-\-list\-pols"
list currently installed policies
.TP
.B "\-b, \-\-load\-authorities"
(re\-)load certification authorities information
.TP
.B "\-L, \-\-list\-conns"
list loaded configurations
.TP
.B "\-B, \-\-list\-authorities"
list loaded certification authorities information
.TP
.B "\-x, \-\-list\-certs"
list stored certificates
.TP
@@ -63,7 +69,7 @@ list stored certificates
list loaded pool configurations
.TP
.B "\-q, \-\-load\-all"
(re\-)load credentials, pools and connections
(re\-)load credentials, pools, authorities and connections
.TP
.B "\-c, \-\-load\-conns"
(re\-)load connection configuration
+32
View File
@@ -810,3 +810,35 @@ pools.<name>.<attr> =
subnets for the corresponding attribute types. Alternatively, **<attr>** can
be a numerical identifier, for which string attribute values are accepted
as well.
authorities { # }
Section defining attributes of certification authorities.
authorities.<name> { # }
Section defining a certification authority with a unique name.
authorities.<name>.cacert =
CA certificate belonging to the certification authority.
The certificates may use a relative path from the **swanctl** _x509ca_
directory, or an absolute path.
authorities.<name>.crl_uris =
Comma-separated list of CRL distribution points
Comma-separated list of CRL distribution points (ldap, http, or file URI)
authorities.<name>.ocsp_uris =
Comma-separated list of OCSP URIs
Comma-separated list of OCSP URIs
authorities.<name>.cert_uri_base =
Defines the base URI for the Hash and URL feature supported by IKEv2.
Defines the base URI for the Hash and URL feature supported by IKEv2.
Instead of exchanging complete certificates, IKEv2 allows one to send an
URI that resolves to the DER encoded certificate. The certificate URIs are
built by appending the SHA1 hash of the DER encoded certificates to this
base URI.