diff options
Diffstat (limited to 'src/swanctl')
-rw-r--r-- | src/swanctl/Makefile.am | 1 | ||||
-rw-r--r-- | src/swanctl/Makefile.in | 12 | ||||
-rw-r--r-- | src/swanctl/command.h | 2 | ||||
-rw-r--r-- | src/swanctl/commands/initiate.c | 12 | ||||
-rw-r--r-- | src/swanctl/commands/install.c | 15 | ||||
-rw-r--r-- | src/swanctl/commands/list_pools.c | 14 | ||||
-rw-r--r-- | src/swanctl/commands/list_sas.c | 23 | ||||
-rw-r--r-- | src/swanctl/commands/load_authorities.c | 8 | ||||
-rw-r--r-- | src/swanctl/commands/load_conns.c | 67 | ||||
-rw-r--r-- | src/swanctl/commands/load_creds.c | 377 | ||||
-rw-r--r-- | src/swanctl/commands/rekey.c | 125 | ||||
-rw-r--r-- | src/swanctl/swanctl.8.in | 3 | ||||
-rw-r--r-- | src/swanctl/swanctl.conf | 123 | ||||
-rw-r--r-- | src/swanctl/swanctl.conf.5.head.in | 3 | ||||
-rw-r--r-- | src/swanctl/swanctl.conf.5.main | 253 | ||||
-rw-r--r-- | src/swanctl/swanctl.opt | 223 |
16 files changed, 1109 insertions, 152 deletions
diff --git a/src/swanctl/Makefile.am b/src/swanctl/Makefile.am index 9ca759ea3..2fc998262 100644 --- a/src/swanctl/Makefile.am +++ b/src/swanctl/Makefile.am @@ -4,6 +4,7 @@ swanctl_SOURCES = \ command.c command.h \ commands/initiate.c \ commands/terminate.c \ + commands/rekey.c \ commands/redirect.c \ commands/install.c \ commands/list_sas.c \ diff --git a/src/swanctl/Makefile.in b/src/swanctl/Makefile.in index ff9dca09d..7e2a1da6b 100644 --- a/src/swanctl/Makefile.in +++ b/src/swanctl/Makefile.in @@ -113,9 +113,9 @@ am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" \ PROGRAMS = $(sbin_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_swanctl_OBJECTS = command.$(OBJEXT) commands/initiate.$(OBJEXT) \ - commands/terminate.$(OBJEXT) commands/redirect.$(OBJEXT) \ - commands/install.$(OBJEXT) commands/list_sas.$(OBJEXT) \ - commands/list_pols.$(OBJEXT) \ + commands/terminate.$(OBJEXT) commands/rekey.$(OBJEXT) \ + commands/redirect.$(OBJEXT) commands/install.$(OBJEXT) \ + commands/list_sas.$(OBJEXT) commands/list_pols.$(OBJEXT) \ commands/list_authorities.$(OBJEXT) \ commands/list_conns.$(OBJEXT) commands/list_certs.$(OBJEXT) \ commands/list_pools.$(OBJEXT) commands/list_algs.$(OBJEXT) \ @@ -377,7 +377,6 @@ exec_prefix = @exec_prefix@ fips_mode = @fips_mode@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ -h_plugins = @h_plugins@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ @@ -412,6 +411,7 @@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ +p_plugins = @p_plugins@ pcsclite_CFLAGS = @pcsclite_CFLAGS@ pcsclite_LIBS = @pcsclite_LIBS@ pdfdir = @pdfdir@ @@ -465,6 +465,7 @@ swanctl_SOURCES = \ command.c command.h \ commands/initiate.c \ commands/terminate.c \ + commands/rekey.c \ commands/redirect.c \ commands/install.c \ commands/list_sas.c \ @@ -603,6 +604,8 @@ commands/initiate.$(OBJEXT): commands/$(am__dirstamp) \ commands/$(DEPDIR)/$(am__dirstamp) commands/terminate.$(OBJEXT): commands/$(am__dirstamp) \ commands/$(DEPDIR)/$(am__dirstamp) +commands/rekey.$(OBJEXT): commands/$(am__dirstamp) \ + commands/$(DEPDIR)/$(am__dirstamp) commands/redirect.$(OBJEXT): commands/$(am__dirstamp) \ commands/$(DEPDIR)/$(am__dirstamp) commands/install.$(OBJEXT): commands/$(am__dirstamp) \ @@ -672,6 +675,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/load_pools.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/redirect.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/rekey.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/reload_settings.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/stats.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@commands/$(DEPDIR)/terminate.Po@am__quote@ diff --git a/src/swanctl/command.h b/src/swanctl/command.h index 7b92ae91a..c17811498 100644 --- a/src/swanctl/command.h +++ b/src/swanctl/command.h @@ -27,7 +27,7 @@ /** * Maximum number of commands (+1). */ -#define MAX_COMMANDS 24 +#define MAX_COMMANDS 25 /** * Maximum number of options in a command (+3) diff --git a/src/swanctl/commands/initiate.c b/src/swanctl/commands/initiate.c index eb7b6adbd..8e452a6f6 100644 --- a/src/swanctl/commands/initiate.c +++ b/src/swanctl/commands/initiate.c @@ -37,7 +37,7 @@ static int initiate(vici_conn_t *conn) vici_req_t *req; vici_res_t *res; command_format_options_t format = COMMAND_FORMAT_NONE; - char *arg, *child = NULL; + char *arg, *child = NULL, *ike = NULL; int ret = 0, timeout = 0, level = 1; while (TRUE) @@ -55,6 +55,9 @@ static int initiate(vici_conn_t *conn) case 'c': child = arg; continue; + case 'i': + ike = arg; + continue; case 't': timeout = atoi(arg); continue; @@ -80,6 +83,10 @@ static int initiate(vici_conn_t *conn) { vici_add_key_valuef(req, "child", "%s", child); } + if (ike) + { + vici_add_key_valuef(req, "ike", "%s", ike); + } if (timeout) { vici_add_key_valuef(req, "timeout", "%d", timeout * 1000); @@ -121,10 +128,11 @@ static void __attribute__ ((constructor))reg() { command_register((command_t) { initiate, 'i', "initiate", "initiate a connection", - {"--child <name> [--timeout <s>] [--raw|--pretty]"}, + {"--child <name> [--ike <name>] [--timeout <s>] [--raw|--pretty]"}, { {"help", 'h', 0, "show usage information"}, {"child", 'c', 1, "initate a CHILD_SA configuration"}, + {"ike", 'i', 1, "name of the connection to which the child belongs"}, {"timeout", 't', 1, "timeout in seconds before detaching"}, {"raw", 'r', 0, "dump raw response message"}, {"pretty", 'P', 0, "dump raw response message in pretty print"}, diff --git a/src/swanctl/commands/install.c b/src/swanctl/commands/install.c index 59c5c24ab..24a397b87 100644 --- a/src/swanctl/commands/install.c +++ b/src/swanctl/commands/install.c @@ -22,7 +22,7 @@ static int manage_policy(vici_conn_t *conn, char *label) vici_req_t *req; vici_res_t *res; command_format_options_t format = COMMAND_FORMAT_NONE; - char *arg, *child = NULL; + char *arg, *child = NULL, *ike = NULL; int ret = 0; while (TRUE) @@ -40,6 +40,9 @@ static int manage_policy(vici_conn_t *conn, char *label) case 'c': child = arg; continue; + case 'i': + ike = arg; + continue; case EOF: break; default: @@ -52,6 +55,10 @@ static int manage_policy(vici_conn_t *conn, char *label) { vici_add_key_valuef(req, "child", "%s", child); } + if (ike) + { + vici_add_key_valuef(req, "ike", "%s", ike); + } res = vici_submit(req, conn); if (!res) { @@ -98,10 +105,11 @@ static void __attribute__ ((constructor))reg_uninstall() { command_register((command_t) { uninstall, 'u', "uninstall", "uninstall a trap or shunt policy", - {"--child <name> [--raw|--pretty]"}, + {"--child <name> [--ike <name>] [--raw|--pretty]"}, { {"help", 'h', 0, "show usage information"}, {"child", 'c', 1, "CHILD_SA configuration to uninstall"}, + {"ike", 'i', 1, "name of the connection to which the child belongs"}, {"raw", 'r', 0, "dump raw response message"}, {"pretty", 'P', 0, "dump raw response message in pretty print"}, } @@ -115,10 +123,11 @@ static void __attribute__ ((constructor))reg_install() { command_register((command_t) { install, 'p', "install", "install a trap or shunt policy", - {"--child <name> [--raw|--pretty]"}, + {"--child <name> [--ike <name>] [--raw|--pretty]"}, { {"help", 'h', 0, "show usage information"}, {"child", 'c', 1, "CHILD_SA configuration to install"}, + {"ike", 'i', 1, "name of the connection to which the child belongs"}, {"raw", 'r', 0, "dump raw response message"}, {"pretty", 'P', 0, "dump raw response message in pretty print"}, } diff --git a/src/swanctl/commands/list_pools.c b/src/swanctl/commands/list_pools.c index 429107e17..a170adeba 100644 --- a/src/swanctl/commands/list_pools.c +++ b/src/swanctl/commands/list_pools.c @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015 Tobias Brunner - * Hochschule fuer Technik Rapperswil + * Copyright (C) 2015-2016 Tobias Brunner + * HSR Hochschule fuer Technik Rapperswil * * Copyright (C) 2014 Martin Willi * Copyright (C) 2014 revosec AG @@ -58,7 +58,7 @@ static int list_pools(vici_conn_t *conn) vici_req_t *req; vici_res_t *res; command_format_options_t format = COMMAND_FORMAT_NONE; - char *arg; + char *arg, *name = NULL; int ret = 0; bool leases = FALSE; @@ -77,6 +77,9 @@ static int list_pools(vici_conn_t *conn) case 'l': leases = TRUE; continue; + case 'n': + name = arg; + continue; case EOF: break; default: @@ -90,6 +93,10 @@ static int list_pools(vici_conn_t *conn) { vici_add_key_valuef(req, "leases", "yes"); } + if (name) + { + vici_add_key_valuef(req, "name", "%s", name); + } res = vici_submit(req, conn); if (!res) { @@ -123,6 +130,7 @@ static void __attribute__ ((constructor))reg() {"raw", 'r', 0, "dump raw response message"}, {"pretty", 'P', 0, "dump raw response message in pretty print"}, {"leases", 'l', 0, "list leases of each pool"}, + {"name", 'n', 1, "filter pools by name"}, } }); } diff --git a/src/swanctl/commands/list_sas.c b/src/swanctl/commands/list_sas.c index e5f251d17..28602fc65 100644 --- a/src/swanctl/commands/list_sas.c +++ b/src/swanctl/commands/list_sas.c @@ -112,8 +112,9 @@ CALLBACK(child_sas, int, if (ret == 0) { printf(" %s: #%s, reqid %s, %s, %s%s, %s:", - name, child->get(child, "uniqueid"), child->get(child, "reqid"), - child->get(child, "state"), child->get(child, "mode"), + child->get(child, "name"), child->get(child, "uniqueid"), + child->get(child, "reqid"), child->get(child, "state"), + child->get(child, "mode"), child->get(child, "encap") ? "-in-UDP" : "", child->get(child, "protocol")); @@ -165,6 +166,15 @@ CALLBACK(child_sas, int, printf(" in %s%s%s", child->get(child, "spi-in"), child->get(child, "cpi-in") ? "/" : "", child->get(child, "cpi-in") ?: ""); + if (child->get(child, "mark-in")) + { + printf(" (0x%s", child->get(child, "mark-in")); + if (child->get(child, "mark-mask-in")) + { + printf("/0x%s", child->get(child, "mark-mask-in")); + } + printf(")"); + } printf(", %6s bytes, %5s packets", child->get(child, "bytes-in"), child->get(child, "packets-in")); if (child->get(child, "use-in")) @@ -176,6 +186,15 @@ CALLBACK(child_sas, int, printf(" out %s%s%s", child->get(child, "spi-out"), child->get(child, "cpi-out") ? "/" : "", child->get(child, "cpi-out") ?: ""); + if (child->get(child, "mark-out")) + { + printf(" (0x%s", child->get(child, "mark-out")); + if (child->get(child, "mark-mask-out")) + { + printf("/0x%s", child->get(child, "mark-mask-out")); + } + printf(")"); + } printf(", %6s bytes, %5s packets", child->get(child, "bytes-out"), child->get(child, "packets-out")); if (child->get(child, "use-out")) diff --git a/src/swanctl/commands/load_authorities.c b/src/swanctl/commands/load_authorities.c index 352a185e8..8947866f5 100644 --- a/src/swanctl/commands/load_authorities.c +++ b/src/swanctl/commands/load_authorities.c @@ -86,18 +86,18 @@ static bool add_key_values(vici_req_t *req, settings_t *cfg, char *section) 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")) + else if (streq(key, "crl_uris") || + streq(key, "ocsp_uris")) { - vici_add_key_valuef(req, key, "%s", value); + add_list_key(req, key, value); } else { - add_list_key(req, key, value); + vici_add_key_valuef(req, key, "%s", value); } if (!ret) { diff --git a/src/swanctl/commands/load_conns.c b/src/swanctl/commands/load_conns.c index 2e443a94a..0518ef54f 100644 --- a/src/swanctl/commands/load_conns.c +++ b/src/swanctl/commands/load_conns.c @@ -38,6 +38,7 @@ static bool is_list_key(char *key) "vips", "pools", "groups", + "cert_policy", }; int i; @@ -97,7 +98,7 @@ static void add_list_key(vici_req_t *req, char *key, char *value) static bool add_file_list_key(vici_req_t *req, char *key, char *value) { enumerator_t *enumerator; - chunk_t *map; + chunk_t *map, blob; char *token, buf[PATH_MAX]; bool ret = TRUE; @@ -105,41 +106,51 @@ static bool add_file_list_key(vici_req_t *req, char *key, char *value) enumerator = enumerator_create_token(value, ",", " "); while (enumerator->enumerate(enumerator, &token)) { - if (!path_absolute(token)) + if (strcasepfx(token, "0x") || strcasepfx(token, "0s")) { - if (streq(key, "certs")) + blob = chunk_from_str(token + 2); + blob = strcasepfx(token, "0x") ? chunk_from_hex(blob, NULL) + : chunk_from_base64(blob, NULL); + vici_add_list_item(req, blob.ptr, blob.len); + chunk_free(&blob); + } + else + { + if (!path_absolute(token)) { - snprintf(buf, sizeof(buf), "%s%s%s", - SWANCTL_X509DIR, DIRECTORY_SEPARATOR, token); - token = buf; + if (streq(key, "certs")) + { + snprintf(buf, sizeof(buf), "%s%s%s", + SWANCTL_X509DIR, DIRECTORY_SEPARATOR, token); + token = buf; + } + else if (streq(key, "cacerts")) + { + snprintf(buf, sizeof(buf), "%s%s%s", + SWANCTL_X509CADIR, DIRECTORY_SEPARATOR, token); + token = buf; + } + else if (streq(key, "pubkeys")) + { + snprintf(buf, sizeof(buf), "%s%s%s", + SWANCTL_PUBKEYDIR, DIRECTORY_SEPARATOR, token); + token = buf; + } } - else if (streq(key, "cacerts")) + map = chunk_map(token, FALSE); + if (map) { - snprintf(buf, sizeof(buf), "%s%s%s", - SWANCTL_X509CADIR, DIRECTORY_SEPARATOR, token); - token = buf; + vici_add_list_item(req, map->ptr, map->len); + chunk_unmap(map); } - else if (streq(key, "pubkeys")) + else { - snprintf(buf, sizeof(buf), "%s%s%s", - SWANCTL_PUBKEYDIR, DIRECTORY_SEPARATOR, token); - token = buf; + fprintf(stderr, "loading %s certificate '%s' failed: %s\n", + key, token, strerror(errno)); + ret = FALSE; + break; } } - - map = chunk_map(token, FALSE); - if (map) - { - vici_add_list_item(req, map->ptr, map->len); - chunk_unmap(map); - } - else - { - fprintf(stderr, "loading %s certificate '%s' failed: %s\n", - key, token, strerror(errno)); - ret = FALSE; - break; - } } enumerator->destroy(enumerator); vici_end_list(req); diff --git a/src/swanctl/commands/load_creds.c b/src/swanctl/commands/load_creds.c index 6278f66b4..848d8512c 100644 --- a/src/swanctl/commands/load_creds.c +++ b/src/swanctl/commands/load_creds.c @@ -1,11 +1,11 @@ /* - * Copyright (C) 2014 Martin Willi - * Copyright (C) 2014 revosec AG - * * Copyright (C) 2016 Tobias Brunner * Copyright (C) 2015 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * * 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 @@ -30,15 +30,35 @@ #include <credentials/sets/mem_cred.h> #include <credentials/sets/callback_cred.h> #include <credentials/containers/pkcs12.h> +#include <collections/hashtable.h> #include <vici_cert_info.h> +#define HASH_SIZE_SHA1_HEX (2 * HASH_SIZE_SHA1) + +/** + * Context used to track loaded secrets + */ +typedef struct { + /** vici connection */ + vici_conn_t *conn; + /** format options */ + command_format_options_t format; + /** read setting */ + settings_t *cfg; + /** don't prompt user for password */ + bool noprompt; + /** list of key ids of loaded private keys */ + hashtable_t *keys; + /** list of unique ids of loaded shared keys */ + hashtable_t *shared; +} load_ctx_t; + /** * Load a single certificate over vici */ -static bool load_cert(vici_conn_t *conn, command_format_options_t format, - char *dir, certificate_type_t type, x509_flag_t flag, - chunk_t data) +static bool load_cert(load_ctx_t *ctx, char *dir, certificate_type_t type, + x509_flag_t flag, chunk_t data) { vici_req_t *req; vici_res_t *res; @@ -53,15 +73,15 @@ static bool load_cert(vici_conn_t *conn, command_format_options_t format, } vici_add_key_value(req, "data", data.ptr, data.len); - res = vici_submit(req, conn); + res = vici_submit(req, ctx->conn); if (!res) { fprintf(stderr, "load-cert request failed: %s\n", strerror(errno)); return FALSE; } - if (format & COMMAND_FORMAT_RAW) + if (ctx->format & COMMAND_FORMAT_RAW) { - vici_dump(res, "load-cert reply", format & COMMAND_FORMAT_PRETTY, + vici_dump(res, "load-cert reply", ctx->format & COMMAND_FORMAT_PRETTY, stdout); } else if (!streq(vici_find_str(res, "no", "success"), "yes")) @@ -81,8 +101,7 @@ static bool load_cert(vici_conn_t *conn, command_format_options_t format, /** * Load certficiates from a directory */ -static void load_certs(vici_conn_t *conn, command_format_options_t format, - char *type_str, char *dir) +static void load_certs(load_ctx_t *ctx, char *type_str, char *dir) { enumerator_t *enumerator; certificate_type_t type; @@ -103,7 +122,7 @@ static void load_certs(vici_conn_t *conn, command_format_options_t format, map = chunk_map(path, FALSE); if (map) { - load_cert(conn, format, path, type, flag, *map); + load_cert(ctx, path, type, flag, *map); chunk_unmap(map); } else @@ -120,8 +139,7 @@ static void load_certs(vici_conn_t *conn, command_format_options_t format, /** * Load a single private key over vici */ -static bool load_key(vici_conn_t *conn, command_format_options_t format, - char *dir, char *type, chunk_t data) +static bool load_key(load_ctx_t *ctx, char *dir, char *type, chunk_t data) { vici_req_t *req; vici_res_t *res; @@ -140,15 +158,15 @@ static bool load_key(vici_conn_t *conn, command_format_options_t format, } vici_add_key_value(req, "data", data.ptr, data.len); - res = vici_submit(req, conn); + res = vici_submit(req, ctx->conn); if (!res) { fprintf(stderr, "load-key request failed: %s\n", strerror(errno)); return FALSE; } - if (format & COMMAND_FORMAT_RAW) + if (ctx->format & COMMAND_FORMAT_RAW) { - vici_dump(res, "load-key reply", format & COMMAND_FORMAT_PRETTY, + vici_dump(res, "load-key reply", ctx->format & COMMAND_FORMAT_PRETTY, stdout); } else if (!streq(vici_find_str(res, "no", "success"), "yes")) @@ -168,11 +186,12 @@ static bool load_key(vici_conn_t *conn, command_format_options_t format, /** * Load a private key of any type to vici */ -static bool load_key_anytype(vici_conn_t *conn, command_format_options_t format, - char *path, private_key_t *private) +static bool load_key_anytype(load_ctx_t *ctx, char *path, + private_key_t *private) { bool loaded = FALSE; - chunk_t encoding; + chunk_t encoding, keyid; + char hex[HASH_SIZE_SHA1_HEX + 1]; if (!private->get_encoding(private, PRIVKEY_ASN1_DER, &encoding)) { @@ -182,18 +201,25 @@ static bool load_key_anytype(vici_conn_t *conn, command_format_options_t format, switch (private->get_type(private)) { case KEY_RSA: - loaded = load_key(conn, format, path, "rsa", encoding); + loaded = load_key(ctx, path, "rsa", encoding); break; case KEY_ECDSA: - loaded = load_key(conn, format, path, "ecdsa", encoding); + loaded = load_key(ctx, path, "ecdsa", encoding); break; case KEY_BLISS: - loaded = load_key(conn, format, path, "bliss", encoding); + loaded = load_key(ctx, path, "bliss", encoding); break; default: fprintf(stderr, "unsupported key type in '%s'\n", path); break; } + + if (loaded && + private->get_fingerprint(private, KEYID_PUBKEY_SHA1, &keyid) && + snprintf(hex, sizeof(hex), "%+B", &keyid) == HASH_SIZE_SHA1_HEX) + { + free(ctx->keys->remove(ctx->keys, hex)); + } chunk_clear(&encoding); return loaded; } @@ -312,7 +338,7 @@ static void* decrypt(char *name, char *type, chunk_t encoding) /** * Try to parse a potentially encrypted credential using configured secret */ -static void* decrypt_with_config(settings_t *cfg, char *name, char *type, +static void* decrypt_with_config(load_ctx_t *ctx, char *name, char *type, chunk_t encoding) { credential_type_t credtype; @@ -329,16 +355,16 @@ static void* decrypt_with_config(settings_t *cfg, char *name, char *type, } /* load all secrets for this key type */ - enumerator = cfg->create_section_enumerator(cfg, "secrets"); + enumerator = ctx->cfg->create_section_enumerator(ctx->cfg, "secrets"); while (enumerator->enumerate(enumerator, §ion)) { if (strpfx(section, type)) { - file = cfg->get_str(cfg, "secrets.%s.file", NULL, section); + file = ctx->cfg->get_str(ctx->cfg, "secrets.%s.file", NULL, section); if (file && strcaseeq(file, name)) { snprintf(buf, sizeof(buf), "secrets.%s", section); - secrets = cfg->create_key_value_enumerator(cfg, buf); + secrets = ctx->cfg->create_key_value_enumerator(ctx->cfg, buf); while (secrets->enumerate(secrets, &key, &value)) { if (strpfx(key, "secret")) @@ -382,22 +408,20 @@ static void* decrypt_with_config(settings_t *cfg, char *name, char *type, /** * Try to decrypt and load a private key */ -static bool load_encrypted_key(vici_conn_t *conn, - command_format_options_t format, settings_t *cfg, - char *rel, char *path, char *type, bool noprompt, - chunk_t data) +static bool load_encrypted_key(load_ctx_t *ctx, char *rel, char *path, + char *type, chunk_t data) { private_key_t *private; bool loaded = FALSE; - private = decrypt_with_config(cfg, rel, type, data); - if (!private && !noprompt) + private = decrypt_with_config(ctx, rel, type, data); + if (!private && !ctx->noprompt) { private = decrypt(rel, type, data); } if (private) { - loaded = load_key_anytype(conn, format, path, private); + loaded = load_key_anytype(ctx, path, private); private->destroy(private); } return loaded; @@ -406,8 +430,7 @@ static bool load_encrypted_key(vici_conn_t *conn, /** * Load private keys from a directory */ -static void load_keys(vici_conn_t *conn, command_format_options_t format, - bool noprompt, settings_t *cfg, char *type, char *dir) +static void load_keys(load_ctx_t *ctx, char *type, char *dir) { enumerator_t *enumerator; struct stat st; @@ -424,10 +447,9 @@ static void load_keys(vici_conn_t *conn, command_format_options_t format, map = chunk_map(path, FALSE); if (map) { - if (!load_encrypted_key(conn, format, cfg, rel, path, type, - noprompt, *map)) + if (!load_encrypted_key(ctx, rel, path, type, *map)) { - load_key(conn, format, path, type, *map); + load_key(ctx, path, type, *map); } chunk_unmap(map); } @@ -445,8 +467,7 @@ static void load_keys(vici_conn_t *conn, command_format_options_t format, /** * Load credentials from a PKCS#12 container over vici */ -static bool load_pkcs12(vici_conn_t *conn, command_format_options_t format, - char *path, pkcs12_t *p12) +static bool load_pkcs12(load_ctx_t *ctx, char *path, pkcs12_t *p12) { enumerator_t *enumerator; certificate_t *cert; @@ -460,8 +481,7 @@ static bool load_pkcs12(vici_conn_t *conn, command_format_options_t format, loaded = FALSE; if (cert->get_encoding(cert, CERT_ASN1_DER, &encoding)) { - loaded = load_cert(conn, format, path, CERT_X509, X509_NONE, - encoding); + loaded = load_cert(ctx, path, CERT_X509, X509_NONE, encoding); if (loaded) { fprintf(stderr, " %Y\n", cert->get_subject(cert)); @@ -478,7 +498,7 @@ static bool load_pkcs12(vici_conn_t *conn, command_format_options_t format, enumerator = p12->create_key_enumerator(p12); while (loaded && enumerator->enumerate(enumerator, &private)) { - loaded = load_key_anytype(conn, format, path, private); + loaded = load_key_anytype(ctx, path, private); } enumerator->destroy(enumerator); @@ -488,15 +508,14 @@ static bool load_pkcs12(vici_conn_t *conn, command_format_options_t format, /** * Try to decrypt and load credentials from a container */ -static bool load_encrypted_container(vici_conn_t *conn, - command_format_options_t format, settings_t *cfg, char *rel, - char *path, char *type, bool noprompt, chunk_t data) +static bool load_encrypted_container(load_ctx_t *ctx, char *rel, char *path, + char *type, chunk_t data) { container_t *container; bool loaded = FALSE; - container = decrypt_with_config(cfg, rel, type, data); - if (!container && !noprompt) + container = decrypt_with_config(ctx, rel, type, data); + if (!container && !ctx->noprompt) { container = decrypt(rel, type, data); } @@ -505,7 +524,7 @@ static bool load_encrypted_container(vici_conn_t *conn, switch (container->get_type(container)) { case CONTAINER_PKCS12: - loaded = load_pkcs12(conn, format, path, (pkcs12_t*)container); + loaded = load_pkcs12(ctx, path, (pkcs12_t*)container); break; default: break; @@ -518,8 +537,7 @@ static bool load_encrypted_container(vici_conn_t *conn, /** * Load credential containers from a directory */ -static void load_containers(vici_conn_t *conn, command_format_options_t format, - bool noprompt, settings_t *cfg, char *type, char *dir) +static void load_containers(load_ctx_t *ctx, char *type, char *dir) { enumerator_t *enumerator; struct stat st; @@ -536,8 +554,7 @@ static void load_containers(vici_conn_t *conn, command_format_options_t format, map = chunk_map(path, FALSE); if (map) { - load_encrypted_container(conn, format, cfg, rel, path, - type, noprompt, *map); + load_encrypted_container(ctx, rel, path, type, *map); chunk_unmap(map); } else @@ -552,10 +569,96 @@ static void load_containers(vici_conn_t *conn, command_format_options_t format, } /** + * Load a single private key on a token over vici + */ +static bool load_token(load_ctx_t *ctx, char *name, char *pin) +{ + vici_req_t *req; + vici_res_t *res; + enumerator_t *enumerator; + char *key, *value, *id; + bool ret = TRUE; + + req = vici_begin("load-token"); + + enumerator = ctx->cfg->create_key_value_enumerator(ctx->cfg, "secrets.%s", + name); + while (enumerator->enumerate(enumerator, &key, &value)) + { + vici_add_key_valuef(req, key, "%s", value); + } + enumerator->destroy(enumerator); + + if (pin) + { + vici_add_key_valuef(req, "pin", "%s", pin); + } + res = vici_submit(req, ctx->conn); + if (!res) + { + fprintf(stderr, "load-token request failed: %s\n", strerror(errno)); + return FALSE; + } + if (ctx->format & COMMAND_FORMAT_RAW) + { + vici_dump(res, "load-token reply", ctx->format & COMMAND_FORMAT_PRETTY, + stdout); + } + else if (!streq(vici_find_str(res, "no", "success"), "yes")) + { + fprintf(stderr, "loading '%s' failed: %s\n", + name, vici_find_str(res, "", "errmsg")); + ret = FALSE; + } + else + { + id = vici_find_str(res, "", "id"); + printf("loaded key %s from token [keyid: %s]\n", name, id); + free(ctx->keys->remove(ctx->keys, id)); + } + vici_free_res(res); + return ret; +} + +/** + * Load keys from tokens + */ +static void load_tokens(load_ctx_t *ctx) +{ + enumerator_t *enumerator; + char *section, *pin = NULL, prompt[128]; + + enumerator = ctx->cfg->create_section_enumerator(ctx->cfg, "secrets"); + while (enumerator->enumerate(enumerator, §ion)) + { + if (strpfx(section, "token")) + { + if (!ctx->noprompt && + !ctx->cfg->get_str(ctx->cfg, "secrets.%s.pin", NULL, section)) + { +#ifdef HAVE_GETPASS + snprintf(prompt, sizeof(prompt), "PIN for %s: ", section); + pin = strdupnull(getpass(prompt)); +#endif + } + load_token(ctx, section, pin); + if (pin) + { + memwipe(pin, strlen(pin)); + free(pin); + pin = NULL; + } + } + } + enumerator->destroy(enumerator); +} + + + +/** * Load a single secret over VICI */ -static bool load_secret(vici_conn_t *conn, settings_t *cfg, - char *section, command_format_options_t format) +static bool load_secret(load_ctx_t *ctx, char *section) { enumerator_t *enumerator; vici_req_t *req; @@ -567,6 +670,7 @@ static bool load_secret(vici_conn_t *conn, settings_t *cfg, char *types[] = { "eap", "xauth", + "ntlm", "ike", "private", "rsa", @@ -574,6 +678,7 @@ static bool load_secret(vici_conn_t *conn, settings_t *cfg, "bliss", "pkcs8", "pkcs12", + "token", }; for (i = 0; i < countof(types); i++) @@ -589,12 +694,13 @@ static bool load_secret(vici_conn_t *conn, settings_t *cfg, fprintf(stderr, "ignoring unsupported secret '%s'\n", section); return FALSE; } - if (!streq(type, "eap") && !streq(type, "xauth") && !streq(type, "ike")) + if (!streq(type, "eap") && !streq(type, "xauth") && !streq(type, "ntlm") && + !streq(type, "ike")) { /* skip non-shared secrets */ return TRUE; } - value = cfg->get_str(cfg, "secrets.%s.secret", NULL, section); + value = ctx->cfg->get_str(ctx->cfg, "secrets.%s.secret", NULL, section); if (!value) { fprintf(stderr, "missing secret in '%s', ignored\n", section); @@ -615,13 +721,14 @@ static bool load_secret(vici_conn_t *conn, settings_t *cfg, req = vici_begin("load-shared"); + vici_add_key_valuef(req, "id", "%s", section); vici_add_key_valuef(req, "type", "%s", type); vici_add_key_value(req, "data", data.ptr, data.len); chunk_clear(&data); vici_begin_list(req, "owners"); snprintf(buf, sizeof(buf), "secrets.%s", section); - enumerator = cfg->create_key_value_enumerator(cfg, buf); + enumerator = ctx->cfg->create_key_value_enumerator(ctx->cfg, buf); while (enumerator->enumerate(enumerator, &key, &value)) { if (strpfx(key, "id")) @@ -632,15 +739,15 @@ static bool load_secret(vici_conn_t *conn, settings_t *cfg, enumerator->destroy(enumerator); vici_end_list(req); - res = vici_submit(req, conn); + res = vici_submit(req, ctx->conn); if (!res) { fprintf(stderr, "load-shared request failed: %s\n", strerror(errno)); return FALSE; } - if (format & COMMAND_FORMAT_RAW) + if (ctx->format & COMMAND_FORMAT_RAW) { - vici_dump(res, "load-shared reply", format & COMMAND_FORMAT_PRETTY, + vici_dump(res, "load-shared reply", ctx->format & COMMAND_FORMAT_PRETTY, stdout); } else if (!streq(vici_find_str(res, "no", "success"), "yes")) @@ -653,10 +760,111 @@ static bool load_secret(vici_conn_t *conn, settings_t *cfg, { printf("loaded %s secret '%s'\n", type, section); } + if (ret) + { + free(ctx->shared->remove(ctx->shared, section)); + } vici_free_res(res); return ret; } +CALLBACK(get_id, int, + hashtable_t *ht, vici_res_t *res, char *name, void *value, int len) +{ + if (streq(name, "keys")) + { + char *str; + + if (asprintf(&str, "%.*s", len, value) != -1) + { + free(ht->put(ht, str, str)); + } + } + return 0; +} + +/** + * Get a list of currently loaded private and shared keys + */ +static void get_creds(load_ctx_t *ctx) +{ + vici_res_t *res; + + res = vici_submit(vici_begin("get-keys"), ctx->conn); + if (res) + { + if (ctx->format & COMMAND_FORMAT_RAW) + { + vici_dump(res, "get-keys reply", ctx->format & COMMAND_FORMAT_PRETTY, + stdout); + } + vici_parse_cb(res, NULL, NULL, get_id, ctx->keys); + vici_free_res(res); + } + res = vici_submit(vici_begin("get-shared"), ctx->conn); + if (res) + { + if (ctx->format & COMMAND_FORMAT_RAW) + { + vici_dump(res, "get-shared reply", ctx->format & COMMAND_FORMAT_PRETTY, + stdout); + } + vici_parse_cb(res, NULL, NULL, get_id, ctx->shared); + vici_free_res(res); + } +} + +/** + * Remove a given key + */ +static bool unload_key(load_ctx_t *ctx, char *command, char *id) +{ + vici_req_t *req; + vici_res_t *res; + char buf[BUF_LEN]; + bool ret = TRUE; + + req = vici_begin(command); + + vici_add_key_valuef(req, "id", "%s", id); + + res = vici_submit(req, ctx->conn); + if (!res) + { + fprintf(stderr, "%s request failed: %s\n", command, strerror(errno)); + return FALSE; + } + if (ctx->format & COMMAND_FORMAT_RAW) + { + snprintf(buf, sizeof(buf), "%s reply", command); + vici_dump(res, buf, ctx->format & COMMAND_FORMAT_PRETTY, stdout); + } + else if (!streq(vici_find_str(res, "no", "success"), "yes")) + { + fprintf(stderr, "unloading key '%s' failed: %s\n", + id, vici_find_str(res, "", "errmsg")); + ret = FALSE; + } + vici_free_res(res); + return ret; +} + +/** + * Remove all keys in the given hashtable using the given command + */ +static void unload_keys(load_ctx_t *ctx, hashtable_t *ht, char *command) +{ + enumerator_t *enumerator; + char *id; + + enumerator = ht->create_enumerator(ht); + while (enumerator->enumerate(enumerator, &id, NULL)) + { + unload_key(ctx, command, id); + } + enumerator->destroy(enumerator); +} + /** * Clear all currently loaded credentials */ @@ -687,6 +895,14 @@ int load_creds_cfg(vici_conn_t *conn, command_format_options_t format, { enumerator_t *enumerator; char *section; + load_ctx_t ctx = { + .conn = conn, + .format = format, + .noprompt = noprompt, + .cfg = cfg, + .keys = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8), + .shared = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8), + }; if (clear) { @@ -696,29 +912,38 @@ int load_creds_cfg(vici_conn_t *conn, command_format_options_t format, } } - load_certs(conn, format, "x509", SWANCTL_X509DIR); - load_certs(conn, format, "x509ca", SWANCTL_X509CADIR); - load_certs(conn, format, "x509ocsp", SWANCTL_X509OCSPDIR); - load_certs(conn, format, "x509aa", SWANCTL_X509AADIR); - load_certs(conn, format, "x509ac", SWANCTL_X509ACDIR); - load_certs(conn, format, "x509crl", SWANCTL_X509CRLDIR); - load_certs(conn, format, "pubkey", SWANCTL_PUBKEYDIR); + get_creds(&ctx); + + load_certs(&ctx, "x509", SWANCTL_X509DIR); + load_certs(&ctx, "x509ca", SWANCTL_X509CADIR); + load_certs(&ctx, "x509ocsp", SWANCTL_X509OCSPDIR); + load_certs(&ctx, "x509aa", SWANCTL_X509AADIR); + load_certs(&ctx, "x509ac", SWANCTL_X509ACDIR); + load_certs(&ctx, "x509crl", SWANCTL_X509CRLDIR); + load_certs(&ctx, "pubkey", SWANCTL_PUBKEYDIR); - load_keys(conn, format, noprompt, cfg, "private", SWANCTL_PRIVATEDIR); - load_keys(conn, format, noprompt, cfg, "rsa", SWANCTL_RSADIR); - load_keys(conn, format, noprompt, cfg, "ecdsa", SWANCTL_ECDSADIR); - load_keys(conn, format, noprompt, cfg, "bliss", SWANCTL_BLISSDIR); - load_keys(conn, format, noprompt, cfg, "pkcs8", SWANCTL_PKCS8DIR); + load_keys(&ctx, "private", SWANCTL_PRIVATEDIR); + load_keys(&ctx, "rsa", SWANCTL_RSADIR); + load_keys(&ctx, "ecdsa", SWANCTL_ECDSADIR); + load_keys(&ctx, "bliss", SWANCTL_BLISSDIR); + load_keys(&ctx, "pkcs8", SWANCTL_PKCS8DIR); - load_containers(conn, format, noprompt, cfg, "pkcs12", SWANCTL_PKCS12DIR); + load_containers(&ctx, "pkcs12", SWANCTL_PKCS12DIR); + + load_tokens(&ctx); enumerator = cfg->create_section_enumerator(cfg, "secrets"); while (enumerator->enumerate(enumerator, §ion)) { - load_secret(conn, cfg, section, format); + load_secret(&ctx, section); } enumerator->destroy(enumerator); + unload_keys(&ctx, ctx.keys, "unload-key"); + unload_keys(&ctx, ctx.shared, "unload-shared"); + + ctx.keys->destroy_function(ctx.keys, (void*)free); + ctx.shared->destroy_function(ctx.shared, (void*)free); return 0; } diff --git a/src/swanctl/commands/rekey.c b/src/swanctl/commands/rekey.c new file mode 100644 index 000000000..47a313657 --- /dev/null +++ b/src/swanctl/commands/rekey.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2017 Tobias Brunner + * 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" + +#include <errno.h> + +static int rekey(vici_conn_t *conn) +{ + vici_req_t *req; + vici_res_t *res; + command_format_options_t format = COMMAND_FORMAT_NONE; + char *arg, *child = NULL, *ike = NULL; + int ret = 0, child_id = 0, ike_id = 0; + + 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 'c': + child = arg; + continue; + case 'i': + ike = arg; + continue; + case 'C': + child_id = atoi(arg); + continue; + case 'I': + ike_id = atoi(arg); + continue; + case EOF: + break; + default: + return command_usage("invalid --rekey option"); + } + break; + } + + req = vici_begin("rekey"); + if (child) + { + vici_add_key_valuef(req, "child", "%s", child); + } + if (ike) + { + vici_add_key_valuef(req, "ike", "%s", ike); + } + if (child_id) + { + vici_add_key_valuef(req, "child-id", "%d", child_id); + } + if (ike_id) + { + vici_add_key_valuef(req, "ike-id", "%d", ike_id); + } + res = vici_submit(req, conn); + if (!res) + { + ret = errno; + fprintf(stderr, "rekey request failed: %s\n", strerror(errno)); + return ret; + } + if (format & COMMAND_FORMAT_RAW) + { + vici_dump(res, "rekey reply", format & COMMAND_FORMAT_PRETTY, + stdout); + } + else + { + if (streq(vici_find_str(res, "no", "success"), "yes")) + { + printf("rekey completed successfully\n"); + } + else + { + fprintf(stderr, "rekey failed: %s\n", + vici_find_str(res, "", "errmsg")); + ret = 1; + } + } + vici_free_res(res); + return ret; +} + +/** + * Register the command. + */ +static void __attribute__ ((constructor))reg() +{ + command_register((command_t) { + rekey, 'R', "rekey", "rekey an SA", + {"--child <name> | --ike <name | --child-id <id> | --ike-id <id>", + "[--raw|--pretty]"}, + { + {"help", 'h', 0, "show usage information"}, + {"child", 'c', 1, "rekey by CHILD_SA name"}, + {"ike", 'i', 1, "rekey by IKE_SA name"}, + {"child-id", 'C', 1, "rekey by CHILD_SA unique identifier"}, + {"ike-id", 'I', 1, "rekey by IKE_SA unique identifier"}, + {"raw", 'r', 0, "dump raw response message"}, + {"pretty", 'P', 0, "dump raw response message in pretty print"}, + } + }); +} diff --git a/src/swanctl/swanctl.8.in b/src/swanctl/swanctl.8.in index 9c5a5a03d..391fe486f 100644 --- a/src/swanctl/swanctl.8.in +++ b/src/swanctl/swanctl.8.in @@ -40,6 +40,9 @@ initiate a connection .B "\-t, \-\-terminate" terminate a connection .TP +.B "\-R, \-\-rekey" +rekey an SA +.TP .B "\-d, \-\-redirect" redirect an IKE_SA .TP diff --git a/src/swanctl/swanctl.conf b/src/swanctl/swanctl.conf index eb46005e1..789b128fd 100644 --- a/src/swanctl/swanctl.conf +++ b/src/swanctl/swanctl.conf @@ -31,6 +31,10 @@ # Set the Mode Config mode to use. # pull = yes + # Differentiated Services Field Codepoint to set on outgoing IKE packets + # (six binary digits). + # dscp = 000000 + # Enforce UDP encapsulation by faking NAT-D payloads. # encap = no @@ -73,6 +77,15 @@ # Comma separated list of named IP pools. # pools = + # Whether this connection is a mediation connection. + # mediation = no + + # The name of the connection to mediate this connection through. + # mediated_by = + + # Identity under which the peer is registered at the mediation server. + # mediation_peer = + # Section for a local authentication round. # local<suffix> { @@ -85,6 +98,9 @@ # authentication. # certs = + # Section for a certificate candidate to use for authentication. + # cert<suffix> = + # Comma separated list of raw public key candidates to use for # authentication. # pubkeys = @@ -106,6 +122,22 @@ # Client XAuth username used in the XAuth exchange. # xauth_id = id + # cert<suffix> { + + # Absolute path to the certificate to load. + # file = + + # Hex-encoded CKA_ID of the certificate on a token. + # handle = + + # Optional slot number of the token that stores the certificate. + # slot = + + # Optional PKCS#11 module name. + # module = + + # } + # } # Section for a remote authentication round. @@ -122,13 +154,22 @@ # Authorization group memberships to require. # groups = + # Certificate policy OIDs the peer's certificate must have. + # cert_policy = + # Comma separated list of certificate to accept for authentication. # certs = + # Section for a certificate to accept for authentication. + # cert<suffix> = + # Comma separated list of CA certificates to accept for # authentication. # cacerts = + # Section for a CA certificate to accept for authentication. + # cacert<suffix> = + # Comma separated list of raw public keys to accept for # authentication. # pubkeys = @@ -140,6 +181,39 @@ # or eap[-method]). # auth = pubkey + # cert<suffix> { + + # Absolute path to the certificate to load. + # file = + + # Hex-encoded CKA_ID of the certificate on a token. + # handle = + + # Optional slot number of the token that stores the certificate. + # slot = + + # Optional PKCS#11 module name. + # module = + + # } + + # cacert<suffix> { + + # Absolute path to the certificate to load. + # file = + + # Hex-encoded CKA_ID of the CA certificate on a token. + # handle = + + # Optional slot number of the token that stores the CA + # certificate. + # slot = + + # Optional PKCS#11 module name. + # module = + + # } + # } # children { @@ -194,8 +268,8 @@ # Hostaccess variable to pass to updown script. # hostaccess = yes - # IPsec Mode to establish (tunnel, transport, beet, pass or - # drop). + # IPsec Mode to establish (tunnel, transport, transport_proxy, + # beet, pass or drop). # mode = tunnel # Whether to install IPsec policies or not. @@ -270,6 +344,17 @@ # } + # NTLM secret section for a specific secret. + # ntlm<suffix> { + + # Value of the NTLM secret. + # secret = + + # Identity the NTLM secret belongs to. + # id<suffix> = + + # } + # IKE preshared secret section for a specific secret. # ike<suffix> { @@ -340,6 +425,24 @@ # } + # Definition for a private key that's stored on a token/smartcard. + # token<suffix> { + + # Hex-encoded CKA_ID of the private key on the token. + # handle = + + # Optional slot number to access the token. + # slot = + + # Optional PKCS#11 module name to access the token. + # module = + + # Optional PIN required to access the key on the token. If none is + # provided the user is prompted during an interactive --load-creds call. + # pin = + + # } + # } # Section defining named pools. @@ -367,10 +470,22 @@ # CA certificate belonging to the certification authority. # cacert = - # Comma-separated list of CRL distribution points + # Absolute path to the certificate to load. + # file = + + # Hex-encoded CKA_ID of the CA certificate on a token. + # handle = + + # Optional slot number of the token that stores the CA certificate. + # slot = + + # Optional PKCS#11 module name. + # module = + + # Comma-separated list of CRL distribution points. # crl_uris = - # Comma-separated list of OCSP URIs + # Comma-separated list of OCSP URIs. # ocsp_uris = # Defines the base URI for the Hash and URL feature supported by IKEv2. diff --git a/src/swanctl/swanctl.conf.5.head.in b/src/swanctl/swanctl.conf.5.head.in index 84f734eb9..5742d2593 100644 --- a/src/swanctl/swanctl.conf.5.head.in +++ b/src/swanctl/swanctl.conf.5.head.in @@ -6,7 +6,8 @@ swanctl.conf is the configuration file used by the .BR swanctl (8) tool to load configurations and credentials into the strongSwan IKE daemon. -For a description of the basic file syntax refer to +For a description of the basic file syntax, including how to split the +configuration in multiple files by including other files, refer to .BR strongswan.conf (5). .SH TIME FORMATS diff --git a/src/swanctl/swanctl.conf.5.main b/src/swanctl/swanctl.conf.5.main index 697bd406a..6e1e9adfb 100644 --- a/src/swanctl/swanctl.conf.5.main +++ b/src/swanctl/swanctl.conf.5.main @@ -35,6 +35,9 @@ As initiator, the first non\-range/non\-subnet is used to initiate the connectio from. As responder, the local destination address must match at least to one of the specified addresses, subnets or ranges. +If FQDNs are assigned they are resolved every time a configuration lookup is +done. If DNS resolution times out, the lookup is delayed for that time. + .TP .BR connections.<conn>.remote_addrs " [%any]" Remote address(es) to use for IKE communication, comma separated. Takes single @@ -44,6 +47,9 @@ As initiator, the first non\-range/non\-subnet is used to initiate the connectio to. As responder, the initiator source address must match at least to one of the specified addresses, subnets or ranges. +If FQDNs are assigned they are resolved every time a configuration lookup is +done. If DNS resolution times out, the lookup is delayed for that time. + To initiate a connection, at least one specific address or DNS name must be specified. @@ -118,6 +124,12 @@ Push mode is currently supported for IKEv1, but not in IKEv2. It is used by a few implementations only, pull mode is recommended. .TP +.BR connections.<conn>.dscp " [000000]" +Differentiated Services Field Codepoint to set on outgoing IKE packets for this +connection. The value is a six digit binary encoded string specifying the +Codepoint to set, as defined in RFC 2474. + +.TP .BR connections.<conn>.encap " [no]" To enforce UDP encapsulation of ESP packets, the IKE daemon can fake the NAT detection payloads. This makes the peer believe that NAT takes place on the @@ -303,6 +315,30 @@ either the section or an external pool. .TP +.BR connections.<conn>.mediation " [no]" +Whether this connection is a mediation connection, that is, whether this +connection is used to mediate other connections using the IKEv2 Mediation +Extension. Mediation connections create no CHILD_SA. + +.TP +.BR connections.<conn>.mediated_by " []" +The name of the connection to mediate this connection through. If given, the +connection will be mediated through the named mediation connection. The +mediation connection must have +.RB "" "mediation" "" +enabled. + +.TP +.BR connections.<conn>.mediation_peer " []" +Identity under which the peer is registered at the mediation server, that is, +the IKE identity the other end of this connection uses as its local identity on +its connection to the mediation server. This is the identity we request the +mediation server to mediate us with. Only relevant on connections that set +.RB "" "mediated_by" "." +If it is not given, the remote IKE identity of the first +authentication round of this connection will be used. + +.TP .B connections.<conn>.local<suffix> .br Section for a local authentication round. A local authentication round defines @@ -334,6 +370,37 @@ certificate request payloads. If no appropriate CA can be located, the first certificate is used. .TP +.BR connections.<conn>.local<suffix>.cert<suffix> " []" +Section for a certificate candidate to use for authentication. Certificates in +.RI "" "certs" "" +are transmitted as binary blobs, these sections offer more flexibility. + +.TP +.BR connections.<conn>.local<suffix>.cert<suffix>.file " []" +Absolute path to the certificate to load. Passed as\-is to the daemon, so it must +be readable by it. + +Configure either this or +.RI "" "handle" "," +but not both, in one section. + +.TP +.BR connections.<conn>.local<suffix>.cert<suffix>.handle " []" +Hex\-encoded CKA_ID of the certificate on a token. + +Configure either this or +.RI "" "file" "," +but not both, in one section. + +.TP +.BR connections.<conn>.local<suffix>.cert<suffix>.slot " []" +Optional slot number of the token that stores the certificate. + +.TP +.BR connections.<conn>.local<suffix>.cert<suffix>.module " []" +Optional PKCS#11 module name. + +.TP .BR connections.<conn>.local<suffix>.pubkeys " []" Comma separated list of raw public key candidates to use for authentication. The public keys may use a relative path from the @@ -498,6 +565,11 @@ certified by different means, for example by appropriate Attribute Certificates or by an AAA backend involved in the authentication. .TP +.BR connections.<conn>.remote<suffix>.cert_policy " []" +Comma separated list of certificate policy OIDs the peer's certificate must +have. OIDs are specified using the numerical dotted representation. + +.TP .BR connections.<conn>.remote<suffix>.certs " []" Comma separated list of certificates to accept for authentication. The certificates may use a relative path from the @@ -507,6 +579,37 @@ directory or an absolute path. .TP +.BR connections.<conn>.remote<suffix>.cert<suffix> " []" +Section for a certificate to accept for authentication. Certificates in +.RI "" "certs" "" +are transmitted as binary blobs, these sections offer more flexibility. + +.TP +.BR connections.<conn>.remote<suffix>.cert<suffix>.file " []" +Absolute path to the certificate to load. Passed as\-is to the daemon, so it must +be readable by it. + +Configure either this or +.RI "" "handle" "," +but not both, in one section. + +.TP +.BR connections.<conn>.remote<suffix>.cert<suffix>.handle " []" +Hex\-encoded CKA_ID of the certificate on a token. + +Configure either this or +.RI "" "file" "," +but not both, in one section. + +.TP +.BR connections.<conn>.remote<suffix>.cert<suffix>.slot " []" +Optional slot number of the token that stores the certificate. + +.TP +.BR connections.<conn>.remote<suffix>.cert<suffix>.module " []" +Optional PKCS#11 module name. + +.TP .BR connections.<conn>.remote<suffix>.cacerts " []" Comma separated list of CA certificates to accept for authentication. The certificates may use a relative path from the @@ -516,6 +619,38 @@ directory or an absolute path. .TP +.BR connections.<conn>.remote<suffix>.cacert<suffix> " []" +Section for a CA certificate to accept for authentication. Certificates in +.RI "" "cacerts" "" +are transmitted as binary blobs, these sections offer more +flexibility. + +.TP +.BR connections.<conn>.remote<suffix>.cacert<suffix>.file " []" +Absolute path to the certificate to load. Passed as\-is to the daemon, so it must +be readable by it. + +Configure either this or +.RI "" "handle" "," +but not both, in one section. + +.TP +.BR connections.<conn>.remote<suffix>.cacert<suffix>.handle " []" +Hex\-encoded CKA_ID of the CA certificate on a token. + +Configure either this or +.RI "" "file" "," +but not both, in one section. + +.TP +.BR connections.<conn>.remote<suffix>.cacert<suffix>.slot " []" +Optional slot number of the token that stores the CA certificate. + +.TP +.BR connections.<conn>.remote<suffix>.cacert<suffix>.module " []" +Optional PKCS#11 module name. + +.TP .BR connections.<conn>.remote<suffix>.pubkeys " []" Comma separated list of raw public keys to accept for authentication. The public keys may use a relative path from the @@ -673,9 +808,16 @@ for RFC 4301 OPAQUE selectors. Port ranges may be specified as well, none of the kernel backends currently support port ranges, though. -Unless the Unity extension is used, IKEv1 supports the first specified selector -only. IKEv1 uses very similar traffic selector narrowing as it is supported in -the IKEv2 protocol. +When IKEv1 is used only the first selector is interpreted, except if the Cisco +Unity extension plugin is used. This is due to a limitation of the IKEv1 +protocol, which only allows a single pair of selectors per CHILD_SA. So to +tunnel traffic matched by several pairs of selectors when using IKEv1 several +children (CHILD_SAs) have to be defined that cover the selectors. + +The IKE daemon uses traffic selector narrowing for IKEv1, the same way it is +standardized and implemented for IKEv2. However, this may lead to problems with +other implementations. To avoid that, configure identical selectors in such +scenarios. .TP .BR connections.<conn>.children.<child>.remote_ts " [dynamic]" @@ -803,10 +945,12 @@ negotiates the CHILD_SA in IPsec Tunnel Mode, whereas .RI "" "transport" "" uses IPsec Transport Mode. +.RI "" "transport_proxy" "" +signifying the special Mobile IPv6 Transport Proxy Mode. .RI "" "beet" "" -is the Bound -End to End Tunnel mixture mode, working with fixed inner addresses without the -need to include them in each packet. +is the Bound End +to End Tunnel mixture mode, working with fixed inner addresses without the need +to include them in each packet. Both .RI "" "transport" "" @@ -1011,6 +1155,33 @@ secrets under both section prefixes are used for both EAP and XAuth authentication. .TP +.B secrets.ntlm<suffix> +.br +NTLM secret section for a specific secret. Each NTLM secret is defined in a +unique section having the +.RI "" "ntlm" "" +prefix. NTLM secrets may only be used for +EAP\-MSCHAPv2 authentication. + +.TP +.BR secrets.ntlm<suffix>.secret " []" +Value of the NTLM secret, which is the NT Hash of the actual secret, that is, +MD4(UTF\-16LE(secret)). The resulting 16\-byte value may either be given as a hex +encoded string with a +.RI "" "0x" "" +prefix or as a Base64 encoded string with a +.RI "" "0s" "" +prefix. + +.TP +.BR secrets.ntlm<suffix>.id<suffix> " []" +Identity the NTLM secret belongs to. Multiple unique identities may be +specified, each having an +.RI "" "id" "" +prefix, if a secret is shared between multiple +users. + +.TP .B secrets.ike<suffix> .br IKE preshared secret section for a specific secret. Each IKE PSK is defined in a @@ -1121,6 +1292,28 @@ folder for which this passphrase should be used. Value of decryption passphrase for PKCS#12 container. .TP +.B secrets.token<suffix> +.br +Definition for a private key that's stored on a token/smartcard. + +.TP +.BR secrets.token<suffix>.handle " []" +Hex\-encoded CKA_ID of the private key on the token. + +.TP +.BR secrets.token<suffix>.slot " []" +Optional slot number to access the token. + +.TP +.BR secrets.token<suffix>.module " []" +Optional PKCS#11 module name to access the token. + +.TP +.BR secrets.token<suffix>.pin " []" +Optional PIN required to access the key on the token. If none is provided the +user is prompted during an interactive \-\-load\-creds call. + +.TP .B pools .br Section defining named pools. Named pools may be referenced by connections with @@ -1172,19 +1365,57 @@ Section defining a certification authority with a unique name. .TP .BR authorities.<name>.cacert " []" -The certificates may use a relative path from the +CA certificate belonging to the certification authority. The certificates may +use a relative path from the .RB "" "swanctl" "" .RI "" "x509ca" "" -directory -or an absolute path. +directory or an absolute path. + +Configure one of +.RI "" "cacert" "," +.RI "" "file" "," +or +.RI "" "handle" "" +per section. + +.TP +.BR authorities.<name>.file " []" +Absolute path to the certificate to load. Passed as\-is to the daemon, so it must +be readable by it. + +Configure one of +.RI "" "cacert" "," +.RI "" "file" "," +or +.RI "" "handle" "" +per section. + +.TP +.BR authorities.<name>.handle " []" +Hex\-encoded CKA_ID of the CA certificate on a token. + +Configure one of +.RI "" "cacert" "," +.RI "" "file" "," +or +.RI "" "handle" "" +per section. + +.TP +.BR authorities.<name>.slot " []" +Optional slot number of the token that stores the CA certificate. + +.TP +.BR authorities.<name>.module " []" +Optional PKCS#11 module name. .TP .BR authorities.<name>.crl_uris " []" -Comma\-separated list of CRL distribution points (ldap, http, or file URI) +Comma\-separated list of CRL distribution points (ldap, http, or file URI). .TP .BR authorities.<name>.ocsp_uris " []" -Comma\-separated list of OCSP URIs +Comma\-separated list of OCSP URIs. .TP .BR authorities.<name>.cert_uri_base " []" diff --git a/src/swanctl/swanctl.opt b/src/swanctl/swanctl.opt index a7d6d9fc3..bdd92177f 100644 --- a/src/swanctl/swanctl.opt +++ b/src/swanctl/swanctl.opt @@ -28,6 +28,9 @@ connections.<conn>.local_addrs = %any connection from. As responder, the local destination address must match at least to one of the specified addresses, subnets or ranges. + If FQDNs are assigned they are resolved every time a configuration lookup + is done. If DNS resolution times out, the lookup is delayed for that time. + connections.<conn>.remote_addrs = %any Remote address(es) to use for IKE communication, comma separated. @@ -38,6 +41,9 @@ connections.<conn>.remote_addrs = %any connection to. As responder, the initiator source address must match at least to one of the specified addresses, subnets or ranges. + If FQDNs are assigned they are resolved every time a configuration lookup + is done. If DNS resolution times out, the lookup is delayed for that time. + To initiate a connection, at least one specific address or DNS name must be specified. @@ -102,6 +108,14 @@ connections.<conn>.pull = yes Push mode is currently supported for IKEv1, but not in IKEv2. It is used by a few implementations only, pull mode is recommended. +connections.<conn>.dscp = 000000 + Differentiated Services Field Codepoint to set on outgoing IKE packets (six + binary digits). + + Differentiated Services Field Codepoint to set on outgoing IKE packets for + this connection. The value is a six digit binary encoded string specifying + the Codepoint to set, as defined in RFC 2474. + connections.<conn>.encap = no Enforce UDP encapsulation by faking NAT-D payloads. @@ -256,6 +270,30 @@ connections.<conn>.pools = other configuration attributes from. Each name references a pool by name from either the **pools** section or an external pool. +connections.<conn>.mediation = no + Whether this connection is a mediation connection. + + Whether this connection is a mediation connection, that is, whether this + connection is used to mediate other connections using the IKEv2 Mediation + Extension. Mediation connections create no CHILD_SA. + +connections.<conn>.mediated_by = + The name of the connection to mediate this connection through. + + The name of the connection to mediate this connection through. If given, the + connection will be mediated through the named mediation connection. + The mediation connection must have **mediation** enabled. + +connections.<conn>.mediation_peer = + Identity under which the peer is registered at the mediation server. + + Identity under which the peer is registered at the mediation server, that + is, the IKE identity the other end of this connection uses as its local + identity on its connection to the mediation server. This is the identity we + request the mediation server to mediate us with. Only relevant on + connections that set **mediated_by**. If it is not given, the remote IKE + identity of the first authentication round of this connection will be used. + connections.<conn>.local<suffix> {} Section for a local authentication round. @@ -284,6 +322,34 @@ connections.<conn>.local<suffix>.certs = certificate request payloads. If no appropriate CA can be located, the first certificate is used. +connections.<conn>.local<suffix>.cert<suffix> = + Section for a certificate candidate to use for authentication. + + Section for a certificate candidate to use for authentication. Certificates + in _certs_ are transmitted as binary blobs, these sections offer more + flexibility. + +connections.<conn>.local<suffix>.cert<suffix>.file = + Absolute path to the certificate to load. + + Absolute path to the certificate to load. Passed as-is to the daemon, so it + must be readable by it. + + Configure either this or _handle_, but not both, in one section. + +connections.<conn>.local<suffix>.cert<suffix>.handle = + Hex-encoded CKA_ID of the certificate on a token. + + Hex-encoded CKA_ID of the certificate on a token. + + Configure either this or _file_, but not both, in one section. + +connections.<conn>.local<suffix>.cert<suffix>.slot = + Optional slot number of the token that stores the certificate. + +connections.<conn>.local<suffix>.cert<suffix>.module = + Optional PKCS#11 module name. + connections.<conn>.local<suffix>.pubkeys = Comma separated list of raw public key candidates to use for authentication. @@ -398,6 +464,12 @@ connections.<conn>.remote<suffix>.groups = can be certified by different means, for example by appropriate Attribute Certificates or by an AAA backend involved in the authentication. +connections.<conn>.remote<suffix>.cert_policy = + Certificate policy OIDs the peer's certificate must have. + + Comma separated list of certificate policy OIDs the peer's certificate must + have. OIDs are specified using the numerical dotted representation. + connections.<conn>.remote<suffix>.certs = Comma separated list of certificate to accept for authentication. @@ -405,6 +477,34 @@ connections.<conn>.remote<suffix>.certs = The certificates may use a relative path from the **swanctl** _x509_ directory or an absolute path. +connections.<conn>.remote<suffix>.cert<suffix> = + Section for a certificate to accept for authentication. + + Section for a certificate to accept for authentication. Certificates + in _certs_ are transmitted as binary blobs, these sections offer more + flexibility. + +connections.<conn>.remote<suffix>.cert<suffix>.file = + Absolute path to the certificate to load. + + Absolute path to the certificate to load. Passed as-is to the daemon, so it + must be readable by it. + + Configure either this or _handle_, but not both, in one section. + +connections.<conn>.remote<suffix>.cert<suffix>.handle = + Hex-encoded CKA_ID of the certificate on a token. + + Hex-encoded CKA_ID of the certificate on a token. + + Configure either this or _file_, but not both, in one section. + +connections.<conn>.remote<suffix>.cert<suffix>.slot = + Optional slot number of the token that stores the certificate. + +connections.<conn>.remote<suffix>.cert<suffix>.module = + Optional PKCS#11 module name. + connections.<conn>.remote<suffix>.cacerts = Comma separated list of CA certificates to accept for authentication. @@ -412,6 +512,34 @@ connections.<conn>.remote<suffix>.cacerts = The certificates may use a relative path from the **swanctl** _x509ca_ directory or an absolute path. +connections.<conn>.remote<suffix>.cacert<suffix> = + Section for a CA certificate to accept for authentication. + + Section for a CA certificate to accept for authentication. Certificates + in _cacerts_ are transmitted as binary blobs, these sections offer more + flexibility. + +connections.<conn>.remote<suffix>.cacert<suffix>.file = + Absolute path to the certificate to load. + + Absolute path to the certificate to load. Passed as-is to the daemon, so it + must be readable by it. + + Configure either this or _handle_, but not both, in one section. + +connections.<conn>.remote<suffix>.cacert<suffix>.handle = + Hex-encoded CKA_ID of the CA certificate on a token. + + Hex-encoded CKA_ID of the CA certificate on a token. + + Configure either this or _file_, but not both, in one section. + +connections.<conn>.remote<suffix>.cacert<suffix>.slot = + Optional slot number of the token that stores the CA certificate. + +connections.<conn>.remote<suffix>.cacert<suffix>.module = + Optional PKCS#11 module name. + connections.<conn>.remote<suffix>.pubkeys = Comma separated list of raw public keys to accept for authentication. @@ -536,9 +664,16 @@ connections.<conn>.children.<child>.local_ts = dynamic value _opaque_ for RFC 4301 OPAQUE selectors. Port ranges may be specified as well, none of the kernel backends currently support port ranges, though. - Unless the Unity extension is used, IKEv1 supports the first specified - selector only. IKEv1 uses very similar traffic selector narrowing as it is - supported in the IKEv2 protocol. + When IKEv1 is used only the first selector is interpreted, except if + the Cisco Unity extension plugin is used. This is due to a limitation of the + IKEv1 protocol, which only allows a single pair of selectors per CHILD_SA. + So to tunnel traffic matched by several pairs of selectors when using IKEv1 + several children (CHILD_SAs) have to be defined that cover the selectors. + + The IKE daemon uses traffic selector narrowing for IKEv1, the same way it is + standardized and implemented for IKEv2. However, this may lead to problems + with other implementations. To avoid that, configure identical selectors in + such scenarios. connections.<conn>.children.<child>.remote_ts = dynamic Remote selectors to include in CHILD_SA. @@ -640,11 +775,13 @@ connections.<conn>.children.<child>.hostaccess = yes Hostaccess variable to pass to **updown** script. connections.<conn>.children.<child>.mode = tunnel - IPsec Mode to establish (_tunnel_, _transport_, _beet_, _pass_ or _drop_). + IPsec Mode to establish (_tunnel_, _transport_, _transport_proxy_, _beet_, + _pass_ or _drop_). IPsec Mode to establish CHILD_SA with. _tunnel_ negotiates the CHILD_SA - in IPsec Tunnel Mode, whereas _transport_ uses IPsec Transport Mode. _beet_ - is the Bound End to End Tunnel mixture mode, working with fixed inner + in IPsec Tunnel Mode, whereas _transport_ uses IPsec Transport Mode. + _transport_proxy_ signifying the special Mobile IPv6 Transport Proxy Mode. + _beet_ is the Bound End to End Tunnel mixture mode, working with fixed inner addresses without the need to include them in each packet. Both _transport_ and _beet_ modes are subject to mode negotiation; _tunnel_ @@ -815,6 +952,28 @@ secrets.eap<suffix>.id<suffix> = be specified, each having an _id_ prefix, if a secret is shared between multiple users. +secrets.ntlm<suffix> { # } + NTLM secret section for a specific secret. + + NTLM secret section for a specific secret. Each NTLM secret is defined in + a unique section having the _ntlm_ prefix. NTLM secrets may only be used for + EAP-MSCHAPv2 authentication. + +secrets.ntlm<suffix>.secret = + Value of the NTLM secret. + + Value of the NTLM secret, which is the NT Hash of the actual secret, that + is, MD4(UTF-16LE(secret)). The resulting 16-byte value may either be given + as a hex encoded string with a _0x_ prefix or as a Base64 encoded string + with a _0s_ prefix. + +secrets.ntlm<suffix>.id<suffix> = + Identity the NTLM secret belongs to. + + Identity the NTLM secret belongs to. Multiple unique identities may + be specified, each having an _id_ prefix, if a secret is shared between + multiple users. + secrets.ike<suffix> { # } IKE preshared secret section for a specific secret. @@ -880,6 +1039,22 @@ secrets.pkcs12<suffix>.file = secrets.pkcs12<suffix>.secret Value of decryption passphrase for PKCS#12 container. +secrets.token<suffix> { # } + Definition for a private key that's stored on a token/smartcard. + +secrets.token<suffix>.handle = + Hex-encoded CKA_ID of the private key on the token. + +secrets.token<suffix>.slot = + Optional slot number to access the token. + +secrets.token<suffix>.module = + Optional PKCS#11 module name to access the token. + +secrets.token<suffix>.pin = + Optional PIN required to access the key on the token. If none is provided + the user is prompted during an interactive --load-creds call. + pools { # } Section defining named pools. @@ -916,18 +1091,40 @@ authorities.<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. + CA certificate belonging to the certification authority. The certificates + may use a relative path from the **swanctl** _x509ca_ directory or an + absolute path. + + Configure one of _cacert_, _file_, or _handle_ per section. + +authorities.<name>.file = + Absolute path to the certificate to load. + + Absolute path to the certificate to load. Passed as-is to the daemon, so it + must be readable by it. + + Configure one of _cacert_, _file_, or _handle_ per section. + +authorities.<name>.handle = + Hex-encoded CKA_ID of the CA certificate on a token. + + Hex-encoded CKA_ID of the CA certificate on a token. + + Configure one of _cacert_, _file_, or _handle_ per section. + +authorities.<name>.slot = + Optional slot number of the token that stores the CA certificate. + +authorities.<name>.module = + Optional PKCS#11 module name. authorities.<name>.crl_uris = - Comma-separated list of CRL distribution points + Comma-separated list of CRL distribution points. - Comma-separated list of CRL distribution points (ldap, http, or file URI) + 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 + Comma-separated list of OCSP URIs. authorities.<name>.cert_uri_base = Defines the base URI for the Hash and URL feature supported by IKEv2. |