diff options
Diffstat (limited to 'src/swanctl')
-rw-r--r-- | src/swanctl/Makefile.am | 1 | ||||
-rw-r--r-- | src/swanctl/Makefile.in | 6 | ||||
-rw-r--r-- | src/swanctl/commands/list_conns.c | 5 | ||||
-rw-r--r-- | src/swanctl/commands/list_sas.c | 6 | ||||
-rw-r--r-- | src/swanctl/commands/load_conns.c | 47 | ||||
-rw-r--r-- | src/swanctl/commands/load_creds.c | 290 | ||||
-rw-r--r-- | src/swanctl/swanctl.conf | 14 | ||||
-rw-r--r-- | src/swanctl/swanctl.conf.5.main | 80 | ||||
-rw-r--r-- | src/swanctl/swanctl.h | 5 | ||||
-rw-r--r-- | src/swanctl/swanctl.opt | 52 |
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, §ion)) 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>. |