From 05ddd767992d68bb38c7f16ece142e8c2e9ae016 Mon Sep 17 00:00:00 2001 From: Yves-Alexis Perez Date: Sat, 1 Apr 2017 16:26:44 +0200 Subject: New upstream version 5.5.2 --- src/swanctl/Makefile.am | 1 + src/swanctl/Makefile.in | 12 +- src/swanctl/command.h | 2 +- src/swanctl/commands/initiate.c | 12 +- src/swanctl/commands/install.c | 15 +- src/swanctl/commands/list_pools.c | 14 +- src/swanctl/commands/list_sas.c | 23 +- src/swanctl/commands/load_authorities.c | 8 +- src/swanctl/commands/load_conns.c | 67 +++--- src/swanctl/commands/load_creds.c | 377 +++++++++++++++++++++++++------- src/swanctl/commands/rekey.c | 125 +++++++++++ src/swanctl/swanctl.8.in | 3 + src/swanctl/swanctl.conf | 123 ++++++++++- src/swanctl/swanctl.conf.5.head.in | 3 +- src/swanctl/swanctl.conf.5.main | 253 ++++++++++++++++++++- src/swanctl/swanctl.opt | 223 +++++++++++++++++-- 16 files changed, 1109 insertions(+), 152 deletions(-) create mode 100644 src/swanctl/commands/rekey.c (limited to 'src/swanctl') 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 [--timeout ] [--raw|--pretty]"}, + {"--child [--ike ] [--timeout ] [--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 [--raw|--pretty]"}, + {"--child [--ike ] [--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 [--raw|--pretty]"}, + {"--child [--ike ] [--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 #include #include +#include #include +#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 @@ -551,11 +568,97 @@ 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 . + * + * 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 + +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 | --ike | --ike-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 { @@ -85,6 +98,9 @@ # authentication. # certs = + # Section for a certificate candidate to use for authentication. + # cert = + # 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 { + + # 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 = + # Comma separated list of CA certificates to accept for # authentication. # cacerts = + # Section for a CA certificate to accept for authentication. + # cacert = + # Comma separated list of raw public keys to accept for # authentication. # pubkeys = @@ -140,6 +181,39 @@ # or eap[-method]). # auth = pubkey + # cert { + + # 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 { + + # 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 { + + # Value of the NTLM secret. + # secret = + + # Identity the NTLM secret belongs to. + # id = + + # } + # IKE preshared secret section for a specific secret. # ike { @@ -340,6 +425,24 @@ # } + # Definition for a private key that's stored on a token/smartcard. + # token { + + # 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..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. @@ -117,6 +123,12 @@ the responder pushes down a virtual IP to the initiating peer. 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..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..encap " [no]" To enforce UDP encapsulation of ESP packets, the IKE daemon can fake the NAT @@ -302,6 +314,30 @@ either the .RB "" "pools" "" section or an external pool. +.TP +.BR connections..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..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..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..local .br @@ -333,6 +369,37 @@ The certificate used for authentication is selected based on the received certificate request payloads. If no appropriate CA can be located, the first certificate is used. +.TP +.BR connections..local.cert " []" +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..local.cert.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..local.cert.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..local.cert.slot " []" +Optional slot number of the token that stores the certificate. + +.TP +.BR connections..local.cert.module " []" +Optional PKCS#11 module name. + .TP .BR connections..local.pubkeys " []" Comma separated list of raw public key candidates to use for authentication. The @@ -497,6 +564,11 @@ membership to at least one of the specified groups. Group membership can be certified by different means, for example by appropriate Attribute Certificates or by an AAA backend involved in the authentication. +.TP +.BR connections..remote.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..remote.certs " []" Comma separated list of certificates to accept for authentication. The @@ -506,6 +578,37 @@ certificates may use a relative path from the directory or an absolute path. +.TP +.BR connections..remote.cert " []" +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..remote.cert.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..remote.cert.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..remote.cert.slot " []" +Optional slot number of the token that stores the certificate. + +.TP +.BR connections..remote.cert.module " []" +Optional PKCS#11 module name. + .TP .BR connections..remote.cacerts " []" Comma separated list of CA certificates to accept for authentication. The @@ -515,6 +618,38 @@ certificates may use a relative path from the directory or an absolute path. +.TP +.BR connections..remote.cacert " []" +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..remote.cacert.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..remote.cacert.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..remote.cacert.slot " []" +Optional slot number of the token that stores the CA certificate. + +.TP +.BR connections..remote.cacert.module " []" +Optional PKCS#11 module name. + .TP .BR connections..remote.pubkeys " []" Comma separated list of raw public keys to accept for authentication. The public @@ -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..children..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" "" @@ -1010,6 +1154,33 @@ is just an alias for secrets under both section prefixes are used for both EAP and XAuth authentication. +.TP +.B secrets.ntlm +.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.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.id " []" +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 .br @@ -1120,6 +1291,28 @@ folder for which this passphrase should be used. .BR secrets.pkcs12.secret " []" Value of decryption passphrase for PKCS#12 container. +.TP +.B secrets.token +.br +Definition for a private key that's stored on a token/smartcard. + +.TP +.BR secrets.token.handle " []" +Hex\-encoded CKA_ID of the private key on the token. + +.TP +.BR secrets.token.slot " []" +Optional slot number to access the token. + +.TP +.BR secrets.token.module " []" +Optional PKCS#11 module name to access the token. + +.TP +.BR secrets.token.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 @@ -1172,19 +1365,57 @@ Section defining a certification authority with a unique name. .TP .BR authorities..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..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..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..slot " []" +Optional slot number of the token that stores the CA certificate. + +.TP +.BR authorities..module " []" +Optional PKCS#11 module name. .TP .BR authorities..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..ocsp_uris " []" -Comma\-separated list of OCSP URIs +Comma\-separated list of OCSP URIs. .TP .BR authorities..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..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..remote_addrs = %any Remote address(es) to use for IKE communication, comma separated. @@ -38,6 +41,9 @@ connections..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..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..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..encap = no Enforce UDP encapsulation by faking NAT-D payloads. @@ -256,6 +270,30 @@ connections..pools = other configuration attributes from. Each name references a pool by name from either the **pools** section or an external pool. +connections..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..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..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..local {} Section for a local authentication round. @@ -284,6 +322,34 @@ connections..local.certs = certificate request payloads. If no appropriate CA can be located, the first certificate is used. +connections..local.cert = + 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..local.cert.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..local.cert.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..local.cert.slot = + Optional slot number of the token that stores the certificate. + +connections..local.cert.module = + Optional PKCS#11 module name. + connections..local.pubkeys = Comma separated list of raw public key candidates to use for authentication. @@ -398,6 +464,12 @@ connections..remote.groups = can be certified by different means, for example by appropriate Attribute Certificates or by an AAA backend involved in the authentication. +connections..remote.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..remote.certs = Comma separated list of certificate to accept for authentication. @@ -405,6 +477,34 @@ connections..remote.certs = The certificates may use a relative path from the **swanctl** _x509_ directory or an absolute path. +connections..remote.cert = + 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..remote.cert.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..remote.cert.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..remote.cert.slot = + Optional slot number of the token that stores the certificate. + +connections..remote.cert.module = + Optional PKCS#11 module name. + connections..remote.cacerts = Comma separated list of CA certificates to accept for authentication. @@ -412,6 +512,34 @@ connections..remote.cacerts = The certificates may use a relative path from the **swanctl** _x509ca_ directory or an absolute path. +connections..remote.cacert = + 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..remote.cacert.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..remote.cacert.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..remote.cacert.slot = + Optional slot number of the token that stores the CA certificate. + +connections..remote.cacert.module = + Optional PKCS#11 module name. + connections..remote.pubkeys = Comma separated list of raw public keys to accept for authentication. @@ -536,9 +664,16 @@ connections..children..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..children..remote_ts = dynamic Remote selectors to include in CHILD_SA. @@ -640,11 +775,13 @@ connections..children..hostaccess = yes Hostaccess variable to pass to **updown** script. connections..children..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.id = be specified, each having an _id_ prefix, if a secret is shared between multiple users. +secrets.ntlm { # } + 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.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.id = + 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 { # } IKE preshared secret section for a specific secret. @@ -880,6 +1039,22 @@ secrets.pkcs12.file = secrets.pkcs12.secret Value of decryption passphrase for PKCS#12 container. +secrets.token { # } + Definition for a private key that's stored on a token/smartcard. + +secrets.token.handle = + Hex-encoded CKA_ID of the private key on the token. + +secrets.token.slot = + Optional slot number to access the token. + +secrets.token.module = + Optional PKCS#11 module name to access the token. + +secrets.token.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. { # } authorities..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..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..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..slot = + Optional slot number of the token that stores the CA certificate. + +authorities..module = + Optional PKCS#11 module name. authorities..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..ocsp_uris = - Comma-separated list of OCSP URIs - - Comma-separated list of OCSP URIs + Comma-separated list of OCSP URIs. authorities..cert_uri_base = Defines the base URI for the Hash and URL feature supported by IKEv2. -- cgit v1.2.3