summaryrefslogtreecommitdiff
path: root/src/swanctl
diff options
context:
space:
mode:
Diffstat (limited to 'src/swanctl')
-rw-r--r--src/swanctl/Makefile.am1
-rw-r--r--src/swanctl/Makefile.in6
-rw-r--r--src/swanctl/commands/list_conns.c5
-rw-r--r--src/swanctl/commands/list_sas.c6
-rw-r--r--src/swanctl/commands/load_conns.c47
-rw-r--r--src/swanctl/commands/load_creds.c290
-rw-r--r--src/swanctl/swanctl.conf14
-rw-r--r--src/swanctl/swanctl.conf.5.main80
-rw-r--r--src/swanctl/swanctl.h5
-rw-r--r--src/swanctl/swanctl.opt52
10 files changed, 408 insertions, 98 deletions
diff --git a/src/swanctl/Makefile.am b/src/swanctl/Makefile.am
index b84d70587..f4f9fdf7e 100644
--- a/src/swanctl/Makefile.am
+++ b/src/swanctl/Makefile.am
@@ -65,4 +65,5 @@ install-data-local: swanctl.conf
test -e "$(DESTDIR)$(swanctldir)/rsa" || $(INSTALL) -d -m 750 "$(DESTDIR)$(swanctldir)/rsa" || true
test -e "$(DESTDIR)$(swanctldir)/ecdsa" || $(INSTALL) -d -m 750 "$(DESTDIR)$(swanctldir)/ecdsa" || true
test -e "$(DESTDIR)$(swanctldir)/pkcs8" || $(INSTALL) -d -m 750 "$(DESTDIR)$(swanctldir)/pkcs8" || true
+ test -e "$(DESTDIR)$(swanctldir)/pkcs12" || $(INSTALL) -d -m 750 "$(DESTDIR)$(swanctldir)/pkcs12" || true
test -e "$(DESTDIR)$(swanctldir)/swanctl.conf" || $(INSTALL) -m 640 $(srcdir)/swanctl.conf $(DESTDIR)$(swanctldir)/swanctl.conf || true
diff --git a/src/swanctl/Makefile.in b/src/swanctl/Makefile.in
index 649e6d8ae..f981bb1f3 100644
--- a/src/swanctl/Makefile.in
+++ b/src/swanctl/Makefile.in
@@ -238,6 +238,7 @@ DLLIB = @DLLIB@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
+EASY_INSTALL = @EASY_INSTALL@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
@@ -298,10 +299,12 @@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PLUGIN_CFLAGS = @PLUGIN_CFLAGS@
PTHREADLIB = @PTHREADLIB@
PYTHON = @PYTHON@
+PYTHONEGGINSTALLDIR = @PYTHONEGGINSTALLDIR@
PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
PYTHON_PLATFORM = @PYTHON_PLATFORM@
PYTHON_PREFIX = @PYTHON_PREFIX@
PYTHON_VERSION = @PYTHON_VERSION@
+PY_TEST = @PY_TEST@
RANLIB = @RANLIB@
RTLIB = @RTLIB@
RUBY = @RUBY@
@@ -375,6 +378,8 @@ json_CFLAGS = @json_CFLAGS@
json_LIBS = @json_LIBS@
libdir = @libdir@
libexecdir = @libexecdir@
+libiptc_CFLAGS = @libiptc_CFLAGS@
+libiptc_LIBS = @libiptc_LIBS@
linux_headers = @linux_headers@
localedir = @localedir@
localstatedir = @localstatedir@
@@ -991,6 +996,7 @@ install-data-local: swanctl.conf
test -e "$(DESTDIR)$(swanctldir)/rsa" || $(INSTALL) -d -m 750 "$(DESTDIR)$(swanctldir)/rsa" || true
test -e "$(DESTDIR)$(swanctldir)/ecdsa" || $(INSTALL) -d -m 750 "$(DESTDIR)$(swanctldir)/ecdsa" || true
test -e "$(DESTDIR)$(swanctldir)/pkcs8" || $(INSTALL) -d -m 750 "$(DESTDIR)$(swanctldir)/pkcs8" || true
+ test -e "$(DESTDIR)$(swanctldir)/pkcs12" || $(INSTALL) -d -m 750 "$(DESTDIR)$(swanctldir)/pkcs12" || true
test -e "$(DESTDIR)$(swanctldir)/swanctl.conf" || $(INSTALL) -m 640 $(srcdir)/swanctl.conf $(DESTDIR)$(swanctldir)/swanctl.conf || true
# Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/src/swanctl/commands/list_conns.c b/src/swanctl/commands/list_conns.c
index 31ab9c40a..019c88888 100644
--- a/src/swanctl/commands/list_conns.c
+++ b/src/swanctl/commands/list_conns.c
@@ -103,7 +103,7 @@ CALLBACK(conn_sn, int,
{
return vici_parse_cb(res, children_sn, NULL, NULL, NULL);
}
- if (streq(name, "local") || streq(name, "remote"))
+ if (strpfx(name, "local") || strpfx(name, "remote"))
{
hashtable_t *auth;
@@ -112,7 +112,8 @@ CALLBACK(conn_sn, int,
if (ret == 0)
{
printf(" %s %s authentication:\n",
- name, auth->get(auth, "class") ?: "unspecified");
+ strpfx(name, "local") ? "local" : "remote",
+ auth->get(auth, "class") ?: "unspecified");
if (auth->get(auth, "id"))
{
printf(" id: %s\n", auth->get(auth, "id"));
diff --git a/src/swanctl/commands/list_sas.c b/src/swanctl/commands/list_sas.c
index 35e7469a9..81e1b7cca 100644
--- a/src/swanctl/commands/list_sas.c
+++ b/src/swanctl/commands/list_sas.c
@@ -86,8 +86,8 @@ CALLBACK(child_sas, int,
ret = vici_parse_cb(res, NULL, sa_values, sa_list, child);
if (ret == 0)
{
- printf(" %s: #%s, %s, %s%s, %s:",
- name, child->get(child, "reqid"),
+ 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, "encap") ? "-in-UDP" : "",
child->get(child, "protocol"));
@@ -122,7 +122,7 @@ CALLBACK(child_sas, int,
}
if (child->get(child, "esn"))
{
- printf("/%s", child->get(child, "esn"));
+ printf("/ESN");
}
printf("\n");
diff --git a/src/swanctl/commands/load_conns.c b/src/swanctl/commands/load_conns.c
index de30d8eb4..6ee8b8785 100644
--- a/src/swanctl/commands/load_conns.c
+++ b/src/swanctl/commands/load_conns.c
@@ -93,11 +93,12 @@ static void add_list_key(vici_req_t *req, char *key, char *value)
/**
* Add a vici list of blobs from a comma separated file list
*/
-static void add_file_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;
char *token, buf[PATH_MAX];
+ bool ret = TRUE;
vici_begin_list(req, key);
enumerator = enumerator_create_token(value, ",", " ");
@@ -127,21 +128,26 @@ static void add_file_list_key(vici_req_t *req, char *key, char *value)
}
else
{
- fprintf(stderr, "loading certificate '%s' failed: %s\n",
- token, strerror(errno));
+ fprintf(stderr, "loading %s certificate '%s' failed: %s\n",
+ key, token, strerror(errno));
+ ret = FALSE;
+ break;
}
}
enumerator->destroy(enumerator);
vici_end_list(req);
+
+ return ret;
}
/**
* Translate setting key/values from a section into vici key-values/lists
*/
-static void add_key_values(vici_req_t *req, settings_t *cfg, char *section)
+static bool add_key_values(vici_req_t *req, settings_t *cfg, char *section)
{
enumerator_t *enumerator;
char *key, *value;
+ bool ret = TRUE;
enumerator = cfg->create_key_value_enumerator(cfg, section);
while (enumerator->enumerate(enumerator, &key, &value))
@@ -152,34 +158,51 @@ static void add_key_values(vici_req_t *req, settings_t *cfg, char *section)
}
else if (is_file_list_key(key))
{
- add_file_list_key(req, key, value);
+ ret = add_file_list_key(req, key, value);
}
else
{
vici_add_key_valuef(req, key, "%s", value);
}
+ if (!ret)
+ {
+ break;
+ }
}
enumerator->destroy(enumerator);
+
+ return ret;
}
/**
* Translate a settings section to a vici section
*/
-static void add_sections(vici_req_t *req, settings_t *cfg, char *section)
+static bool add_sections(vici_req_t *req, settings_t *cfg, char *section)
{
enumerator_t *enumerator;
char *name, buf[256];
+ bool ret = TRUE;
enumerator = cfg->create_section_enumerator(cfg, section);
while (enumerator->enumerate(enumerator, &name))
{
vici_begin_section(req, name);
snprintf(buf, sizeof(buf), "%s.%s", section, name);
- add_key_values(req, cfg, buf);
- add_sections(req, cfg, buf);
+ ret = add_key_values(req, cfg, buf);
+ if (!ret)
+ {
+ break;
+ }
+ ret = add_sections(req, cfg, buf);
+ if (!ret)
+ {
+ break;
+ }
vici_end_section(req);
}
enumerator->destroy(enumerator);
+
+ return ret;
}
/**
@@ -198,8 +221,12 @@ static bool load_conn(vici_conn_t *conn, settings_t *cfg,
req = vici_begin("load-conn");
vici_begin_section(req, section);
- add_key_values(req, cfg, buf);
- add_sections(req, cfg, buf);
+ if (!add_key_values(req, cfg, buf) ||
+ !add_sections(req, cfg, buf))
+ {
+ vici_free_req(req);
+ return FALSE;
+ }
vici_end_section(req);
res = vici_submit(req, conn);
diff --git a/src/swanctl/commands/load_creds.c b/src/swanctl/commands/load_creds.c
index 86ee3c179..d2ebc22eb 100644
--- a/src/swanctl/commands/load_creds.c
+++ b/src/swanctl/commands/load_creds.c
@@ -25,6 +25,7 @@
#include <credentials/sets/mem_cred.h>
#include <credentials/sets/callback_cred.h>
+#include <credentials/containers/pkcs12.h>
/**
* Load a single certificate over vici
@@ -60,7 +61,7 @@ static bool load_cert(vici_conn_t *conn, command_format_options_t format,
}
else
{
- printf("loaded %s certificate '%s'\n", type, dir);
+ printf("loaded %s certificate from '%s'\n", type, dir);
}
vici_free_res(res);
return ret;
@@ -113,7 +114,14 @@ static bool load_key(vici_conn_t *conn, command_format_options_t format,
req = vici_begin("load-key");
- vici_add_key_valuef(req, "type", "%s", type);
+ if (streq(type, "pkcs8"))
+ { /* as used by vici */
+ vici_add_key_valuef(req, "type", "any");
+ }
+ else
+ {
+ vici_add_key_valuef(req, "type", "%s", type);
+ }
vici_add_key_value(req, "data", data.ptr, data.len);
res = vici_submit(req, conn);
@@ -135,20 +143,59 @@ static bool load_key(vici_conn_t *conn, command_format_options_t format,
}
else
{
- printf("loaded %s key '%s'\n", type, dir);
+ printf("loaded %s key from '%s'\n", type, dir);
}
vici_free_res(res);
return ret;
}
/**
+ * 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)
+{
+ bool loaded = FALSE;
+ chunk_t encoding;
+
+ if (!private->get_encoding(private, PRIVKEY_ASN1_DER, &encoding))
+ {
+ fprintf(stderr, "encoding private key from '%s' failed\n", path);
+ return FALSE;
+ }
+ switch (private->get_type(private))
+ {
+ case KEY_RSA:
+ loaded = load_key(conn, format, path, "rsa", encoding);
+ break;
+ case KEY_ECDSA:
+ loaded = load_key(conn, format, path, "ecdsa", encoding);
+ break;
+ default:
+ fprintf(stderr, "unsupported key type in '%s'\n", path);
+ break;
+ }
+ chunk_clear(&encoding);
+ return loaded;
+}
+
+/**
+ * Data passed to password callback
+ */
+typedef struct {
+ char prompt[128];
+ mem_cred_t *cache;
+} cb_data_t;
+
+/**
* Callback function to prompt for private key passwords
*/
CALLBACK(password_cb, shared_key_t*,
- char *prompt, shared_key_type_t type,
+ cb_data_t *data, shared_key_type_t type,
identification_t *me, identification_t *other,
id_match_t *match_me, id_match_t *match_other)
{
+ shared_key_t *shared;
char *pwd = NULL;
if (type != SHARED_PRIVATE_KEY_PASS)
@@ -156,7 +203,7 @@ CALLBACK(password_cb, shared_key_t*,
return NULL;
}
#ifdef HAVE_GETPASS
- pwd = getpass(prompt);
+ pwd = getpass(data->prompt);
#endif
if (!pwd || strlen(pwd) == 0)
{
@@ -170,65 +217,94 @@ CALLBACK(password_cb, shared_key_t*,
{
*match_other = ID_MATCH_PERFECT;
}
- return shared_key_create(type, chunk_clone(chunk_from_str(pwd)));
+ shared = shared_key_create(type, chunk_clone(chunk_from_str(pwd)));
+ /* cache secret if it is required more than once (PKCS#12) */
+ data->cache->add_shared(data->cache, shared, NULL);
+ return shared->get_ref(shared);
}
/**
- * Try to parse a potentially encrypted private key using password prompt
+ * Determine credential type and subtype from a type string
*/
-static private_key_t* decrypt_key(char *name, char *type, chunk_t encoding)
+static bool determine_credtype(char *type, credential_type_t *credtype,
+ int *subtype)
{
- key_type_t kt = KEY_ANY;
- private_key_t *private;
- callback_cred_t *cb;
- char buf[128];
+ struct {
+ char *type;
+ credential_type_t credtype;
+ int subtype;
+ } map[] = {
+ { "pkcs8", CRED_PRIVATE_KEY, KEY_ANY, },
+ { "rsa", CRED_PRIVATE_KEY, KEY_RSA, },
+ { "ecdsa", CRED_PRIVATE_KEY, KEY_ECDSA, },
+ { "pkcs12", CRED_CONTAINER, CONTAINER_PKCS12, },
+ };
+ int i;
- if (streq(type, "rsa"))
+ for (i = 0; i < countof(map); i++)
{
- kt = KEY_RSA;
+ if (streq(map[i].type, type))
+ {
+ *credtype = map[i].credtype;
+ *subtype = map[i].subtype;
+ return TRUE;
+ }
}
- else if (streq(type, "ecdsa"))
+ return FALSE;
+}
+
+/**
+ * Try to parse a potentially encrypted credential using password prompt
+ */
+static void* decrypt(char *name, char *type, chunk_t encoding)
+{
+ credential_type_t credtype;
+ int subtype;
+ void *cred;
+ callback_cred_t *cb;
+ cb_data_t data;
+
+ if (!determine_credtype(type, &credtype, &subtype))
{
- kt = KEY_ECDSA;
+ return NULL;
}
- snprintf(buf, sizeof(buf), "Password for '%s': ", name);
+ snprintf(data.prompt, sizeof(data.prompt), "Password for %s file '%s': ",
+ type, name);
- cb = callback_cred_create_shared(password_cb, buf);
+ data.cache = mem_cred_create();
+ lib->credmgr->add_set(lib->credmgr, &data.cache->set);
+ cb = callback_cred_create_shared(password_cb, &data);
lib->credmgr->add_set(lib->credmgr, &cb->set);
- private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, kt,
- BUILD_BLOB_PEM, encoding, BUILD_END);
+ cred = lib->creds->create(lib->creds, credtype, subtype,
+ BUILD_BLOB_PEM, encoding, BUILD_END);
+ lib->credmgr->remove_set(lib->credmgr, &data.cache->set);
+ data.cache->destroy(data.cache);
lib->credmgr->remove_set(lib->credmgr, &cb->set);
cb->destroy(cb);
- return private;
+ return cred;
}
/**
- * Try to parse a potentially encrypted private key using configured secret
+ * Try to parse a potentially encrypted credential using configured secret
*/
-static private_key_t* decrypt_key_with_config(settings_t *cfg, char *name,
- char *type, chunk_t encoding)
-{ key_type_t kt = KEY_ANY;
+static void* decrypt_with_config(settings_t *cfg, char *name, char *type,
+ chunk_t encoding)
+{
+ credential_type_t credtype;
+ int subtype;
enumerator_t *enumerator, *secrets;
char *section, *key, *value, *file, buf[128];
shared_key_t *shared;
- private_key_t *private = NULL;
+ void *cred = NULL;
mem_cred_t *mem = NULL;
- if (streq(type, "rsa"))
- {
- kt = KEY_RSA;
- }
- else if (streq(type, "ecdsa"))
- {
- kt = KEY_ECDSA;
- }
- else
+ if (!determine_credtype(type, &credtype, &subtype))
{
- type = "pkcs8";
+ return NULL;
}
/* load all secrets for this key type */
@@ -265,12 +341,12 @@ static private_key_t* decrypt_key_with_config(settings_t *cfg, char *name,
{
lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
- private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, kt,
- BUILD_BLOB_PEM, encoding, BUILD_END);
+ cred = lib->creds->create(lib->creds, credtype, subtype,
+ BUILD_BLOB_PEM, encoding, BUILD_END);
lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
- if (!private)
+ if (!cred)
{
fprintf(stderr, "configured decryption secret for '%s' invalid\n",
name);
@@ -279,7 +355,7 @@ static private_key_t* decrypt_key_with_config(settings_t *cfg, char *name,
mem->destroy(mem);
}
- return private;
+ return cred;
}
/**
@@ -292,30 +368,15 @@ static bool load_encrypted_key(vici_conn_t *conn,
{
private_key_t *private;
bool loaded = FALSE;
- chunk_t encoding;
- private = decrypt_key_with_config(cfg, rel, type, data);
+ private = decrypt_with_config(cfg, rel, type, data);
if (!private && !noprompt)
{
- private = decrypt_key(rel, type, data);
+ private = decrypt(rel, type, data);
}
if (private)
{
- if (private->get_encoding(private, PRIVKEY_ASN1_DER, &encoding))
- {
- switch (private->get_type(private))
- {
- case KEY_RSA:
- loaded = load_key(conn, format, path, "rsa", encoding);
- break;
- case KEY_ECDSA:
- loaded = load_key(conn, format, path, "ecdsa", encoding);
- break;
- default:
- break;
- }
- chunk_clear(&encoding);
- }
+ loaded = load_key_anytype(conn, format, path, private);
private->destroy(private);
}
return loaded;
@@ -361,6 +422,114 @@ 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)
+{
+ enumerator_t *enumerator;
+ certificate_t *cert;
+ private_key_t *private;
+ chunk_t encoding;
+ bool loaded = TRUE;
+
+ enumerator = p12->create_cert_enumerator(p12);
+ while (loaded && enumerator->enumerate(enumerator, &cert))
+ {
+ loaded = FALSE;
+ if (cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
+ {
+ loaded = load_cert(conn, format, path, "x509", encoding);
+ if (loaded)
+ {
+ fprintf(stderr, " %Y\n", cert->get_subject(cert));
+ }
+ free(encoding.ptr);
+ }
+ else
+ {
+ fprintf(stderr, "encoding certificate from '%s' failed\n", path);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ enumerator = p12->create_key_enumerator(p12);
+ while (loaded && enumerator->enumerate(enumerator, &private))
+ {
+ loaded = load_key_anytype(conn, format, path, private);
+ }
+ enumerator->destroy(enumerator);
+
+ return loaded;
+}
+
+/**
+ * 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)
+{
+ container_t *container;
+ bool loaded = FALSE;
+
+ container = decrypt_with_config(cfg, rel, type, data);
+ if (!container && !noprompt)
+ {
+ container = decrypt(rel, type, data);
+ }
+ if (container)
+ {
+ switch (container->get_type(container))
+ {
+ case CONTAINER_PKCS12:
+ loaded = load_pkcs12(conn, format, path, (pkcs12_t*)container);
+ break;
+ default:
+ break;
+ }
+ container->destroy(container);
+ }
+ return loaded;
+}
+
+/**
+ * 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)
+{
+ enumerator_t *enumerator;
+ struct stat st;
+ chunk_t *map;
+ char *path, *rel;
+
+ enumerator = enumerator_create_directory(dir);
+ if (enumerator)
+ {
+ while (enumerator->enumerate(enumerator, &rel, &path, &st))
+ {
+ if (S_ISREG(st.st_mode))
+ {
+ map = chunk_map(path, FALSE);
+ if (map)
+ {
+ load_encrypted_container(conn, format, cfg, rel, path,
+ type, noprompt, *map);
+ chunk_unmap(map);
+ }
+ else
+ {
+ fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
+ path, strerror(errno));
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+}
+
+/**
* Load a single secret over VICI
*/
static bool load_secret(vici_conn_t *conn, settings_t *cfg,
@@ -380,6 +549,7 @@ static bool load_secret(vici_conn_t *conn, settings_t *cfg,
"rsa",
"ecdsa",
"pkcs8",
+ "pkcs12",
};
for (i = 0; i < countof(types); i++)
@@ -510,7 +680,9 @@ int load_creds_cfg(vici_conn_t *conn, command_format_options_t format,
load_keys(conn, format, noprompt, cfg, "rsa", SWANCTL_RSADIR);
load_keys(conn, format, noprompt, cfg, "ecdsa", SWANCTL_ECDSADIR);
- load_keys(conn, format, noprompt, cfg, "any", SWANCTL_PKCS8DIR);
+ load_keys(conn, format, noprompt, cfg, "pkcs8", SWANCTL_PKCS8DIR);
+
+ load_containers(conn, format, noprompt, cfg, "pkcs12", SWANCTL_PKCS12DIR);
enumerator = cfg->create_section_enumerator(cfg, "secrets");
while (enumerator->enumerate(enumerator, &section))
diff --git a/src/swanctl/swanctl.conf b/src/swanctl/swanctl.conf
index 0808cf58b..faafecc44 100644
--- a/src/swanctl/swanctl.conf
+++ b/src/swanctl/swanctl.conf
@@ -286,6 +286,18 @@
# }
+ # PKCS#12 decryption passphrase for a container in the pkcs12 folder.
+ # pkcs12<suffix> {
+
+ # File name in the pkcs12 folder for which this passphrase should be
+ # used.
+ # file =
+
+ # Value of decryption passphrase for PKCS#12 container.
+ # secret =
+
+ # }
+
# }
# Section defining named pools.
@@ -294,7 +306,7 @@
# Section defining a single pool with a unique name.
# <name> {
- # Subnet defining addresses allocated in pool.
+ # Addresses allocated in pool.
# addrs =
# Comma separated list of additional attributes from type <attr>.
diff --git a/src/swanctl/swanctl.conf.5.main b/src/swanctl/swanctl.conf.5.main
index 8943b62db..a770b28b1 100644
--- a/src/swanctl/swanctl.conf.5.main
+++ b/src/swanctl/swanctl.conf.5.main
@@ -251,7 +251,12 @@ performs a reauthentication procedure instead.
With the default value IKE rekeying is scheduled every 4 hours, minus the
configured
.RB "" "rand_time" "."
-
+If a
+.RB "" "reauth_time" ""
+is configured,
+.RB "" "rekey_time" ""
+defaults to zero disabling rekeying; explicitly set both to enforce rekeying and
+reauthentication.
.TP
.BR connections.<conn>.over_time " [10% of rekey_time/reauth_time]"
@@ -363,6 +368,37 @@ IKE identity to use for authentication round. When using certificate
authentication, the IKE identity must be contained in the certificate, either as
subject or as subjectAltName.
+The identity can be an IP address, a fully\-qualified domain name, an email
+address or a Distinguished Name for which the ID type is determined
+automatically and the string is converted to the appropriate encoding. To
+enforce a specific identity type, a prefix may be used, followed by a colon (:).
+If the number sign (#) follows the colon, the remaining data is interpreted as
+hex encoding, otherwise the string is used as\-is as the identification data.
+Note that this implies that no conversion is performed for non\-string
+identities. For example,
+.RI "" "ipv4:10.0.0.1" ""
+does not create a valid ID_IPV4_ADDR
+IKE identity, as it does not get converted to binary 0x0a000001. Instead, one
+could use
+.RI "" "ipv4:#0a000001" ""
+to get a valid identity, but just using the implicit
+type with automatic conversion is usually simpler. The same applies to the ASN1
+encoded types. The following prefixes are known:
+.RI "" "ipv4" ","
+.RI "" "ipv6" ","
+.RI "" "rfc822" ","
+.RI "" "email" ","
+.RI "" "userfqdn" ","
+.RI "" "fqdn" ","
+.RI "" "dns" ","
+.RI "" "asn1dn" ","
+.RI "" "asn1gn" ""
+and
+.RI "" "keyid" "."
+Custom type
+prefixes may be specified by surrounding the numerical type value by curly
+brackets.
+
.TP
.BR connections.<conn>.local<suffix>.eap_id " [id]"
Client EAP\-Identity to use in EAP\-Identity exchange and the EAP method.
@@ -397,9 +433,10 @@ omitted.
.TP
.BR connections.<conn>.remote<suffix>.id " [%any]"
-IKE identity to expect for authentication round. When using certificate
-authentication, the IKE identity must be contained in the certificate, either as
-subject or as subjectAltName.
+IKE identity to expect for authentication round. Refer to the
+.RI "" "local" ""
+.RI "" "id" ""
+section for details.
.TP
.BR connections.<conn>.remote<suffix>.groups " []"
@@ -725,9 +762,11 @@ uses dynamic reqids, allocated incrementally.
.TP
.BR connections.<conn>.children.<child>.mark_in " [0/0x00000000]"
-Netfilter mark and mask for input traffic. On Linux Netfilter may apply marks to
-each packet coming from a tunnel having that option set. The mark may then be
-used by Netfilter to match rules.
+Netfilter mark and mask for input traffic. On Linux Netfilter may require marks
+on each packet to match an SA having that option set. This allows Netfilter
+rules to select specific tunnels for incoming traffic. The special value
+.RI "" "%unique" ""
+sets a unique mark on each CHILD_SA instance.
An additional mask may be appended to the mark, separated by _/_. The default
mask if omitted is 0xffffffff.
@@ -736,7 +775,9 @@ mask if omitted is 0xffffffff.
.BR connections.<conn>.children.<child>.mark_out " [0/0x00000000]"
Netfilter mark and mask for output traffic. On Linux Netfilter may require marks
on each packet to match a policy having that option set. This allows Netfilter
-rules to select specific tunnels for outgoing traffic.
+rules to select specific tunnels for outgoing traffic. The special value
+.RI "" "%unique" ""
+sets a unique mark on each CHILD_SA instance.
An additional mask may be appended to the mark, separated by _/_. The default
mask if omitted is 0xffffffff.
@@ -925,6 +966,23 @@ folder for which this passphrase should be used.
Value of decryption passphrase for PKCS#8 key.
.TP
+.B secrets.pkcs12<suffix>
+.br
+PKCS#12 decryption passphrase for a container in the
+.RI "" "pkcs12" ""
+folder.
+
+.TP
+.BR secrets.pkcs12<suffix>.file " []"
+File name in the
+.RI "" "pkcs12" ""
+folder for which this passphrase should be used.
+
+.TP
+.BR secrets.pkcs12<suffix>.secret " []"
+Value of decryption passphrase for PKCS#12 container.
+
+.TP
.B pools
.br
Section defining named pools. Named pools may be referenced by connections with
@@ -939,9 +997,9 @@ Section defining a single pool with a unique name.
.TP
.BR pools.<name>.addrs " []"
-Subnet defining addresses allocated in pool. Accepts a single CIDR subnet
-defining the pool to allocate addresses from. Pools must be unique and
-non\-overlapping.
+Subnet or range defining addresses allocated in pool. Accepts a single CIDR
+subnet defining the pool to allocate addresses from, or an address range
+(<from>\-<to>). Pools must be unique and non\-overlapping.
.TP
.BR pools.<name>.<attr> " []"
diff --git a/src/swanctl/swanctl.h b/src/swanctl/swanctl.h
index bd7e00378..cb570cd34 100644
--- a/src/swanctl/swanctl.h
+++ b/src/swanctl/swanctl.h
@@ -66,4 +66,9 @@
*/
#define SWANCTL_PKCS8DIR SWANCTLDIR "/pkcs8"
+/**
+ * Directory for PKCS#12 containers
+ */
+#define SWANCTL_PKCS12DIR SWANCTLDIR "/pkcs12"
+
#endif /** SWANCTL_H_ @}*/
diff --git a/src/swanctl/swanctl.opt b/src/swanctl/swanctl.opt
index f1e47a9e4..b6ef17546 100644
--- a/src/swanctl/swanctl.opt
+++ b/src/swanctl/swanctl.opt
@@ -220,7 +220,9 @@ connections.<conn>.rekey_time = 4h
IKEv1 performs a reauthentication procedure instead.
With the default value IKE rekeying is scheduled every 4 hours, minus the
- configured **rand_time**.
+ configured **rand_time**. If a **reauth_time** is configured, **rekey_time**
+ defaults to zero disabling rekeying; explicitly set both to enforce
+ rekeying and reauthentication.
connections.<conn>.over_time = 10% of rekey_time/reauth_time
Hard IKE_SA lifetime if rekey/reauth does not complete, as time.
@@ -303,6 +305,22 @@ connections.<conn>.local<suffix>.id =
authentication, the IKE identity must be contained in the certificate,
either as subject or as subjectAltName.
+ The identity can be an IP address, a fully-qualified domain name, an email
+ address or a Distinguished Name for which the ID type is determined
+ automatically and the string is converted to the appropriate encoding. To
+ enforce a specific identity type, a prefix may be used, followed by a colon
+ (:). If the number sign (#) follows the colon, the remaining data is
+ interpreted as hex encoding, otherwise the string is used as-is as the
+ identification data. Note that this implies that no conversion is performed
+ for non-string identities. For example, _ipv4:10.0.0.1_ does not create a
+ valid ID_IPV4_ADDR IKE identity, as it does not get converted to binary
+ 0x0a000001. Instead, one could use _ipv4:#0a000001_ to get a valid identity,
+ but just using the implicit type with automatic conversion is usually
+ simpler. The same applies to the ASN1 encoded types. The following prefixes
+ are known: _ipv4_, _ipv6_, _rfc822_, _email_, _userfqdn_, _fqdn_, _dns_,
+ _asn1dn_, _asn1gn_ and _keyid_. Custom type prefixes may be specified by
+ surrounding the numerical type value by curly brackets.
+
connections.<conn>.local<suffix>.eap_id = id
Client EAP-Identity to use in EAP-Identity exchange and the EAP method.
@@ -335,9 +353,8 @@ connections.<conn>.remote<suffix> {}
connections.<conn>.remote<suffix>.id = %any
IKE identity to expect for authentication round.
- IKE identity to expect for authentication round. When using certificate
- authentication, the IKE identity must be contained in the certificate,
- either as subject or as subjectAltName.
+ IKE identity to expect for authentication round. Refer to the _local_ _id_
+ section for details.
connections.<conn>.remote<suffix>.groups =
Authorization group memberships to require.
@@ -607,9 +624,10 @@ connections.<conn>.children.<child>.reqid = 0
connections.<conn>.children.<child>.mark_in = 0/0x00000000
Netfilter mark and mask for input traffic.
- Netfilter mark and mask for input traffic. On Linux Netfilter may apply
- marks to each packet coming from a tunnel having that option set. The
- mark may then be used by Netfilter to match rules.
+ Netfilter mark and mask for input traffic. On Linux Netfilter may require
+ marks on each packet to match an SA having that option set. This allows
+ Netfilter rules to select specific tunnels for incoming traffic. The
+ special value _%unique_ sets a unique mark on each CHILD_SA instance.
An additional mask may be appended to the mark, separated by _/_. The
default mask if omitted is 0xffffffff.
@@ -619,7 +637,8 @@ connections.<conn>.children.<child>.mark_out = 0/0x00000000
Netfilter mark and mask for output traffic. On Linux Netfilter may require
marks on each packet to match a policy having that option set. This allows
- Netfilter rules to select specific tunnels for outgoing traffic.
+ Netfilter rules to select specific tunnels for outgoing traffic. The
+ special value _%unique_ sets a unique mark on each CHILD_SA instance.
An additional mask may be appended to the mark, separated by _/_. The
default mask if omitted is 0xffffffff.
@@ -756,6 +775,15 @@ secrets.pkcs8<suffix>.file =
secrets.pkcs8<suffix>.secret
Value of decryption passphrase for PKCS#8 key.
+secrets.pkcs12<suffix> { # }
+ PKCS#12 decryption passphrase for a container in the _pkcs12_ folder.
+
+secrets.pkcs12<suffix>.file =
+ File name in the _pkcs12_ folder for which this passphrase should be used.
+
+secrets.pkcs12<suffix>.secret
+ Value of decryption passphrase for PKCS#12 container.
+
pools { # }
Section defining named pools.
@@ -767,11 +795,11 @@ pools.<name> { # }
Section defining a single pool with a unique name.
pools.<name>.addrs =
- Subnet defining addresses allocated in pool.
+ Addresses allocated in pool.
- Subnet defining addresses allocated in pool. Accepts a single CIDR subnet
- defining the pool to allocate addresses from. Pools must be unique and
- non-overlapping.
+ Subnet or range defining addresses allocated in pool. Accepts a single CIDR
+ subnet defining the pool to allocate addresses from, or an address range
+ (<from>-<to>). Pools must be unique and non-overlapping.
pools.<name>.<attr> =
Comma separated list of additional attributes from type <attr>.