Merge branch 'vici-updates'

Adds several new features for the VICI interface and swanctl.
This commit is contained in:
Tobias Brunner
2017-02-16 19:24:17 +01:00
39 changed files with 1971 additions and 330 deletions
+15 -1
View File
@@ -8,9 +8,23 @@ strongswan-5.5.2
draft-ietf-ipsecme-eddsa. Ed25519-based public key pairs, X.509 certificates
and CRLs can be generated and printed by the pki tool.
- In-place update of cached base and delta CRLs does no leave dozens
- In-place update of cached base and delta CRLs does not leave dozens
of stale copies in cache memory.
- Several new features for the VICI interface and the swanctl utility: Querying
specific pools, enumerating and unloading keys and shared secrets, loading
keys and certificates from PKCS#11 tokens, the ability to initiate, install
and uninstall connections and policies by their exact name (if multiple child
sections in different connections share the same name), a command to initiate
the rekeying of IKE and IPsec SAs, support for settings previously only
supported by the old config files (plain pubkeys, dscp, certificate policies,
IPv6 Transport Proxy Mode, NT Hash secrets, mediation extension).
Important: Due to issues with VICI bindings that map sub-sections to
dictionaries the CHILD_SA sections returned via list-sas now have a unique
name, the original name of a CHILD_SA is returned in the "name" key of its
section.
strongswan-5.5.1
----------------
+6 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2016 Tobias Brunner
* Copyright (C) 2007-2017 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* HSR Hochschule fuer Technik Rapperswil
@@ -164,7 +164,7 @@ struct private_peer_cfg_t {
/**
* Name of the mediation connection to mediate through
*/
peer_cfg_t *mediated_by;
char *mediated_by;
/**
* ID of our peer at the mediation server (= leftid of the peer's conn with
@@ -580,7 +580,7 @@ METHOD(peer_cfg_t, is_mediation, bool,
return this->mediation;
}
METHOD(peer_cfg_t, get_mediated_by, peer_cfg_t*,
METHOD(peer_cfg_t, get_mediated_by, char*,
private_peer_cfg_t *this)
{
return this->mediated_by;
@@ -683,7 +683,7 @@ METHOD(peer_cfg_t, equals, bool,
auth_cfg_equal(this, other)
#ifdef ME
&& this->mediation == other->mediation &&
this->mediated_by == other->mediated_by &&
streq(this->mediated_by, other->mediated_by) &&
(this->peer_id == other->peer_id ||
(this->peer_id && other->peer_id &&
this->peer_id->equals(this->peer_id, other->peer_id)))
@@ -713,8 +713,8 @@ METHOD(peer_cfg_t, destroy, void,
this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
this->pools->destroy_function(this->pools, free);
#ifdef ME
DESTROY_IF(this->mediated_by);
DESTROY_IF(this->peer_id);
free(this->mediated_by);
#endif /* ME */
this->mutex->destroy(this->mutex);
free(this->name);
@@ -802,7 +802,7 @@ peer_cfg_t *peer_cfg_create(char *name, ike_cfg_t *ike_cfg,
.refcount = 1,
#ifdef ME
.mediation = data->mediation,
.mediated_by = data->mediated_by,
.mediated_by = strdupnull(data->mediated_by),
.peer_id = data->peer_id,
#endif /* ME */
);
+8 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2016 Tobias Brunner
* Copyright (C) 2007-2017 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* HSR Hochschule fuer Technik Rapperswil
@@ -319,14 +319,14 @@ struct peer_cfg_t {
*
* @return TRUE, if this is a mediation connection
*/
bool (*is_mediation) (peer_cfg_t *this);
bool (*is_mediation)(peer_cfg_t *this);
/**
* Get peer_cfg of the connection this one is mediated through.
* Get name of the connection this one is mediated through.
*
* @return the peer_cfg of the mediation connection
* @return the name of the mediation connection
*/
peer_cfg_t* (*get_mediated_by) (peer_cfg_t *this);
char* (*get_mediated_by)(peer_cfg_t *this);
/**
* Get the id of the other peer at the mediation server.
@@ -338,7 +338,7 @@ struct peer_cfg_t {
*
* @return the id of the other peer
*/
identification_t* (*get_peer_id) (peer_cfg_t *this);
identification_t* (*get_peer_id)(peer_cfg_t *this);
#endif /* ME */
/**
@@ -398,8 +398,8 @@ struct peer_cfg_create_t {
#ifdef ME
/** TRUE if this is a mediation connection */
bool mediation;
/** peer_cfg_t of the mediation connection to mediate through (adopted) */
peer_cfg_t *mediated_by;
/** peer_cfg_t of the mediation connection to mediate through (cloned) */
char *mediated_by;
/** ID that identifies our peer at the mediation server (adopted) */
identification_t *peer_id;
#endif /* ME */
@@ -79,7 +79,7 @@ static void bypass_policy_destroy(bypass_policy_t *this)
ts = traffic_selector_create_from_subnet(this->net->clone(this->net),
this->mask, 0, 0, 65535);
DBG1(DBG_IKE, "uninstalling bypass policy for %R", ts);
charon->shunts->uninstall(charon->shunts,
charon->shunts->uninstall(charon->shunts, "bypass-lan",
this->cfg->get_name(this->cfg));
this->cfg->destroy(this->cfg);
ts->destroy(ts);
@@ -173,7 +173,7 @@ static job_requeue_t update_bypass(private_bypass_lan_listener_t *this)
cfg = child_cfg_create(name, &child);
cfg->add_traffic_selector(cfg, FALSE, ts->clone(ts));
cfg->add_traffic_selector(cfg, TRUE, ts);
charon->shunts->install(charon->shunts, cfg);
charon->shunts->install(charon->shunts, "bypass-lan", cfg);
DBG1(DBG_IKE, "installed bypass policy for %R", ts);
INIT(found,
+53 -28
View File
@@ -23,6 +23,11 @@
typedef struct private_medcli_config_t private_medcli_config_t;
/**
* Name of the mediation connection
*/
#define MEDIATION_CONN_NAME "medcli-mediation"
/**
* Private data of an medcli_config_t object
*/
@@ -72,36 +77,19 @@ static traffic_selector_t *ts_from_string(char *str)
return traffic_selector_create_dynamic(0, 0, 65535);
}
METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
private_medcli_config_t *this, char *name)
/**
* Build a mediation config
*/
static peer_cfg_t *build_mediation_config(private_medcli_config_t *this,
peer_cfg_create_t *defaults)
{
enumerator_t *e;
peer_cfg_t *peer_cfg, *med_cfg;
auth_cfg_t *auth;
ike_cfg_t *ike_cfg;
child_cfg_t *child_cfg;
peer_cfg_t *med_cfg;
peer_cfg_create_t peer = *defaults;
chunk_t me, other;
char *address, *local_net, *remote_net;
peer_cfg_create_t peer = {
.cert_policy = CERT_NEVER_SEND,
.unique = UNIQUE_REPLACE,
.keyingtries = 1,
.rekey_time = this->rekey * 60,
.jitter_time = this->rekey * 5,
.over_time = this->rekey * 3,
.dpd = this->dpd,
.mediation = TRUE,
};
child_cfg_create_t child = {
.lifetime = {
.time = {
.life = this->rekey * 60 + this->rekey,
.rekey = this->rekey,
.jitter = this->rekey
},
},
.mode = MODE_TUNNEL,
};
char *address;
/* query mediation server config:
* - build ike_cfg/peer_cfg for mediation connection on-the-fly
@@ -120,7 +108,9 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
address, IKEV2_UDP_PORT, FRAGMENTATION_NO, 0);
ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE));
med_cfg = peer_cfg_create("mediation", ike_cfg, &peer);
peer.mediation = TRUE;
med_cfg = peer_cfg_create(MEDIATION_CONN_NAME, ike_cfg, &peer);
e->destroy(e);
auth = auth_cfg_create();
@@ -133,6 +123,42 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
auth->add(auth, AUTH_RULE_IDENTITY,
identification_create_from_encoding(ID_KEY_ID, other));
med_cfg->add_auth_cfg(med_cfg, auth, FALSE);
return med_cfg;
}
METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
private_medcli_config_t *this, char *name)
{
enumerator_t *e;
auth_cfg_t *auth;
peer_cfg_t *peer_cfg;
child_cfg_t *child_cfg;
chunk_t me, other;
char *local_net, *remote_net;
peer_cfg_create_t peer = {
.cert_policy = CERT_NEVER_SEND,
.unique = UNIQUE_REPLACE,
.keyingtries = 1,
.rekey_time = this->rekey * 60,
.jitter_time = this->rekey * 5,
.over_time = this->rekey * 3,
.dpd = this->dpd,
};
child_cfg_create_t child = {
.lifetime = {
.time = {
.life = this->rekey * 60 + this->rekey,
.rekey = this->rekey,
.jitter = this->rekey
},
},
.mode = MODE_TUNNEL,
};
if (streq(name, "medcli-mediation"))
{
return build_mediation_config(this, &peer);
}
/* query mediated config:
* - use any-any ike_cfg
@@ -150,8 +176,7 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
DESTROY_IF(e);
return NULL;
}
peer.mediation = FALSE;
peer.mediated_by = med_cfg;
peer.mediated_by = MEDIATION_CONN_NAME;
peer.peer_id = identification_create_from_encoding(ID_KEY_ID, other);
peer_cfg = peer_cfg_create(name, this->ike->get_ref(this->ike), &peer);
+7 -3
View File
@@ -381,12 +381,14 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
ike = get_ike_cfg_by_id(this, ike_cfg);
#ifdef ME
mediated_cfg = mediated_by ? get_peer_cfg_by_id(this, mediated_by) : NULL;
mediated_cfg = mediated_by ? get_peer_cfg_by_id(this, mediated_by)
: NULL;
if (p_type)
{
peer_id = identification_create_from_encoding(p_type, p_data);
}
#endif
#endif /* ME */
if (virtual)
{
vip = host_create_from_string(virtual, 0);
@@ -405,7 +407,8 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
.dpd = dpd_delay,
#ifdef ME
.mediation = mediation,
.mediated_by = mediated_cfg,
.mediated_by = mediated_cfg ?
mediated_cfg->get_name(mediated_cfg) : NULL,
.peer_id = peer_id,
#endif /* ME */
};
@@ -443,6 +446,7 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
}
peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
add_child_cfgs(this, peer_cfg, id);
DESTROY_IF(mediated_cfg);
return peer_cfg;
}
DESTROY_IF(ike);
+2 -21
View File
@@ -642,28 +642,9 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
/* force unique connections for mediation connections */
msg->add_conn.unique = 1;
}
if (msg->add_conn.ikeme.mediated_by)
else if (msg->add_conn.ikeme.mediated_by)
{
peer_cfg_t *mediated_by;
mediated_by = charon->backends->get_peer_cfg_by_name(
charon->backends, msg->add_conn.ikeme.mediated_by);
if (!mediated_by)
{
DBG1(DBG_CFG, "mediation connection '%s' not found, aborting",
msg->add_conn.ikeme.mediated_by);
return NULL;
}
if (!mediated_by->is_mediation(mediated_by))
{
DBG1(DBG_CFG, "connection '%s' as referred to by '%s' is "
"no mediation connection, aborting",
msg->add_conn.ikeme.mediated_by, msg->add_conn.name);
mediated_by->destroy(mediated_by);
return NULL;
}
peer.mediated_by = mediated_by;
peer.mediated_by = msg->add_conn.ikeme.mediated_by;
if (msg->add_conn.ikeme.peerid)
{
peer.peer_id = identification_create_from_string(
+18 -2
View File
@@ -641,7 +641,8 @@ static void charon_route(peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
mode = child_cfg->get_mode(child_cfg);
if (mode == MODE_PASS || mode == MODE_DROP)
{
if (charon->shunts->install(charon->shunts, child_cfg))
if (charon->shunts->install(charon->shunts,
peer_cfg->get_name(peer_cfg), child_cfg))
{
fprintf(out, "'%s' shunt %N policy installed\n",
name, ipsec_mode_names, mode);
@@ -729,15 +730,30 @@ METHOD(stroke_control_t, route, void,
METHOD(stroke_control_t, unroute, void,
private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
{
child_cfg_t *child_cfg;
child_sa_t *child_sa;
enumerator_t *enumerator;
char *ns, *found = NULL;
uint32_t id = 0;
if (charon->shunts->uninstall(charon->shunts, msg->unroute.name))
enumerator = charon->shunts->create_enumerator(charon->shunts);
while (enumerator->enumerate(enumerator, &ns, &child_cfg))
{
if (ns && streq(msg->unroute.name, child_cfg->get_name(child_cfg)))
{
found = strdup(ns);
break;
}
}
enumerator->destroy(enumerator);
if (found && charon->shunts->uninstall(charon->shunts, found,
msg->unroute.name))
{
free(found);
fprintf(out, "shunt policy '%s' uninstalled\n", msg->unroute.name);
return;
}
free(found);
enumerator = charon->traps->create_enumerator(charon->traps);
while (enumerator->enumerate(enumerator, NULL, &child_sa))
+1 -1
View File
@@ -603,7 +603,7 @@ METHOD(stroke_list_t, status, void,
/* Enumerate shunt policies */
first = TRUE;
enumerator = charon->shunts->create_enumerator(charon->shunts);
while (enumerator->enumerate(enumerator, &child_cfg))
while (enumerator->enumerate(enumerator, NULL, &child_cfg))
{
if (name && !streq(name, child_cfg->get_name(child_cfg)))
{
+3 -2
View File
@@ -235,7 +235,7 @@ static job_requeue_t add_exclude_async(entry_t *entry)
enumerator->destroy(enumerator);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
charon->shunts->install(charon->shunts, child_cfg);
charon->shunts->install(charon->shunts, "unity", child_cfg);
child_cfg->destroy(child_cfg);
DBG1(DBG_IKE, "installed %N bypass policy for %R",
@@ -310,7 +310,8 @@ static bool remove_exclude(private_unity_handler_t *this, chunk_t data)
DBG1(DBG_IKE, "uninstalling %N bypass policy for %R",
configuration_attribute_type_names, UNITY_LOCAL_LAN, ts);
ts->destroy(ts);
success = charon->shunts->uninstall(charon->shunts, name) && success;
success = charon->shunts->uninstall(charon->shunts, "unity",
name) && success;
}
list->destroy(list);
return success;
+93 -4
View File
@@ -283,12 +283,29 @@ Terminates an SA while streaming _control-log_ events.
loglevel = <loglevel to issue "control-log" events for>
} => {
success = <yes or no>
matches = <number of matched SAs>
terminated = <number of terminated SAs>
errmsg = <error string on failure or timeout>
}
The default timeout of 0 waits indefinitely for a result, and a timeout value
of -1 returns a result immediately.
### rekey() ###
Initiate the rekeying of an SA.
{
child = <rekey a CHILD_SA by configuration name>
ike = <rekey an IKE_SA by configuration name>
child-id = <rekey a CHILD_SA by its reqid>
ike-id = <rekey an IKE_SA by its unique id>
} => {
success = <yes or no>
matches = <number of matched SAs>
errmsg = <error string on failure>
}
### redirect() ###
Redirect a client-initiated IKE_SA to another gateway. Only for IKEv2 and if
@@ -303,6 +320,7 @@ supported by the peer.
wildcards>
} => {
success = <yes or no>
matches = <number of matched SAs>
errmsg = <error string on failure>
}
@@ -312,7 +330,7 @@ Install a trap, drop or bypass policy defined by a CHILD_SA config.
{
child = <CHILD_SA configuration name to install>
ike = <optional IKE_SA configuraiton name to find child under>
ike = <optional IKE_SA configuration name to find child under>
} => {
success = <yes or no>
errmsg = <error string on failure>
@@ -324,6 +342,8 @@ Uninstall a trap, drop or bypass policy defined by a CHILD_SA config.
{
child = <CHILD_SA configuration name to install>
ike = <optional IKE_SA configuration name to find child under,
if not given the first policy matching child is removed>
} => {
success = <yes or no>
errmsg = <error string on failure>
@@ -352,6 +372,7 @@ _list-policy_ events.
pass = <set to yes to list bypass policies>
trap = <set to yes to list trap policies>
child = <filter by CHILD_SA configuration name>
ike = <filter by IKE_SA configuration name>
} => {
# completes after streaming list-sa events
}
@@ -466,12 +487,53 @@ Load a private key into the daemon.
errmsg = <error string on failure>
}
### unload-key() ###
Unload the private key with the given key identifier.
{
id = <hex-encoded SHA-1 key identifier of the private key to unload>
} => {
success = <yes or no>
errmsg = <error string on failure>
}
### get-keys() ###
Return a list of identifiers of private keys loaded exclusively over vici, not
including keys found in other backends.
{} => {
keys = [
<list of hex-encoded SHA-1 key identifiers>
]
}
### load-token() ###
Load a private key located on a token into the daemon. Such keys may be listed
and unloaded using the _get-keys_ and _unload-key_ commands, respectively (based
on the key identifier derived from the public key).
{
handle = <hex-encoded CKA_ID of the private key on token>
slot = <optional slot number>
module = <optional PKCS#11 module>
pin = <optional PIN to access the key, has to be provided via other
means if not given>
} => {
success = <yes or no>
errmsg = <error string on failure>
id = <hex-encoded SHA-1 key identifier of the public key on success>
}
### load-shared() ###
Load a shared IKE PSK, EAP or XAuth secret into the daemon.
{
type = <private key type, IKE|EAP|XAUTH>
id = <optional unique identifier of this shared key>
type = <shared key type, IKE|EAP|XAUTH>
data = <raw shared key data>
owners = [
<list of shared key owner identities>
@@ -481,6 +543,29 @@ Load a shared IKE PSK, EAP or XAuth secret into the daemon.
errmsg = <error string on failure>
}
### unload-shared() ###
Unload a previously loaded shared IKE PSK, EAP or XAuth secret by its unique
identifier.
{
id = <unique identifier of the shared key to unload>
} => {
success = <yes or no>
errmsg = <error string on failure>
}
### get-shared() ###
Return a list of unique identifiers of shared keys loaded exclusively over vici,
not including keys found in other backends.
{} => {
keys = [
<list of unique identifiers>
]
}
### flush-certs() ###
Flushes the certificate cache. The optional type argument allows to flush
@@ -569,6 +654,7 @@ List the currently loaded pools.
{
leases = <set to yes to include leases>
name = <optional name of the pool to query>
} => {
<pool name>* = {
base = <virtual IP pool base address>
@@ -678,7 +764,8 @@ command.
<list of tasks currently handling passively>
]
child-sas = {
<child-sa-name>* = {
<unique child-sa-name>* = {
name = <name of the CHILD_SA>
uniqueid = <unique CHILD_SA identifier>
reqid = <reqid of CHILD_SA>
state = <state string of CHILD_SA>
@@ -726,7 +813,9 @@ The _list-policy_ event is issued to stream installed policies during an active
_list-policies_ command.
{
<child-sa-config-name> = {
<ike-sa-config-name/child-sa-config-name> = {
child = <CHILD_SA configuration name>
ike = <IKE_SA configuration name or namespace, if available>
mode = <policy mode, tunnel|transport|pass|drop>
local-ts = [
<list of local traffic selectors>
@@ -208,13 +208,15 @@ class Session(object):
"""
self.handler.request("unload-pool", pool_name)
def get_pools(self):
def get_pools(self, options):
"""Retrieve loaded pools.
:param options: filter by name and/or retrieve leases (optional)
:type options: dict
:return: loaded pools
:rtype: dict
"""
return self.handler.request("get-pools")
return self.handler.request("get-pools", options)
def listen(self, event_types):
"""Register and listen for the given events.
+2 -2
View File
@@ -492,8 +492,8 @@ module Vici
##
# Get the currently loaded pools.
def get_pools()
@transp.request("get-pools").root
def get_pools(options)
@transp.request("get-pools", Message.new(options)).root
end
##
+9 -3
View File
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014-2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
* Copyright (C) 2014-2016 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
@@ -668,10 +668,11 @@ CALLBACK(get_pools, vici_message_t*,
identification_t *uid;
host_t *lease;
bool list_leases, on;
char buf[32];
char buf[32], *filter;
int i;
list_leases = message->get_bool(message, FALSE, "leases");
filter = message->get_str(message, NULL, "name");
builder = vici_builder_create();
@@ -679,6 +680,11 @@ CALLBACK(get_pools, vici_message_t*,
enumerator = this->pools->create_enumerator(this->pools);
while (enumerator->enumerate(enumerator, &name, &pool))
{
if (filter && !streq(name, filter))
{
continue;
}
vips = pool->vips;
builder->begin_section(builder, name);
+97 -10
View File
@@ -1,4 +1,5 @@
/*
* Copyright (C) 2016 Tobias Brunner
* Copyright (C) 2015 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
@@ -199,8 +200,27 @@ typedef struct {
typedef struct {
request_data_t *request;
authority_t *authority;
char *handle;
uint32_t slot;
char *module;
char *file;
} load_data_t;
/**
* Clean up data associated with an authority load
*/
static void free_load_data(load_data_t *data)
{
if (data->authority)
{
authority_destroy(data->authority);
}
free(data->handle);
free(data->module);
free(data->file);
free(data);
}
/**
* Parse a string
*/
@@ -216,6 +236,28 @@ CALLBACK(parse_string, bool,
return TRUE;
}
/**
* Parse a uint32_t
*/
CALLBACK(parse_uint32, bool,
uint32_t *out, chunk_t v)
{
char buf[16], *end;
u_long l;
if (!vici_stringify(v, buf, sizeof(buf)))
{
return FALSE;
}
l = strtoul(buf, &end, 0);
if (*end == 0)
{
*out = l;
return TRUE;
}
return FALSE;
}
/**
* Parse list of URIs
*/
@@ -266,8 +308,12 @@ CALLBACK(authority_kv, bool,
load_data_t *data, vici_message_t *message, char *name, chunk_t value)
{
parse_rule_t rules[] = {
{ "cacert", parse_cacert, &data->authority->cert },
{ "cert_uri_base", parse_string, &data->authority->cert_uri_base },
{ "cacert", parse_cacert, &data->authority->cert },
{ "file", parse_string, &data->file },
{ "handle", parse_string, &data->handle },
{ "slot", parse_uint32, &data->slot },
{ "module", parse_string, &data->module },
{ "cert_uri_base", parse_string, &data->authority->cert_uri_base },
};
return parse_rules(rules, countof(rules), name, value,
@@ -341,21 +387,60 @@ CALLBACK(authority_sn, bool,
linked_list_t *authorities;
authority_t *authority;
vici_cred_t *cred;
load_data_t *data;
chunk_t handle;
load_data_t data = {
INIT(data,
.request = request,
.authority = authority_create(name),
};
.slot = -1,
);
DBG2(DBG_CFG, " authority %s:", name);
if (!message->parse(message, ctx, NULL, authority_kv, authority_li, &data) ||
!data.authority->cert)
if (!message->parse(message, ctx, NULL, authority_kv, authority_li, data))
{
authority_destroy(data.authority);
free_load_data(data);
return FALSE;
}
log_authority_data(data.authority);
if (!data->authority->cert)
{
if (data->file)
{
data->authority->cert = lib->creds->create(lib->creds,
CRED_CERTIFICATE, CERT_X509,
BUILD_FROM_FILE, data->file, BUILD_END);
}
else if (data->handle)
{
handle = chunk_from_hex(chunk_from_str(data->handle), NULL);
if (data->slot != -1)
{
data->authority->cert = lib->creds->create(lib->creds,
CRED_CERTIFICATE, CERT_X509,
BUILD_PKCS11_KEYID, handle,
BUILD_PKCS11_SLOT, data->slot,
data->module ? BUILD_PKCS11_MODULE : BUILD_END,
data->module, BUILD_END);
}
else
{
data->authority->cert = lib->creds->create(lib->creds,
CRED_CERTIFICATE, CERT_X509,
BUILD_PKCS11_KEYID, handle,
data->module ? BUILD_PKCS11_MODULE : BUILD_END,
data->module, BUILD_END);
}
chunk_free(&handle);
}
}
if (!data->authority->cert)
{
request->reply = create_reply("CA certificate missing: %s", name);
free_load_data(data);
return FALSE;
}
log_authority_data(data->authority);
request->this->lock->write_lock(request->this->lock);
@@ -372,12 +457,14 @@ CALLBACK(authority_sn, bool,
}
}
enumerator->destroy(enumerator);
authorities->insert_last(authorities, data.authority);
authorities->insert_last(authorities, data->authority);
cred = request->this->cred;
data.authority->cert = cred->add_cert(cred, data.authority->cert);
data->authority->cert = cred->add_cert(cred, data->authority->cert);
data->authority = NULL;
request->this->lock->unlock(request->this->lock);
free_load_data(data);
return TRUE;
}
+295 -31
View File
@@ -2,7 +2,7 @@
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
*
* Copyright (C) 2015-2016 Tobias Brunner
* Copyright (C) 2015-2017 Tobias Brunner
* Copyright (C) 2015-2016 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
@@ -246,6 +246,28 @@ typedef struct {
vici_message_t *reply;
} request_data_t;
/**
* Certificate data
*/
typedef struct {
request_data_t *request;
char *handle;
uint32_t slot;
char *module;
char *file;
} cert_data_t;
/**
* Clean up certificate data
*/
static void free_cert_data(cert_data_t *data)
{
free(data->handle);
free(data->module);
free(data->file);
free(data);
}
/**
* Auth config data
*/
@@ -295,6 +317,12 @@ typedef struct {
uint64_t rekey_time;
uint64_t over_time;
uint64_t rand_time;
uint8_t dscp;
#ifdef ME
bool mediation;
char *mediated_by;
identification_t *peer_id;
#endif /* ME */
} peer_data_t;
/**
@@ -370,6 +398,7 @@ static void log_peer_data(peer_data_t *data)
DBG2(DBG_CFG, " send_cert = %N", cert_policy_names, data->send_cert);
DBG2(DBG_CFG, " mobike = %u", data->mobike);
DBG2(DBG_CFG, " aggressive = %u", data->aggressive);
DBG2(DBG_CFG, " dscp = 0x%.2x", data->dscp);
DBG2(DBG_CFG, " encap = %u", data->encap);
DBG2(DBG_CFG, " dpd_delay = %llu", data->dpd_delay);
DBG2(DBG_CFG, " dpd_timeout = %llu", data->dpd_timeout);
@@ -381,6 +410,14 @@ static void log_peer_data(peer_data_t *data)
DBG2(DBG_CFG, " over_time = %llu", data->over_time);
DBG2(DBG_CFG, " rand_time = %llu", data->rand_time);
DBG2(DBG_CFG, " proposals = %#P", data->proposals);
#ifdef ME
DBG2(DBG_CFG, " mediation = %u", data->mediation);
if (data->mediated_by)
{
DBG2(DBG_CFG, " mediated_by = %s", data->mediated_by);
DBG2(DBG_CFG, " mediation_peer = %Y", data->peer_id);
}
#endif /* ME */
if (data->vips->get_count(data->vips))
{
@@ -425,6 +462,10 @@ static void free_peer_data(peer_data_t *data)
free(data->pools);
free(data->local_addrs);
free(data->remote_addrs);
#ifdef ME
free(data->mediated_by);
DESTROY_IF(data->peer_id);
#endif /* ME */
}
/**
@@ -461,7 +502,8 @@ static void log_child_data(child_data_t *data, char *name)
DBG2(DBG_CFG, " updown = %s", cfg->updown);
DBG2(DBG_CFG, " hostaccess = %u", cfg->hostaccess);
DBG2(DBG_CFG, " ipcomp = %u", cfg->ipcomp);
DBG2(DBG_CFG, " mode = %N", ipsec_mode_names, cfg->mode);
DBG2(DBG_CFG, " mode = %N%s", ipsec_mode_names, cfg->mode,
cfg->proxy_mode ? "_PROXY" : "");
DBG2(DBG_CFG, " policies = %u", data->policies);
DBG2(DBG_CFG, " policies_fwd_out = %u", data->policies_fwd_out);
if (data->replay_window != REPLAY_UNDEFINED)
@@ -770,20 +812,22 @@ CALLBACK(parse_bool, bool,
* Parse a ipsec_mode_t
*/
CALLBACK(parse_mode, bool,
ipsec_mode_t *out, chunk_t v)
child_cfg_create_t *cfg, chunk_t v)
{
enum_map_t map[] = {
{ "tunnel", MODE_TUNNEL },
{ "transport", MODE_TRANSPORT },
{ "beet", MODE_BEET },
{ "drop", MODE_DROP },
{ "pass", MODE_PASS },
{ "tunnel", MODE_TUNNEL },
{ "transport", MODE_TRANSPORT },
{ "transport_proxy", MODE_TRANSPORT },
{ "beet", MODE_BEET },
{ "drop", MODE_DROP },
{ "pass", MODE_PASS },
};
int d;
if (parse_map(map, countof(map), &d, v))
{
*out = d;
cfg->mode = d;
cfg->proxy_mode = (d == MODE_TRANSPORT) && (v.len > 9);
return TRUE;
}
return FALSE;
@@ -814,10 +858,9 @@ CALLBACK(parse_action, bool,
}
/**
* Parse a uint32_t
* Parse a uint32_t with the given base
*/
CALLBACK(parse_uint32, bool,
uint32_t *out, chunk_t v)
static bool parse_uint32_base(uint32_t *out, chunk_t v, int base)
{
char buf[16], *end;
u_long l;
@@ -826,7 +869,7 @@ CALLBACK(parse_uint32, bool,
{
return FALSE;
}
l = strtoul(buf, &end, 0);
l = strtoul(buf, &end, base);
if (*end == 0)
{
*out = l;
@@ -835,6 +878,24 @@ CALLBACK(parse_uint32, bool,
return FALSE;
}
/**
* Parse a uint32_t
*/
CALLBACK(parse_uint32, bool,
uint32_t *out, chunk_t v)
{
return parse_uint32_base(out, v, 0);
}
/**
* Parse a uint32_t in binary encoding
*/
CALLBACK(parse_uint32_bin, bool,
uint32_t *out, chunk_t v)
{
return parse_uint32_base(out, v, 2);
}
/**
* Parse a uint64_t
*/
@@ -983,6 +1044,20 @@ CALLBACK(parse_tfc, bool,
return parse_uint32(out, v);
}
/**
* Parse 6-bit DSCP value
*/
CALLBACK(parse_dscp, bool,
uint8_t *out, chunk_t v)
{
if (parse_uint32_bin(out, v))
{
*out = *out & 0x3f;
return TRUE;
}
return FALSE;
}
/**
* Parse authentication config
*/
@@ -1108,28 +1183,53 @@ CALLBACK(parse_group, bool,
return parse_id(cfg, AUTH_RULE_GROUP, v);
}
/**
* Parse certificate policy
*/
CALLBACK(parse_cert_policy, bool,
auth_cfg_t *cfg, chunk_t v)
{
char buf[BUF_LEN];
if (!vici_stringify(v, buf, sizeof(buf)))
{
return FALSE;
}
cfg->add(cfg, AUTH_RULE_CERT_POLICY, strdup(buf));
return TRUE;
}
/**
* Add a certificate as auth rule to config
*/
static bool add_cert(auth_data_t *auth, auth_rule_t rule, certificate_t *cert)
{
vici_authority_t *authority;
vici_cred_t *cred;
if (rule == AUTH_RULE_SUBJECT_CERT)
{
authority = auth->request->this->authority;
authority->check_for_hash_and_url(authority, cert);
}
cred = auth->request->this->cred;
cert = cred->add_cert(cred, cert);
auth->cfg->add(auth->cfg, rule, cert);
return TRUE;
}
/**
* Parse a certificate; add as auth rule to config
*/
static bool parse_cert(auth_data_t *auth, auth_rule_t rule, chunk_t v)
{
vici_authority_t *authority;
vici_cred_t *cred;
certificate_t *cert;
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_BLOB_PEM, v, BUILD_END);
if (cert)
{
if (rule == AUTH_RULE_SUBJECT_CERT)
{
authority = auth->request->this->authority;
authority->check_for_hash_and_url(authority, cert);
}
cred = auth->request->this->cred;
cert = cred->add_cert(cred, cert);
auth->cfg->add(auth->cfg, rule, cert);
return TRUE;
return add_cert(auth, rule, cert);
}
return FALSE;
}
@@ -1314,6 +1414,38 @@ CALLBACK(parse_hosts, bool,
return TRUE;
}
#ifdef ME
/**
* Parse peer ID
*/
CALLBACK(parse_peer_id, bool,
identification_t **out, chunk_t v)
{
char buf[BUF_LEN];
if (!vici_stringify(v, buf, sizeof(buf)))
{
return FALSE;
}
*out = identification_create_from_string(buf);
return TRUE;
}
#endif /* ME */
CALLBACK(cert_kv, bool,
cert_data_t *cert, vici_message_t *message, char *name, chunk_t value)
{
parse_rule_t rules[] = {
{ "handle", parse_string, &cert->handle },
{ "slot", parse_uint32, &cert->slot },
{ "module", parse_string, &cert->module },
{ "file", parse_string, &cert->file },
};
return parse_rules(rules, countof(rules), name, value,
&cert->request->reply);
}
CALLBACK(child_li, bool,
child_data_t *child, vici_message_t *message, char *name, chunk_t value)
{
@@ -1334,7 +1466,7 @@ CALLBACK(child_kv, bool,
parse_rule_t rules[] = {
{ "updown", parse_string, &child->cfg.updown },
{ "hostaccess", parse_bool, &child->cfg.hostaccess },
{ "mode", parse_mode, &child->cfg.mode },
{ "mode", parse_mode, &child->cfg },
{ "policies", parse_bool, &child->policies },
{ "policies_fwd_out", parse_bool, &child->policies_fwd_out },
{ "replay_window", parse_uint32, &child->replay_window },
@@ -1369,6 +1501,7 @@ CALLBACK(auth_li, bool,
{
parse_rule_t rules[] = {
{ "groups", parse_group, auth->cfg },
{ "cert_policy", parse_cert_policy, auth },
{ "certs", parse_certs, auth },
{ "cacerts", parse_cacerts, auth },
{ "pubkeys", parse_pubkeys, auth },
@@ -1417,6 +1550,7 @@ CALLBACK(peer_kv, bool,
{ "version", parse_uint32, &peer->version },
{ "aggressive", parse_bool, &peer->aggressive },
{ "pull", parse_bool, &peer->pull },
{ "dscp", parse_dscp, &peer->dscp },
{ "encap", parse_bool, &peer->encap },
{ "mobike", parse_bool, &peer->mobike },
{ "dpd_delay", parse_time, &peer->dpd_delay },
@@ -1432,12 +1566,94 @@ CALLBACK(peer_kv, bool,
{ "rekey_time", parse_time, &peer->rekey_time },
{ "over_time", parse_time, &peer->over_time },
{ "rand_time", parse_time, &peer->rand_time },
#ifdef ME
{ "mediation", parse_bool, &peer->mediation },
{ "mediated_by", parse_string, &peer->mediated_by },
{ "mediation_peer", parse_peer_id, &peer->peer_id },
#endif /* ME */
};
return parse_rules(rules, countof(rules), name, value,
&peer->request->reply);
}
CALLBACK(auth_sn, bool,
auth_data_t *auth, vici_message_t *message, vici_parse_context_t *ctx,
char *name)
{
if (strcasepfx(name, "cert") ||
strcasepfx(name, "cacert"))
{
cert_data_t *data;
auth_rule_t rule;
certificate_t *cert;
chunk_t handle;
INIT(data,
.request = auth->request,
.slot = -1,
);
if (!message->parse(message, ctx, NULL, cert_kv, NULL, data))
{
free_cert_data(data);
return FALSE;
}
if (!data->handle && !data->file)
{
auth->request->reply = create_reply("handle or file path missing: "
"%s", name);
free_cert_data(data);
return FALSE;
}
else if (data->handle && data->file)
{
auth->request->reply = create_reply("handle and file path given: "
"%s", name);
free_cert_data(data);
return FALSE;
}
if (data->file)
{
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_FROM_FILE, data->file, BUILD_END);
}
else
{
handle = chunk_from_hex(chunk_from_str(data->handle), NULL);
if (data->slot != -1)
{
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
CERT_X509, BUILD_PKCS11_KEYID, handle,
BUILD_PKCS11_SLOT, data->slot,
data->module ? BUILD_PKCS11_MODULE : BUILD_END,
data->module, BUILD_END);
}
else
{
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
CERT_X509, BUILD_PKCS11_KEYID, handle,
data->module ? BUILD_PKCS11_MODULE : BUILD_END,
data->module, BUILD_END);
}
chunk_free(&handle);
}
free_cert_data(data);
if (!cert)
{
auth->request->reply = create_reply("unable to load certificate: "
"%s", name);
return FALSE;
}
rule = strcasepfx(name, "cert") ? AUTH_RULE_SUBJECT_CERT
: AUTH_RULE_CA_CERT;
return add_cert(auth, rule, cert);
}
auth->request->reply = create_reply("invalid section: %s", name);
return FALSE;
}
/**
* Check and update lifetimes
*/
@@ -1600,7 +1816,7 @@ CALLBACK(peer_sn, bool,
.cfg = auth_cfg_create(),
);
if (!message->parse(message, ctx, NULL, auth_kv, auth_li, auth))
if (!message->parse(message, ctx, auth_sn, auth_kv, auth_li, auth))
{
free_auth_data(auth);
return FALSE;
@@ -1703,7 +1919,8 @@ static void run_start_action(private_vici_config_t *this, peer_cfg_t *peer_cfg,
{
case MODE_PASS:
case MODE_DROP:
charon->shunts->install(charon->shunts, child_cfg);
charon->shunts->install(charon->shunts,
peer_cfg->get_name(peer_cfg), child_cfg);
break;
default:
charon->traps->install(charon->traps, peer_cfg, child_cfg,
@@ -1724,6 +1941,7 @@ static void clear_start_action(private_vici_config_t *this, char *peer_name,
{
enumerator_t *enumerator, *children;
child_sa_t *child_sa;
peer_cfg_t *peer_cfg;
ike_sa_t *ike_sa;
uint32_t id = 0, others;
array_t *ids = NULL, *ikeids = NULL;
@@ -1811,13 +2029,15 @@ static void clear_start_action(private_vici_config_t *this, char *peer_name,
{
case MODE_PASS:
case MODE_DROP:
charon->shunts->uninstall(charon->shunts, name);
charon->shunts->uninstall(charon->shunts, peer_name, name);
break;
default:
enumerator = charon->traps->create_enumerator(charon->traps);
while (enumerator->enumerate(enumerator, NULL, &child_sa))
while (enumerator->enumerate(enumerator, &peer_cfg,
&child_sa))
{
if (streq(name, child_sa->get_name(child_sa)))
if (streq(peer_name, peer_cfg->get_name(peer_cfg)) &&
streq(name, child_sa->get_name(child_sa)))
{
id = child_sa->get_reqid(child_sa);
break;
@@ -2080,12 +2300,48 @@ CALLBACK(config_sn, bool,
peer.rand_time = min(peer.over_time, peer.rand_time / 2);
}
#ifdef ME
if (peer.mediation && peer.mediated_by)
{
DBG1(DBG_CFG, "a mediation connection cannot be a mediated connection "
"at the same time, config discarded");
free_peer_data(&peer);
return FALSE;
}
if (peer.mediation)
{ /* force unique connections for mediation connections */
peer.unique = UNIQUE_REPLACE;
}
else if (peer.mediated_by)
{ /* fallback to remote identity of first auth round if peer_id is not
* given explicitly */
auth_cfg_t *cfg;
if (!peer.peer_id &&
peer.remote->get_first(peer.remote, (void**)&cfg) == SUCCESS)
{
peer.peer_id = cfg->get(cfg, AUTH_RULE_IDENTITY);
if (peer.peer_id)
{
peer.peer_id = peer.peer_id->clone(peer.peer_id);
}
else
{
DBG1(DBG_CFG, "mediation peer missing for mediated connection, "
"config discarded");
free_peer_data(&peer);
return FALSE;
}
}
}
#endif /* ME */
log_peer_data(&peer);
ike_cfg = ike_cfg_create(peer.version, peer.send_certreq, peer.encap,
peer.local_addrs, peer.local_port,
peer.remote_addrs, peer.remote_port,
peer.fragmentation, 0);
peer.fragmentation, peer.dscp);
cfg = (peer_cfg_create_t){
.cert_policy = peer.send_cert,
@@ -2101,6 +2357,14 @@ CALLBACK(config_sn, bool,
.dpd = peer.dpd_delay,
.dpd_timeout = peer.dpd_timeout,
};
#ifdef ME
cfg.mediation = peer.mediation;
if (peer.mediated_by)
{
cfg.mediated_by = peer.mediated_by;
cfg.peer_id = peer.peer_id->clone(peer.peer_id);
}
#endif /* ME */
peer_cfg = peer_cfg_create(name, ike_cfg, &cfg);
while (peer.local->remove_first(peer.local,
+129 -7
View File
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
* Copyright (C) 2015-2017 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
@@ -23,6 +23,8 @@
#include <daemon.h>
#include <collections/array.h>
#include <processing/jobs/rekey_ike_sa_job.h>
#include <processing/jobs/rekey_child_sa_job.h>
#include <processing/jobs/redirect_job.h>
typedef struct private_vici_control_t private_vici_control_t;
@@ -360,6 +362,100 @@ CALLBACK(terminate, vici_message_t*,
return builder->finalize(builder);
}
CALLBACK(rekey, vici_message_t*,
private_vici_control_t *this, char *name, u_int id, vici_message_t *request)
{
enumerator_t *isas, *csas;
char *child, *ike, *errmsg = NULL;
u_int child_id, ike_id, found = 0;
ike_sa_t *ike_sa;
child_sa_t *child_sa;
vici_builder_t *builder;
child = request->get_str(request, NULL, "child");
ike = request->get_str(request, NULL, "ike");
child_id = request->get_int(request, 0, "child-id");
ike_id = request->get_int(request, 0, "ike-id");
if (!child && !ike && !ike_id && !child_id)
{
return send_reply(this, "missing rekey selector");
}
if (ike_id)
{
DBG1(DBG_CFG, "vici rekey IKE_SA #%d", ike_id);
}
if (child_id)
{
DBG1(DBG_CFG, "vici rekey CHILD_SA #%d", child_id);
}
if (ike)
{
DBG1(DBG_CFG, "vici rekey IKE_SA '%s'", ike);
}
if (child)
{
DBG1(DBG_CFG, "vici rekey CHILD_SA '%s'", child);
}
isas = charon->controller->create_ike_sa_enumerator(charon->controller, TRUE);
while (isas->enumerate(isas, &ike_sa))
{
if (child || child_id)
{
if (ike && !streq(ike, ike_sa->get_name(ike_sa)))
{
continue;
}
if (ike_id && ike_id != ike_sa->get_unique_id(ike_sa))
{
continue;
}
csas = ike_sa->create_child_sa_enumerator(ike_sa);
while (csas->enumerate(csas, &child_sa))
{
if (child && !streq(child, child_sa->get_name(child_sa)))
{
continue;
}
if (child_id && child_sa->get_unique_id(child_sa) != child_id)
{
continue;
}
lib->processor->queue_job(lib->processor,
(job_t*)rekey_child_sa_job_create(
child_sa->get_protocol(child_sa),
child_sa->get_spi(child_sa, TRUE),
ike_sa->get_my_host(ike_sa)));
found++;
}
csas->destroy(csas);
}
else if ((ike && streq(ike, ike_sa->get_name(ike_sa))) ||
(ike_id && ike_id == ike_sa->get_unique_id(ike_sa)))
{
lib->processor->queue_job(lib->processor,
(job_t*)rekey_ike_sa_job_create(ike_sa->get_id(ike_sa), FALSE));
found++;
}
}
isas->destroy(isas);
builder = vici_builder_create();
if (!found)
{
errmsg = "no matching SAs to rekey found";
}
builder->add_kv(builder, "success", errmsg ? "no" : "yes");
builder->add_kv(builder, "matches", "%u", found);
if (errmsg)
{
builder->add_kv(builder, "errmsg", "%s", errmsg);
}
return builder->finalize(builder);
}
/**
* Parse a peer-ip specified, which can be a subnet in CIDR notation, a range
* or a single IP address.
@@ -494,6 +590,7 @@ CALLBACK(redirect, vici_message_t*,
errmsg = "no matching SAs to redirect found";
}
builder->add_kv(builder, "success", errmsg ? "no" : "yes");
builder->add_kv(builder, "matches", "%u", found);
if (errmsg)
{
builder->add_kv(builder, "errmsg", "%s", errmsg);
@@ -565,7 +662,8 @@ CALLBACK(install, vici_message_t*,
{
case MODE_PASS:
case MODE_DROP:
ok = charon->shunts->install(charon->shunts, child_cfg);
ok = charon->shunts->install(charon->shunts,
peer_cfg->get_name(peer_cfg), child_cfg);
break;
default:
ok = charon->traps->install(charon->traps, peer_cfg, child_cfg,
@@ -581,12 +679,15 @@ CALLBACK(install, vici_message_t*,
CALLBACK(uninstall, vici_message_t*,
private_vici_control_t *this, char *name, u_int id, vici_message_t *request)
{
peer_cfg_t *peer_cfg;
child_cfg_t *child_cfg;
child_sa_t *child_sa;
enumerator_t *enumerator;
uint32_t reqid = 0;
char *child;
char *child, *ike, *ns;
child = request->get_str(request, NULL, "child");
ike = request->get_str(request, NULL, "ike");
if (!child)
{
return send_reply(this, "missing configuration name");
@@ -594,15 +695,35 @@ CALLBACK(uninstall, vici_message_t*,
DBG1(DBG_CFG, "vici uninstall '%s'", child);
if (charon->shunts->uninstall(charon->shunts, child))
if (!ike)
{
enumerator = charon->shunts->create_enumerator(charon->shunts);
while (enumerator->enumerate(enumerator, &ns, &child_cfg))
{
if (ns && streq(child, child_cfg->get_name(child_cfg)))
{
ike = strdup(ns);
break;
}
}
enumerator->destroy(enumerator);
if (ike && charon->shunts->uninstall(charon->shunts, ike, child))
{
free(ike);
return send_reply(this, NULL);
}
free(ike);
}
else if (charon->shunts->uninstall(charon->shunts, ike, child))
{
return send_reply(this, NULL);
}
enumerator = charon->traps->create_enumerator(charon->traps);
while (enumerator->enumerate(enumerator, NULL, &child_sa))
while (enumerator->enumerate(enumerator, &peer_cfg, &child_sa))
{
if (streq(child, child_sa->get_name(child_sa)))
if ((!ike || streq(ike, peer_cfg->get_name(peer_cfg))) &&
streq(child, child_sa->get_name(child_sa)))
{
reqid = child_sa->get_reqid(child_sa);
break;
@@ -647,6 +768,7 @@ static void manage_commands(private_vici_control_t *this, bool reg)
{
manage_command(this, "initiate", initiate, reg);
manage_command(this, "terminate", terminate, reg);
manage_command(this, "rekey", rekey, reg);
manage_command(this, "redirect", redirect, reg);
manage_command(this, "install", install, reg);
manage_command(this, "uninstall", uninstall, reg);
+204 -6
View File
@@ -1,9 +1,11 @@
/*
* Copyright (C) 2015-2016 Andreas Steffen
* Copyright (C) 2016 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
*
* Copyright (C) 2015-2016 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -54,6 +56,11 @@ struct private_vici_cred_t {
*/
mem_cred_t *creds;
/**
* separate credential set for token PINs
*/
mem_cred_t *pins;
/**
* cache CRLs to disk?
*/
@@ -249,6 +256,139 @@ CALLBACK(load_key, vici_message_t*,
return create_reply(NULL);
}
CALLBACK(unload_key, vici_message_t*,
private_vici_cred_t *this, char *name, u_int id, vici_message_t *message)
{
chunk_t keyid;
char buf[BUF_LEN], *hex, *msg = NULL;
hex = message->get_str(message, NULL, "id");
if (!hex)
{
return create_reply("key id missing");
}
keyid = chunk_from_hex(chunk_from_str(hex), NULL);
snprintf(buf, sizeof(buf), "%+B", &keyid);
DBG1(DBG_CFG, "unloaded private key with id %s", buf);
if (this->creds->remove_key(this->creds, keyid))
{ /* also remove any potential PIN associated with this id */
this->pins->remove_shared_unique(this->pins, buf);
}
else
{
msg = "key not found";
}
chunk_free(&keyid);
return create_reply(msg);
}
CALLBACK(get_keys, vici_message_t*,
private_vici_cred_t *this, char *name, u_int id, vici_message_t *message)
{
vici_builder_t *builder;
enumerator_t *enumerator;
private_key_t *private;
chunk_t keyid;
builder = vici_builder_create();
builder->begin_list(builder, "keys");
enumerator = this->creds->set.create_private_enumerator(&this->creds->set,
KEY_ANY, NULL);
while (enumerator->enumerate(enumerator, &private))
{
if (private->get_fingerprint(private, KEYID_PUBKEY_SHA1, &keyid))
{
builder->add_li(builder, "%+B", &keyid);
}
}
enumerator->destroy(enumerator);
builder->end_list(builder);
return builder->finalize(builder);
}
CALLBACK(load_token, vici_message_t*,
private_vici_cred_t *this, char *name, u_int id, vici_message_t *message)
{
vici_builder_t *builder;
private_key_t *key;
shared_key_t *shared = NULL;
identification_t *owner;
mem_cred_t *set = NULL;
chunk_t handle, fp;
char buf[BUF_LEN], *hex, *module, *pin, *unique = NULL;
int slot;
hex = message->get_str(message, NULL, "handle");
if (!hex)
{
return create_reply("keyid missing");
}
handle = chunk_from_hex(chunk_from_str(hex), NULL);
slot = message->get_int(message, -1, "slot");
module = message->get_str(message, NULL, "module");
pin = message->get_str(message, NULL, "pin");
if (pin)
{ /* provide the pin in a temporary credential set to access the key */
shared = shared_key_create(SHARED_PIN, chunk_clone(chunk_from_str(pin)));
owner = identification_create_from_encoding(ID_KEY_ID, handle);
set = mem_cred_create();
set->add_shared(set, shared->get_ref(shared), owner, NULL);
lib->credmgr->add_local_set(lib->credmgr, &set->set, FALSE);
}
if (slot >= 0)
{
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
BUILD_PKCS11_KEYID, handle,
BUILD_PKCS11_SLOT, slot,
module ? BUILD_PKCS11_MODULE : BUILD_END, module,
BUILD_END);
}
else
{
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
BUILD_PKCS11_KEYID, handle,
module ? BUILD_PKCS11_MODULE : BUILD_END, module,
BUILD_END);
}
if (set)
{
lib->credmgr->remove_local_set(lib->credmgr, &set->set);
set->destroy(set);
}
if (!key)
{
chunk_free(&handle);
DESTROY_IF(shared);
return create_reply("loading private key from token failed");
}
builder = vici_builder_create();
builder->add_kv(builder, "success", "yes");
if (key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fp))
{
snprintf(buf, sizeof(buf), "%+B", &fp);
builder->add_kv(builder, "id", "%s", buf);
unique = buf;
}
if (shared && unique)
{ /* use the handle as owner, but the key identifier as unique ID */
owner = identification_create_from_encoding(ID_KEY_ID, handle);
this->pins->add_shared_unique(this->pins, unique, shared,
linked_list_create_with_items(owner, NULL));
}
else
{
DESTROY_IF(shared);
}
DBG1(DBG_CFG, "loaded %N private key from token", key_type_names,
key->get_type(key));
this->creds->add_key(this->creds, key);
chunk_free(&handle);
return builder->finalize(builder);
}
CALLBACK(shared_owners, bool,
linked_list_t *owners, vici_message_t *message, char *name, chunk_t value)
{
@@ -271,11 +411,12 @@ CALLBACK(load_shared, vici_message_t*,
shared_key_type_t type;
linked_list_t *owners;
chunk_t data;
char *str, buf[512] = "";
char *unique, *str, buf[512] = "";
enumerator_t *enumerator;
identification_t *owner;
int len;
unique = message->get_str(message, NULL, "id");
str = message->get_str(message, NULL, "type");
if (!str)
{
@@ -289,6 +430,10 @@ CALLBACK(load_shared, vici_message_t*,
{
type = SHARED_EAP;
}
else if (strcaseeq(str, "ntlm"))
{
type = SHARED_NT_HASH;
}
else
{
return create_reply("invalid shared key type: %s", str);
@@ -322,15 +467,59 @@ CALLBACK(load_shared, vici_message_t*,
}
enumerator->destroy(enumerator);
DBG1(DBG_CFG, "loaded %N shared key for: %s",
shared_key_type_names, type, buf);
if (unique)
{
DBG1(DBG_CFG, "loaded %N shared key with id '%s' for: %s",
shared_key_type_names, type, unique, buf);
}
else
{
DBG1(DBG_CFG, "loaded %N shared key for: %s",
shared_key_type_names, type, buf);
}
this->creds->add_shared_list(this->creds,
this->creds->add_shared_unique(this->creds, unique,
shared_key_create(type, chunk_clone(data)), owners);
return create_reply(NULL);
}
CALLBACK(unload_shared, vici_message_t*,
private_vici_cred_t *this, char *name, u_int id, vici_message_t *message)
{
char *unique;
unique = message->get_str(message, NULL, "id");
if (!unique)
{
return create_reply("unique identifier missing");
}
DBG1(DBG_CFG, "unloaded shared key with id '%s'", unique);
this->creds->remove_shared_unique(this->creds, unique);
return create_reply(NULL);
}
CALLBACK(get_shared, vici_message_t*,
private_vici_cred_t *this, char *name, u_int id, vici_message_t *message)
{
vici_builder_t *builder;
enumerator_t *enumerator;
char *unique;
builder = vici_builder_create();
builder->begin_list(builder, "keys");
enumerator = this->creds->create_unique_shared_enumerator(this->creds);
while (enumerator->enumerate(enumerator, &unique))
{
builder->add_li(builder, "%s", unique);
}
enumerator->destroy(enumerator);
builder->end_list(builder);
return builder->finalize(builder);
}
CALLBACK(clear_creds, vici_message_t*,
private_vici_cred_t *this, char *name, u_int id, vici_message_t *message)
{
@@ -374,7 +563,12 @@ static void manage_commands(private_vici_cred_t *this, bool reg)
manage_command(this, "flush-certs", flush_certs, reg);
manage_command(this, "load-cert", load_cert, reg);
manage_command(this, "load-key", load_key, reg);
manage_command(this, "unload-key", unload_key, reg);
manage_command(this, "get-keys", get_keys, reg);
manage_command(this, "load-token", load_token, reg);
manage_command(this, "load-shared", load_shared, reg);
manage_command(this, "unload-shared", unload_shared, reg);
manage_command(this, "get-shared", get_shared, reg);
}
METHOD(vici_cred_t, add_cert, certificate_t*,
@@ -390,6 +584,8 @@ METHOD(vici_cred_t, destroy, void,
lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
this->creds->destroy(this->creds);
lib->credmgr->remove_set(lib->credmgr, &this->pins->set);
this->pins->destroy(this->pins);
free(this);
}
@@ -414,6 +610,7 @@ vici_cred_t *vici_cred_create(vici_dispatcher_t *dispatcher)
},
.dispatcher = dispatcher,
.creds = mem_cred_create(),
.pins = mem_cred_create(),
);
if (lib->settings->get_bool(lib->settings, "%s.cache_crls", FALSE, lib->ns))
@@ -422,6 +619,7 @@ vici_cred_t *vici_cred_create(vici_dispatcher_t *dispatcher)
DBG1(DBG_CFG, "crl caching to %s enabled", CRL_DIR);
}
lib->credmgr->add_set(lib->credmgr, &this->creds->set);
lib->credmgr->add_set(lib->credmgr, &this->pins->set);
manage_commands(this, TRUE);
+4 -2
View File
@@ -471,15 +471,17 @@ METHOD(vici_dispatcher_t, manage_event, void,
METHOD(vici_dispatcher_t, has_event_listeners, bool,
private_vici_dispatcher_t *this, char *name)
{
event_t *event;
bool retval = FALSE;
this->mutex->lock(this->mutex);
if (this->events->get(this->events, name))
event = this->events->get(this->events, name);
if (event)
{
/* the entry might be getting destroyed, but returning
* false positive is not a problem as a later raise_event
* will check things again. */
retval = TRUE;
retval = array_count(event->clients);
}
this->mutex->unlock(this->mutex);
+7
View File
@@ -95,6 +95,11 @@ METHOD(logger_t, log_, void,
private_vici_logger_t *this, debug_t group, level_t level, int thread,
ike_sa_t* ike_sa, const char *msg)
{
if (!this->dispatcher->has_event_listeners(this->dispatcher, "log"))
{
return;
}
this->mutex->lock(this->mutex);
/* avoid recursive invocations by the vici subsystem */
@@ -130,6 +135,8 @@ METHOD(logger_t, log_, void,
METHOD(logger_t, get_level, level_t,
private_vici_logger_t *this, debug_t group)
{
/* anything higher might produce a loop as sending messages or listening
* for clients might cause log messages itself */
return LEVEL_CTRL;
}
+63 -18
View File
@@ -92,6 +92,29 @@ static void add_mark(vici_builder_t *b, mark_t mark,
}
}
/**
* List the mode of a CHILD_SA or config
*/
static void list_mode(vici_builder_t *b, child_sa_t *child, child_cfg_t *cfg)
{
ipsec_mode_t mode;
char *sub_mode = "";
if (child || cfg)
{
if (!cfg)
{
cfg = child->get_config(child);
}
mode = child ? child->get_mode(child) : cfg->get_mode(cfg);
if (mode == MODE_TRANSPORT && cfg->use_proxy_mode(cfg))
{ /* only report this if the negotiated mode is actually TRANSPORT */
sub_mode = "_PROXY";
}
b->add_kv(b, "mode", "%N%s", ipsec_mode_names, mode, sub_mode);
}
}
/**
* List details of a CHILD_SA
*/
@@ -105,10 +128,11 @@ static void list_child(private_vici_query_t *this, vici_builder_t *b,
enumerator_t *enumerator;
traffic_selector_t *ts;
b->add_kv(b, "name", "%s", child->get_name(child));
b->add_kv(b, "uniqueid", "%u", child->get_unique_id(child));
b->add_kv(b, "reqid", "%u", child->get_reqid(child));
b->add_kv(b, "state", "%N", child_sa_state_names, child->get_state(child));
b->add_kv(b, "mode", "%N", ipsec_mode_names, child->get_mode(child));
list_mode(b, child, NULL);
if (child->get_state(child) == CHILD_INSTALLED ||
child->get_state(child) == CHILD_REKEYING ||
child->get_state(child) == CHILD_REKEYED)
@@ -397,6 +421,7 @@ CALLBACK(list_sas, vici_message_t*,
char *ike;
u_int ike_id;
bool bl;
char buf[BUF_LEN];
bl = request->get_str(request, NULL, "noblock") == NULL;
ike = request->get_str(request, NULL, "ike");
@@ -425,7 +450,9 @@ CALLBACK(list_sas, vici_message_t*,
csas = ike_sa->create_child_sa_enumerator(ike_sa);
while (csas->enumerate(csas, &child_sa))
{
b->begin_section(b, child_sa->get_name(child_sa));
snprintf(buf, sizeof(buf), "%s-%u", child_sa->get_name(child_sa),
child_sa->get_unique_id(child_sa));
b->begin_section(b, buf);
list_child(this, b, child_sa, now);
b->end_section(b);
}
@@ -446,16 +473,21 @@ CALLBACK(list_sas, vici_message_t*,
/**
* Raise a list-policy event for given CHILD_SA
*/
static void raise_policy(private_vici_query_t *this, u_int id, child_sa_t *child)
static void raise_policy(private_vici_query_t *this, u_int id, char *ike,
child_sa_t *child)
{
enumerator_t *enumerator;
traffic_selector_t *ts;
vici_builder_t *b;
char buf[BUF_LEN];
b = vici_builder_create();
b->begin_section(b, child->get_name(child));
snprintf(buf, sizeof(buf), "%s/%s", ike, child->get_name(child));
b->begin_section(b, buf);
b->add_kv(b, "child", "%s", child->get_name(child));
b->add_kv(b, "ike", "%s", ike);
b->add_kv(b, "mode", "%N", ipsec_mode_names, child->get_mode(child));
list_mode(b, child, NULL);
b->begin_list(b, "local-ts");
enumerator = child->create_ts_enumerator(child, TRUE);
@@ -484,18 +516,26 @@ static void raise_policy(private_vici_query_t *this, u_int id, child_sa_t *child
/**
* Raise a list-policy event for given CHILD_SA config
*/
static void raise_policy_cfg(private_vici_query_t *this, u_int id,
static void raise_policy_cfg(private_vici_query_t *this, u_int id, char *ike,
child_cfg_t *cfg)
{
enumerator_t *enumerator;
linked_list_t *list;
traffic_selector_t *ts;
vici_builder_t *b;
char buf[BUF_LEN];
b = vici_builder_create();
b->begin_section(b, cfg->get_name(cfg));
snprintf(buf, sizeof(buf), "%s%s%s", ike ? ike : "", ike ? "/" : "",
cfg->get_name(cfg));
b->begin_section(b, buf);
b->add_kv(b, "child", "%s", cfg->get_name(cfg));
if (ike)
{
b->add_kv(b, "ike", "%s", ike);
}
b->add_kv(b, "mode", "%N", ipsec_mode_names, cfg->get_mode(cfg));
list_mode(b, NULL, cfg);
b->begin_list(b, "local-ts");
list = cfg->get_traffic_selectors(cfg, TRUE, NULL, NULL);
@@ -531,25 +571,28 @@ CALLBACK(list_policies, vici_message_t*,
enumerator_t *enumerator;
vici_builder_t *b;
child_sa_t *child_sa;
peer_cfg_t *peer_cfg;
child_cfg_t *child_cfg;
bool drop, pass, trap;
char *child;
char *child, *ike, *ns;
drop = request->get_str(request, NULL, "drop") != NULL;
pass = request->get_str(request, NULL, "pass") != NULL;
trap = request->get_str(request, NULL, "trap") != NULL;
child = request->get_str(request, NULL, "child");
ike = request->get_str(request, NULL, "ike");
if (trap)
{
enumerator = charon->traps->create_enumerator(charon->traps);
while (enumerator->enumerate(enumerator, NULL, &child_sa))
while (enumerator->enumerate(enumerator, &peer_cfg, &child_sa))
{
if (child && !streq(child, child_sa->get_name(child_sa)))
if ((ike && !streq(ike, peer_cfg->get_name(peer_cfg))) ||
(child && !streq(child, child_sa->get_name(child_sa))))
{
continue;
}
raise_policy(this, id, child_sa);
raise_policy(this, id, peer_cfg->get_name(peer_cfg), child_sa);
}
enumerator->destroy(enumerator);
}
@@ -557,9 +600,10 @@ CALLBACK(list_policies, vici_message_t*,
if (drop || pass)
{
enumerator = charon->shunts->create_enumerator(charon->shunts);
while (enumerator->enumerate(enumerator, &child_cfg))
while (enumerator->enumerate(enumerator, &ns, &child_cfg))
{
if (child && !streq(child, child_cfg->get_name(child_cfg)))
if ((ike && !streq(ike, ns)) ||
(child && !streq(child, child_cfg->get_name(child_cfg))))
{
continue;
}
@@ -568,13 +612,13 @@ CALLBACK(list_policies, vici_message_t*,
case MODE_DROP:
if (drop)
{
raise_policy_cfg(this, id, child_cfg);
raise_policy_cfg(this, id, ns, child_cfg);
}
break;
case MODE_PASS:
if (pass)
{
raise_policy_cfg(this, id, child_cfg);
raise_policy_cfg(this, id, ns, child_cfg);
}
break;
default:
@@ -746,6 +790,8 @@ CALLBACK(list_conns, vici_message_t*,
peer_cfg->get_reauth_time(peer_cfg, FALSE));
b->add_kv(b, "rekey_time", "%u",
peer_cfg->get_rekey_time(peer_cfg, FALSE));
b->add_kv(b, "unique", "%N", unique_policy_names,
peer_cfg->get_unique_policy(peer_cfg));
build_auth_cfgs(peer_cfg, TRUE, b);
build_auth_cfgs(peer_cfg, FALSE, b);
@@ -757,8 +803,7 @@ CALLBACK(list_conns, vici_message_t*,
{
b->begin_section(b, child_cfg->get_name(child_cfg));
b->add_kv(b, "mode", "%N", ipsec_mode_names,
child_cfg->get_mode(child_cfg));
list_mode(b, NULL, child_cfg);
lft = child_cfg->get_lifetime(child_cfg, FALSE);
b->add_kv(b, "rekey_time", "%"PRIu64, lft->time.rekey);
@@ -82,8 +82,25 @@ METHOD(job_t, initiate, job_requeue_t,
charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa);
mediation_cfg = mediated_cfg->get_mediated_by(mediated_cfg);
mediation_cfg->get_ref(mediation_cfg);
mediation_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
mediated_cfg->get_mediated_by(mediated_cfg));
if (!mediation_cfg)
{
DBG1(DBG_IKE, "mediation connection '%s' not found, aborting",
mediated_cfg->get_mediated_by(mediated_cfg));
mediated_cfg->destroy(mediated_cfg);
return JOB_REQUEUE_NONE;
}
if (!mediation_cfg->is_mediation(mediation_cfg))
{
DBG1(DBG_CFG, "connection '%s' as referred to by '%s' is no "
"mediation connection, aborting",
mediated_cfg->get_mediated_by(mediated_cfg),
mediated_cfg->get_name(mediated_cfg));
mediated_cfg->destroy(mediated_cfg);
mediation_cfg->destroy(mediation_cfg);
return JOB_REQUEUE_NONE;
}
enumerator = mediation_cfg->create_auth_cfg_enumerator(mediation_cfg,
TRUE);
@@ -68,7 +68,9 @@ METHOD(job_t, execute, job_requeue_t,
mode = child_cfg->get_mode(child_cfg);
if (mode == MODE_PASS || mode == MODE_DROP)
{
charon->shunts->install(charon->shunts, child_cfg);
charon->shunts->install(charon->shunts,
peer_cfg->get_name(peer_cfg),
child_cfg);
}
else
{
+67 -23
View File
@@ -36,7 +36,7 @@ struct private_shunt_manager_t {
shunt_manager_t public;
/**
* Installed shunts, as child_cfg_t
* Installed shunts, as entry_t
*/
linked_list_t *shunts;
@@ -56,6 +56,32 @@ struct private_shunt_manager_t {
rwlock_condvar_t *condvar;
};
/**
* Config entry for a shunt
*/
typedef struct {
/**
* Configured namespace
*/
char *ns;
/**
* Child config
*/
child_cfg_t *cfg;
} entry_t;
/**
* Destroy a config entry
*/
static void entry_destroy(entry_t *this)
{
this->cfg->destroy(this->cfg);
free(this->ns);
free(this);
}
/**
* Install in and out shunt policies in the kernel
*/
@@ -162,10 +188,10 @@ static bool install_shunt_policy(child_cfg_t *child)
}
METHOD(shunt_manager_t, install, bool,
private_shunt_manager_t *this, child_cfg_t *child)
private_shunt_manager_t *this, char *ns, child_cfg_t *cfg)
{
enumerator_t *enumerator;
child_cfg_t *child_cfg;
entry_t *entry;
bool found = FALSE, success;
/* check if not already installed */
@@ -176,9 +202,10 @@ METHOD(shunt_manager_t, install, bool,
return FALSE;
}
enumerator = this->shunts->create_enumerator(this->shunts);
while (enumerator->enumerate(enumerator, &child_cfg))
while (enumerator->enumerate(enumerator, &entry))
{
if (streq(child_cfg->get_name(child_cfg), child->get_name(child)))
if (streq(ns, entry->ns) &&
streq(cfg->get_name(cfg), entry->cfg->get_name(entry->cfg)))
{
found = TRUE;
break;
@@ -188,21 +215,25 @@ METHOD(shunt_manager_t, install, bool,
if (found)
{
DBG1(DBG_CFG, "shunt %N policy '%s' already installed",
ipsec_mode_names, child->get_mode(child), child->get_name(child));
ipsec_mode_names, cfg->get_mode(cfg), cfg->get_name(cfg));
this->lock->unlock(this->lock);
return TRUE;
}
this->shunts->insert_last(this->shunts, child->get_ref(child));
INIT(entry,
.ns = strdupnull(ns),
.cfg = cfg->get_ref(cfg),
);
this->shunts->insert_last(this->shunts, entry);
this->installing++;
this->lock->unlock(this->lock);
success = install_shunt_policy(child);
success = install_shunt_policy(cfg);
this->lock->write_lock(this->lock);
if (!success)
{
this->shunts->remove(this->shunts, child, NULL);
child->destroy(child);
this->shunts->remove(this->shunts, entry, NULL);
entry_destroy(entry);
}
this->installing--;
this->condvar->signal(this->condvar);
@@ -320,19 +351,20 @@ static void uninstall_shunt_policy(child_cfg_t *child)
}
METHOD(shunt_manager_t, uninstall, bool,
private_shunt_manager_t *this, char *name)
private_shunt_manager_t *this, char *ns, char *name)
{
enumerator_t *enumerator;
child_cfg_t *child, *found = NULL;
entry_t *entry, *found = NULL;
this->lock->write_lock(this->lock);
enumerator = this->shunts->create_enumerator(this->shunts);
while (enumerator->enumerate(enumerator, &child))
while (enumerator->enumerate(enumerator, &entry))
{
if (streq(name, child->get_name(child)))
if (streq(ns, entry->ns) &&
streq(name, entry->cfg->get_name(entry->cfg)))
{
this->shunts->remove_at(this->shunts, enumerator);
found = child;
found = entry;
break;
}
}
@@ -343,8 +375,19 @@ METHOD(shunt_manager_t, uninstall, bool,
{
return FALSE;
}
uninstall_shunt_policy(child);
child->destroy(child);
uninstall_shunt_policy(found->cfg);
entry_destroy(found);
return TRUE;
}
CALLBACK(filter_entries, bool,
void *unused, entry_t **entry, char **ns, void **in, child_cfg_t **cfg)
{
if (ns)
{
*ns = (*entry)->ns;
}
*cfg = (*entry)->cfg;
return TRUE;
}
@@ -352,25 +395,26 @@ METHOD(shunt_manager_t, create_enumerator, enumerator_t*,
private_shunt_manager_t *this)
{
this->lock->read_lock(this->lock);
return enumerator_create_cleaner(
return enumerator_create_filter(
this->shunts->create_enumerator(this->shunts),
(void*)this->lock->unlock, this->lock);
(void*)filter_entries, this->lock,
(void*)this->lock->unlock);
}
METHOD(shunt_manager_t, flush, void,
private_shunt_manager_t *this)
{
child_cfg_t *child;
entry_t *entry;
this->lock->write_lock(this->lock);
while (this->installing)
{
this->condvar->wait(this->condvar, this->lock);
}
while (this->shunts->remove_last(this->shunts, (void**)&child) == SUCCESS)
while (this->shunts->remove_last(this->shunts, (void**)&entry) == SUCCESS)
{
uninstall_shunt_policy(child);
child->destroy(child);
uninstall_shunt_policy(entry->cfg);
entry_destroy(entry);
}
this->installing = INSTALL_DISABLED;
this->lock->unlock(this->lock);
+8 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 Tobias Brunner
* Copyright (C) 2015-2016 Tobias Brunner
* Copyright (C) 2011 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
@@ -36,23 +36,26 @@ struct shunt_manager_t {
/**
* Install a policy as a shunt.
*
* @param child child configuration to install as a shunt
* @param ns optional namespace (e.g. name of a connection or
* plugin), cloned
* @param child child configuration to install as a shunt
* @return TRUE if installed successfully
*/
bool (*install)(shunt_manager_t *this, child_cfg_t *child);
bool (*install)(shunt_manager_t *this, char *ns, child_cfg_t *child);
/**
* Uninstall a shunt policy.
*
* @param ns namespace (same as given during installation)
* @param name name of child configuration to uninstall as a shunt
* @return TRUE if uninstalled successfully
*/
bool (*uninstall)(shunt_manager_t *this, char *name);
bool (*uninstall)(shunt_manager_t *this, char *ns, char *name);
/**
* Create an enumerator over all installed shunts.
*
* @return enumerator over (child_sa_t)
* @return enumerator over (char*, child_cfg_t*)
*/
enumerator_t* (*create_enumerator)(shunt_manager_t *this);
+107 -6
View File
@@ -370,14 +370,42 @@ METHOD(mem_cred_t, add_key, void,
this->lock->unlock(this->lock);
}
METHOD(mem_cred_t, remove_key, bool,
private_mem_cred_t *this, chunk_t fp)
{
enumerator_t *enumerator;
private_key_t *current;
bool found = FALSE;
this->lock->write_lock(this->lock);
enumerator = this->keys->create_enumerator(this->keys);
while (enumerator->enumerate(enumerator, &current))
{
if (current->has_fingerprint(current, fp))
{
this->keys->remove_at(this->keys, enumerator);
current->destroy(current);
found = TRUE;
break;
}
}
enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
return found;
}
/**
* Shared key entry
*/
typedef struct {
/* shared key */
/** shared key */
shared_key_t *shared;
/* list of owners, identification_t */
/** list of owners, identification_t */
linked_list_t *owners;
/** optional unique identifier */
char *id;
} shared_entry_t;
/**
@@ -388,11 +416,12 @@ static void shared_entry_destroy(shared_entry_t *entry)
entry->owners->destroy_offset(entry->owners,
offsetof(identification_t, destroy));
entry->shared->destroy(entry->shared);
free(entry->id);
free(entry);
}
/**
* Check if two shared key entries equal
* Check if two shared key entries are equal (ignoring the unique identifier)
*/
static bool shared_entry_equals(shared_entry_t *a, shared_entry_t *b)
{
@@ -528,8 +557,9 @@ METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
(void*)shared_filter, data, (void*)shared_data_destroy);
}
METHOD(mem_cred_t, add_shared_list, void,
private_mem_cred_t *this, shared_key_t *shared, linked_list_t* owners)
METHOD(mem_cred_t, add_shared_unique, void,
private_mem_cred_t *this, char *id, shared_key_t *shared,
linked_list_t* owners)
{
shared_entry_t *current, *new;
enumerator_t *enumerator;
@@ -537,6 +567,7 @@ METHOD(mem_cred_t, add_shared_list, void,
INIT(new,
.shared = shared,
.owners = owners,
.id = strdupnull(id),
);
this->lock->write_lock(this->lock);
@@ -544,7 +575,10 @@ METHOD(mem_cred_t, add_shared_list, void,
enumerator = this->shared->create_enumerator(this->shared);
while (enumerator->enumerate(enumerator, &current))
{
if (shared_entry_equals(current, new))
/* always replace keys with the same unique identifier, only compare
* them if both have no unique id assigned */
if ((id && streq(id, current->id)) ||
(!id && !current->id && shared_entry_equals(current, new)))
{
this->shared->remove_at(this->shared, enumerator);
shared_entry_destroy(current);
@@ -558,6 +592,12 @@ METHOD(mem_cred_t, add_shared_list, void,
this->lock->unlock(this->lock);
}
METHOD(mem_cred_t, add_shared_list, void,
private_mem_cred_t *this, shared_key_t *shared, linked_list_t* owners)
{
add_shared_unique(this, NULL, shared, owners);
}
METHOD(mem_cred_t, add_shared, void,
private_mem_cred_t *this, shared_key_t *shared, ...)
{
@@ -580,6 +620,63 @@ METHOD(mem_cred_t, add_shared, void,
add_shared_list(this, shared, owners);
}
METHOD(mem_cred_t, remove_shared_unique, void,
private_mem_cred_t *this, char *id)
{
enumerator_t *enumerator;
shared_entry_t *current;
if (!id)
{
return;
}
this->lock->write_lock(this->lock);
enumerator = this->shared->create_enumerator(this->shared);
while (enumerator->enumerate(enumerator, &current))
{
if (streq(id, current->id))
{
this->shared->remove_at(this->shared, enumerator);
shared_entry_destroy(current);
break;
}
}
enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
}
/**
* Filter unique ids of shared keys (ingore secrets without unique id)
*/
static bool unique_filter(void *unused,
shared_entry_t **in, char **id)
{
shared_entry_t *entry = *in;
if (!entry->id)
{
return FALSE;
}
if (id)
{
*id = entry->id;
}
return TRUE;
}
METHOD(mem_cred_t, create_unique_shared_enumerator, enumerator_t*,
private_mem_cred_t *this)
{
this->lock->read_lock(this->lock);
return enumerator_create_filter(
this->shared->create_enumerator(this->shared),
(void*)unique_filter, this->lock,
(void*)this->lock->unlock);
}
/**
* Certificate distribution point
*/
@@ -817,8 +914,12 @@ mem_cred_t *mem_cred_create()
.get_cert_ref = _get_cert_ref,
.add_crl = _add_crl,
.add_key = _add_key,
.remove_key = _remove_key,
.add_shared = _add_shared,
.add_shared_list = _add_shared_list,
.add_shared_unique = _add_shared_unique,
.remove_shared_unique = _remove_shared_unique,
.create_unique_shared_enumerator = _create_unique_shared_enumerator,
.add_cdp = _add_cdp,
.replace_certs = _replace_certs,
.replace_secrets = _replace_secrets,
+38 -2
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2010-2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
* Copyright (C) 2010-2016 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2010 Martin Willi
* Copyright (C) 2010 revosec AG
*
@@ -86,6 +87,14 @@ struct mem_cred_t {
*/
void (*add_key)(mem_cred_t *this, private_key_t *key);
/**
* Remove a private key from the credential set.
*
* @param fp fingerprint of the key to remove
* @return TRUE if the key was found and removed
*/
bool (*remove_key)(mem_cred_t *this, chunk_t fp);
/**
* Add a shared key to the credential set.
*
@@ -103,6 +112,33 @@ struct mem_cred_t {
void (*add_shared_list)(mem_cred_t *this, shared_key_t *shared,
linked_list_t *owners);
/**
* Add a shared key to the credential set, associated with the given unique
* identifier.
*
* If a shared key with the same id already exists it is replaced.
*
* @param id unique identifier of this key (cloned)
* @param shared shared key to add, gets owned by set
* @param ... NULL terminated list of owners (identification_t*)
*/
void (*add_shared_unique)(mem_cred_t *this, char *id, shared_key_t *shared,
linked_list_t *owners);
/**
* Remove a shared key by its unique identifier.
*
* @param id unique identifier of this key
*/
void (*remove_shared_unique)(mem_cred_t *this, char *id);
/**
* Create an enumerator over the unique identifiers of shared keys.
*
* @return enumerator over char*
*/
enumerator_t *(*create_unique_shared_enumerator)(mem_cred_t *this);
/**
* Add a certificate distribution point to the set.
*
+1
View File
@@ -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 \
+1 -1
View File
@@ -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)
+10 -2
View File
@@ -37,7 +37,7 @@ static int initiate(vici_conn_t *conn)
vici_req_t *req;
vici_res_t *res;
command_format_options_t format = COMMAND_FORMAT_NONE;
char *arg, *child = NULL;
char *arg, *child = NULL, *ike = NULL;
int ret = 0, timeout = 0, level = 1;
while (TRUE)
@@ -55,6 +55,9 @@ static int initiate(vici_conn_t *conn)
case 'c':
child = arg;
continue;
case 'i':
ike = arg;
continue;
case 't':
timeout = atoi(arg);
continue;
@@ -80,6 +83,10 @@ static int initiate(vici_conn_t *conn)
{
vici_add_key_valuef(req, "child", "%s", child);
}
if (ike)
{
vici_add_key_valuef(req, "ike", "%s", ike);
}
if (timeout)
{
vici_add_key_valuef(req, "timeout", "%d", timeout * 1000);
@@ -121,10 +128,11 @@ static void __attribute__ ((constructor))reg()
{
command_register((command_t) {
initiate, 'i', "initiate", "initiate a connection",
{"--child <name> [--timeout <s>] [--raw|--pretty]"},
{"--child <name> [--ike <name>] [--timeout <s>] [--raw|--pretty]"},
{
{"help", 'h', 0, "show usage information"},
{"child", 'c', 1, "initate a CHILD_SA configuration"},
{"ike", 'i', 1, "name of the connection to which the child belongs"},
{"timeout", 't', 1, "timeout in seconds before detaching"},
{"raw", 'r', 0, "dump raw response message"},
{"pretty", 'P', 0, "dump raw response message in pretty print"},
+12 -3
View File
@@ -22,7 +22,7 @@ static int manage_policy(vici_conn_t *conn, char *label)
vici_req_t *req;
vici_res_t *res;
command_format_options_t format = COMMAND_FORMAT_NONE;
char *arg, *child = NULL;
char *arg, *child = NULL, *ike = NULL;
int ret = 0;
while (TRUE)
@@ -40,6 +40,9 @@ static int manage_policy(vici_conn_t *conn, char *label)
case 'c':
child = arg;
continue;
case 'i':
ike = arg;
continue;
case EOF:
break;
default:
@@ -52,6 +55,10 @@ static int manage_policy(vici_conn_t *conn, char *label)
{
vici_add_key_valuef(req, "child", "%s", child);
}
if (ike)
{
vici_add_key_valuef(req, "ike", "%s", ike);
}
res = vici_submit(req, conn);
if (!res)
{
@@ -98,10 +105,11 @@ static void __attribute__ ((constructor))reg_uninstall()
{
command_register((command_t) {
uninstall, 'u', "uninstall", "uninstall a trap or shunt policy",
{"--child <name> [--raw|--pretty]"},
{"--child <name> [--ike <name>] [--raw|--pretty]"},
{
{"help", 'h', 0, "show usage information"},
{"child", 'c', 1, "CHILD_SA configuration to uninstall"},
{"ike", 'i', 1, "name of the connection to which the child belongs"},
{"raw", 'r', 0, "dump raw response message"},
{"pretty", 'P', 0, "dump raw response message in pretty print"},
}
@@ -115,10 +123,11 @@ static void __attribute__ ((constructor))reg_install()
{
command_register((command_t) {
install, 'p', "install", "install a trap or shunt policy",
{"--child <name> [--raw|--pretty]"},
{"--child <name> [--ike <name>] [--raw|--pretty]"},
{
{"help", 'h', 0, "show usage information"},
{"child", 'c', 1, "CHILD_SA configuration to install"},
{"ike", 'i', 1, "name of the connection to which the child belongs"},
{"raw", 'r', 0, "dump raw response message"},
{"pretty", 'P', 0, "dump raw response message in pretty print"},
}
+11 -3
View File
@@ -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"},
}
});
}
+3 -2
View File
@@ -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"));
+4 -4
View File
@@ -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)
{
+42 -31
View File
@@ -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,40 +106,50 @@ 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"))
{
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;
}
}
map = chunk_map(token, FALSE);
if (map)
{
vici_add_list_item(req, map->ptr, map->len);
chunk_unmap(map);
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
{
fprintf(stderr, "loading %s certificate '%s' failed: %s\n",
key, token, strerror(errno));
ret = FALSE;
break;
if (!path_absolute(token))
{
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;
}
}
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);
+301 -76
View File
@@ -1,11 +1,11 @@
/*
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
*
* Copyright (C) 2016 Tobias Brunner
* Copyright (C) 2015 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
@@ -30,15 +30,35 @@
#include <credentials/sets/mem_cred.h>
#include <credentials/sets/callback_cred.h>
#include <credentials/containers/pkcs12.h>
#include <collections/hashtable.h>
#include <vici_cert_info.h>
#define HASH_SIZE_SHA1_HEX (2 * HASH_SIZE_SHA1)
/**
* Context used to track loaded secrets
*/
typedef struct {
/** vici connection */
vici_conn_t *conn;
/** format options */
command_format_options_t format;
/** read setting */
settings_t *cfg;
/** don't prompt user for password */
bool noprompt;
/** list of key ids of loaded private keys */
hashtable_t *keys;
/** list of unique ids of loaded shared keys */
hashtable_t *shared;
} load_ctx_t;
/**
* Load a single certificate over vici
*/
static bool load_cert(vici_conn_t *conn, command_format_options_t format,
char *dir, certificate_type_t type, x509_flag_t flag,
chunk_t data)
static bool load_cert(load_ctx_t *ctx, char *dir, certificate_type_t type,
x509_flag_t flag, chunk_t data)
{
vici_req_t *req;
vici_res_t *res;
@@ -53,15 +73,15 @@ static bool load_cert(vici_conn_t *conn, command_format_options_t format,
}
vici_add_key_value(req, "data", data.ptr, data.len);
res = vici_submit(req, conn);
res = vici_submit(req, ctx->conn);
if (!res)
{
fprintf(stderr, "load-cert request failed: %s\n", strerror(errno));
return FALSE;
}
if (format & COMMAND_FORMAT_RAW)
if (ctx->format & COMMAND_FORMAT_RAW)
{
vici_dump(res, "load-cert reply", format & COMMAND_FORMAT_PRETTY,
vici_dump(res, "load-cert reply", ctx->format & COMMAND_FORMAT_PRETTY,
stdout);
}
else if (!streq(vici_find_str(res, "no", "success"), "yes"))
@@ -81,8 +101,7 @@ static bool load_cert(vici_conn_t *conn, command_format_options_t format,
/**
* Load certficiates from a directory
*/
static void load_certs(vici_conn_t *conn, command_format_options_t format,
char *type_str, char *dir)
static void load_certs(load_ctx_t *ctx, char *type_str, char *dir)
{
enumerator_t *enumerator;
certificate_type_t type;
@@ -103,7 +122,7 @@ static void load_certs(vici_conn_t *conn, command_format_options_t format,
map = chunk_map(path, FALSE);
if (map)
{
load_cert(conn, format, path, type, flag, *map);
load_cert(ctx, path, type, flag, *map);
chunk_unmap(map);
}
else
@@ -120,8 +139,7 @@ static void load_certs(vici_conn_t *conn, command_format_options_t format,
/**
* Load a single private key over vici
*/
static bool load_key(vici_conn_t *conn, command_format_options_t format,
char *dir, char *type, chunk_t data)
static bool load_key(load_ctx_t *ctx, char *dir, char *type, chunk_t data)
{
vici_req_t *req;
vici_res_t *res;
@@ -140,15 +158,15 @@ static bool load_key(vici_conn_t *conn, command_format_options_t format,
}
vici_add_key_value(req, "data", data.ptr, data.len);
res = vici_submit(req, conn);
res = vici_submit(req, ctx->conn);
if (!res)
{
fprintf(stderr, "load-key request failed: %s\n", strerror(errno));
return FALSE;
}
if (format & COMMAND_FORMAT_RAW)
if (ctx->format & COMMAND_FORMAT_RAW)
{
vici_dump(res, "load-key reply", format & COMMAND_FORMAT_PRETTY,
vici_dump(res, "load-key reply", ctx->format & COMMAND_FORMAT_PRETTY,
stdout);
}
else if (!streq(vici_find_str(res, "no", "success"), "yes"))
@@ -168,11 +186,12 @@ static bool load_key(vici_conn_t *conn, command_format_options_t format,
/**
* Load a private key of any type to vici
*/
static bool load_key_anytype(vici_conn_t *conn, command_format_options_t format,
char *path, private_key_t *private)
static bool load_key_anytype(load_ctx_t *ctx, char *path,
private_key_t *private)
{
bool loaded = FALSE;
chunk_t encoding;
chunk_t encoding, keyid;
char hex[HASH_SIZE_SHA1_HEX + 1];
if (!private->get_encoding(private, PRIVKEY_ASN1_DER, &encoding))
{
@@ -182,18 +201,25 @@ static bool load_key_anytype(vici_conn_t *conn, command_format_options_t format,
switch (private->get_type(private))
{
case KEY_RSA:
loaded = load_key(conn, format, path, "rsa", encoding);
loaded = load_key(ctx, path, "rsa", encoding);
break;
case KEY_ECDSA:
loaded = load_key(conn, format, path, "ecdsa", encoding);
loaded = load_key(ctx, path, "ecdsa", encoding);
break;
case KEY_BLISS:
loaded = load_key(conn, format, path, "bliss", encoding);
loaded = load_key(ctx, path, "bliss", encoding);
break;
default:
fprintf(stderr, "unsupported key type in '%s'\n", path);
break;
}
if (loaded &&
private->get_fingerprint(private, KEYID_PUBKEY_SHA1, &keyid) &&
snprintf(hex, sizeof(hex), "%+B", &keyid) == HASH_SIZE_SHA1_HEX)
{
free(ctx->keys->remove(ctx->keys, hex));
}
chunk_clear(&encoding);
return loaded;
}
@@ -312,7 +338,7 @@ static void* decrypt(char *name, char *type, chunk_t encoding)
/**
* Try to parse a potentially encrypted credential using configured secret
*/
static void* decrypt_with_config(settings_t *cfg, char *name, char *type,
static void* decrypt_with_config(load_ctx_t *ctx, char *name, char *type,
chunk_t encoding)
{
credential_type_t credtype;
@@ -329,16 +355,16 @@ static void* decrypt_with_config(settings_t *cfg, char *name, char *type,
}
/* load all secrets for this key type */
enumerator = cfg->create_section_enumerator(cfg, "secrets");
enumerator = ctx->cfg->create_section_enumerator(ctx->cfg, "secrets");
while (enumerator->enumerate(enumerator, &section))
{
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, &section))
{
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_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_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_containers(conn, format, noprompt, cfg, "pkcs12", SWANCTL_PKCS12DIR);
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(&ctx, "pkcs12", SWANCTL_PKCS12DIR);
load_tokens(&ctx);
enumerator = cfg->create_section_enumerator(cfg, "secrets");
while (enumerator->enumerate(enumerator, &section))
{
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;
}
+125
View File
@@ -0,0 +1,125 @@
/*
* Copyright (C) 2017 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "command.h"
#include <errno.h>
static int rekey(vici_conn_t *conn)
{
vici_req_t *req;
vici_res_t *res;
command_format_options_t format = COMMAND_FORMAT_NONE;
char *arg, *child = NULL, *ike = NULL;
int ret = 0, child_id = 0, ike_id = 0;
while (TRUE)
{
switch (command_getopt(&arg))
{
case 'h':
return command_usage(NULL);
case 'P':
format |= COMMAND_FORMAT_PRETTY;
/* fall through to raw */
case 'r':
format |= COMMAND_FORMAT_RAW;
continue;
case 'c':
child = arg;
continue;
case 'i':
ike = arg;
continue;
case 'C':
child_id = atoi(arg);
continue;
case 'I':
ike_id = atoi(arg);
continue;
case EOF:
break;
default:
return command_usage("invalid --rekey option");
}
break;
}
req = vici_begin("rekey");
if (child)
{
vici_add_key_valuef(req, "child", "%s", child);
}
if (ike)
{
vici_add_key_valuef(req, "ike", "%s", ike);
}
if (child_id)
{
vici_add_key_valuef(req, "child-id", "%d", child_id);
}
if (ike_id)
{
vici_add_key_valuef(req, "ike-id", "%d", ike_id);
}
res = vici_submit(req, conn);
if (!res)
{
ret = errno;
fprintf(stderr, "rekey request failed: %s\n", strerror(errno));
return ret;
}
if (format & COMMAND_FORMAT_RAW)
{
vici_dump(res, "rekey reply", format & COMMAND_FORMAT_PRETTY,
stdout);
}
else
{
if (streq(vici_find_str(res, "no", "success"), "yes"))
{
printf("rekey completed successfully\n");
}
else
{
fprintf(stderr, "rekey failed: %s\n",
vici_find_str(res, "", "errmsg"));
ret = 1;
}
}
vici_free_res(res);
return ret;
}
/**
* Register the command.
*/
static void __attribute__ ((constructor))reg()
{
command_register((command_t) {
rekey, 'R', "rekey", "rekey an SA",
{"--child <name> | --ike <name | --child-id <id> | --ike-id <id>",
"[--raw|--pretty]"},
{
{"help", 'h', 0, "show usage information"},
{"child", 'c', 1, "rekey by CHILD_SA name"},
{"ike", 'i', 1, "rekey by IKE_SA name"},
{"child-id", 'C', 1, "rekey by CHILD_SA unique identifier"},
{"ike-id", 'I', 1, "rekey by IKE_SA unique identifier"},
{"raw", 'r', 0, "dump raw response message"},
{"pretty", 'P', 0, "dump raw response message in pretty print"},
}
});
}
+3
View File
@@ -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
+194 -10
View File
@@ -102,6 +102,14 @@ connections.<conn>.pull = yes
Push mode is currently supported for IKEv1, but not in IKEv2. It is used
by a few implementations only, pull mode is recommended.
connections.<conn>.dscp = 000000
Differentiated Services Field Codepoint to set on outgoing IKE packets (six
binary digits).
Differentiated Services Field Codepoint to set on outgoing IKE packets for
this connection. The value is a six digit binary encoded string specifying
the Codepoint to set, as defined in RFC 2474.
connections.<conn>.encap = no
Enforce UDP encapsulation by faking NAT-D payloads.
@@ -256,6 +264,30 @@ connections.<conn>.pools =
other configuration attributes from. Each name references a pool by name
from either the **pools** section or an external pool.
connections.<conn>.mediation = no
Whether this connection is a mediation connection.
Whether this connection is a mediation connection, that is, whether this
connection is used to mediate other connections using the IKEv2 Mediation
Extension. Mediation connections create no CHILD_SA.
connections.<conn>.mediated_by =
The name of the connection to mediate this connection through.
The name of the connection to mediate this connection through. If given, the
connection will be mediated through the named mediation connection.
The mediation connection must have **mediation** enabled.
connections.<conn>.mediation_peer =
Identity under which the peer is registered at the mediation server.
Identity under which the peer is registered at the mediation server, that
is, the IKE identity the other end of this connection uses as its local
identity on its connection to the mediation server. This is the identity we
request the mediation server to mediate us with. Only relevant on
connections that set **mediated_by**. If it is not given, the remote IKE
identity of the first authentication round of this connection will be used.
connections.<conn>.local<suffix> {}
Section for a local authentication round.
@@ -284,6 +316,34 @@ connections.<conn>.local<suffix>.certs =
certificate request payloads. If no appropriate CA can be located, the
first certificate is used.
connections.<conn>.local<suffix>.cert<suffix> =
Section for a certificate candidate to use for authentication.
Section for a certificate candidate to use for authentication. Certificates
in _certs_ are transmitted as binary blobs, these sections offer more
flexibility.
connections.<conn>.local<suffix>.cert<suffix>.file =
Absolute path to the certificate to load.
Absolute path to the certificate to load. Passed as-is to the daemon, so it
must be readable by it.
Configure either this or _handle_, but not both, in one section.
connections.<conn>.local<suffix>.cert<suffix>.handle =
Hex-encoded CKA_ID of the certificate on a token.
Hex-encoded CKA_ID of the certificate on a token.
Configure either this or _file_, but not both, in one section.
connections.<conn>.local<suffix>.cert<suffix>.slot =
Optional slot number of the token that stores the certificate.
connections.<conn>.local<suffix>.cert<suffix>.module =
Optional PKCS#11 module name.
connections.<conn>.local<suffix>.pubkeys =
Comma separated list of raw public key candidates to use for authentication.
@@ -398,6 +458,12 @@ connections.<conn>.remote<suffix>.groups =
can be certified by different means, for example by appropriate Attribute
Certificates or by an AAA backend involved in the authentication.
connections.<conn>.remote<suffix>.cert_policy =
Certificate policy OIDs the peer's certificate must have.
Comma separated list of certificate policy OIDs the peer's certificate must
have. OIDs are specified using the numerical dotted representation.
connections.<conn>.remote<suffix>.certs =
Comma separated list of certificate to accept for authentication.
@@ -405,6 +471,34 @@ connections.<conn>.remote<suffix>.certs =
The certificates may use a relative path from the **swanctl** _x509_
directory or an absolute path.
connections.<conn>.remote<suffix>.cert<suffix> =
Section for a certificate to accept for authentication.
Section for a certificate to accept for authentication. Certificates
in _certs_ are transmitted as binary blobs, these sections offer more
flexibility.
connections.<conn>.remote<suffix>.cert<suffix>.file =
Absolute path to the certificate to load.
Absolute path to the certificate to load. Passed as-is to the daemon, so it
must be readable by it.
Configure either this or _handle_, but not both, in one section.
connections.<conn>.remote<suffix>.cert<suffix>.handle =
Hex-encoded CKA_ID of the certificate on a token.
Hex-encoded CKA_ID of the certificate on a token.
Configure either this or _file_, but not both, in one section.
connections.<conn>.remote<suffix>.cert<suffix>.slot =
Optional slot number of the token that stores the certificate.
connections.<conn>.remote<suffix>.cert<suffix>.module =
Optional PKCS#11 module name.
connections.<conn>.remote<suffix>.cacerts =
Comma separated list of CA certificates to accept for authentication.
@@ -412,6 +506,34 @@ connections.<conn>.remote<suffix>.cacerts =
The certificates may use a relative path from the **swanctl** _x509ca_
directory or an absolute path.
connections.<conn>.remote<suffix>.cacert<suffix> =
Section for a CA certificate to accept for authentication.
Section for a CA certificate to accept for authentication. Certificates
in _cacerts_ are transmitted as binary blobs, these sections offer more
flexibility.
connections.<conn>.remote<suffix>.cacert<suffix>.file =
Absolute path to the certificate to load.
Absolute path to the certificate to load. Passed as-is to the daemon, so it
must be readable by it.
Configure either this or _handle_, but not both, in one section.
connections.<conn>.remote<suffix>.cacert<suffix>.handle =
Hex-encoded CKA_ID of the CA certificate on a token.
Hex-encoded CKA_ID of the CA certificate on a token.
Configure either this or _file_, but not both, in one section.
connections.<conn>.remote<suffix>.cacert<suffix>.slot =
Optional slot number of the token that stores the CA certificate.
connections.<conn>.remote<suffix>.cacert<suffix>.module =
Optional PKCS#11 module name.
connections.<conn>.remote<suffix>.pubkeys =
Comma separated list of raw public keys to accept for authentication.
@@ -640,11 +762,13 @@ connections.<conn>.children.<child>.hostaccess = yes
Hostaccess variable to pass to **updown** script.
connections.<conn>.children.<child>.mode = tunnel
IPsec Mode to establish (_tunnel_, _transport_, _beet_, _pass_ or _drop_).
IPsec Mode to establish (_tunnel_, _transport_, _transport_proxy_, _beet_,
_pass_ or _drop_).
IPsec Mode to establish CHILD_SA with. _tunnel_ negotiates the CHILD_SA
in IPsec Tunnel Mode, whereas _transport_ uses IPsec Transport Mode. _beet_
is the Bound End to End Tunnel mixture mode, working with fixed inner
in IPsec Tunnel Mode, whereas _transport_ uses IPsec Transport Mode.
_transport_proxy_ signifying the special Mobile IPv6 Transport Proxy Mode.
_beet_ is the Bound End to End Tunnel mixture mode, working with fixed inner
addresses without the need to include them in each packet.
Both _transport_ and _beet_ modes are subject to mode negotiation; _tunnel_
@@ -815,6 +939,28 @@ secrets.eap<suffix>.id<suffix> =
be specified, each having an _id_ prefix, if a secret is shared between
multiple users.
secrets.ntlm<suffix> { # }
NTLM secret section for a specific secret.
NTLM secret section for a specific secret. Each NTLM secret is defined in
a unique section having the _ntlm_ prefix. NTLM secrets may only be used for
EAP-MSCHAPv2 authentication.
secrets.ntlm<suffix>.secret =
Value of the NTLM secret.
Value of the NTLM secret, which is the NT Hash of the actual secret, that
is, MD4(UTF-16LE(secret)). The resulting 16-byte value may either be given
as a hex encoded string with a _0x_ prefix or as a Base64 encoded string
with a _0s_ prefix.
secrets.ntlm<suffix>.id<suffix> =
Identity the NTLM secret belongs to.
Identity the NTLM secret belongs to. Multiple unique identities may
be specified, each having an _id_ prefix, if a secret is shared between
multiple users.
secrets.ike<suffix> { # }
IKE preshared secret section for a specific secret.
@@ -880,6 +1026,22 @@ secrets.pkcs12<suffix>.file =
secrets.pkcs12<suffix>.secret
Value of decryption passphrase for PKCS#12 container.
secrets.token<suffix> { # }
Definition for a private key that's stored on a token/smartcard.
secrets.token<suffix>.handle =
Hex-encoded CKA_ID of the private key on the token.
secrets.token<suffix>.slot =
Optional slot number to access the token.
secrets.token<suffix>.module =
Optional PKCS#11 module name to access the token.
secrets.token<suffix>.pin =
Optional PIN required to access the key on the token. If none is provided
the user is prompted during an interactive --load-creds call.
pools { # }
Section defining named pools.
@@ -916,18 +1078,40 @@ authorities.<name> { # }
authorities.<name>.cacert =
CA certificate belonging to the certification authority.
The certificates may use a relative path from the **swanctl** _x509ca_
directory or an absolute path.
CA certificate belonging to the certification authority. The certificates
may use a relative path from the **swanctl** _x509ca_ directory or an
absolute path.
Configure one of _cacert_, _file_, or _handle_ per section.
authorities.<name>.file =
Absolute path to the certificate to load.
Absolute path to the certificate to load. Passed as-is to the daemon, so it
must be readable by it.
Configure one of _cacert_, _file_, or _handle_ per section.
authorities.<name>.handle =
Hex-encoded CKA_ID of the CA certificate on a token.
Hex-encoded CKA_ID of the CA certificate on a token.
Configure one of _cacert_, _file_, or _handle_ per section.
authorities.<name>.slot =
Optional slot number of the token that stores the CA certificate.
authorities.<name>.module =
Optional PKCS#11 module name.
authorities.<name>.crl_uris =
Comma-separated list of CRL distribution points
Comma-separated list of CRL distribution points.
Comma-separated list of CRL distribution points (ldap, http, or file URI)
Comma-separated list of CRL distribution points (ldap, http, or file URI).
authorities.<name>.ocsp_uris =
Comma-separated list of OCSP URIs
Comma-separated list of OCSP URIs
Comma-separated list of OCSP URIs.
authorities.<name>.cert_uri_base =
Defines the base URI for the Hash and URL feature supported by IKEv2.