summaryrefslogtreecommitdiff
path: root/src/libcharon/plugins/nm
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/plugins/nm')
-rw-r--r--src/libcharon/plugins/nm/Makefile.in20
-rw-r--r--src/libcharon/plugins/nm/nm_creds.c97
-rw-r--r--src/libcharon/plugins/nm/nm_creds.h17
-rw-r--r--src/libcharon/plugins/nm/nm_plugin.c2
-rw-r--r--src/libcharon/plugins/nm/nm_service.c108
5 files changed, 209 insertions, 35 deletions
diff --git a/src/libcharon/plugins/nm/Makefile.in b/src/libcharon/plugins/nm/Makefile.in
index 1b3e4c5a6..2f5c20971 100644
--- a/src/libcharon/plugins/nm/Makefile.in
+++ b/src/libcharon/plugins/nm/Makefile.in
@@ -44,6 +44,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \
$(top_srcdir)/m4/config/lt~obsolete.m4 \
$(top_srcdir)/m4/macros/with.m4 \
$(top_srcdir)/m4/macros/enable-disable.m4 \
+ $(top_srcdir)/m4/macros/add-plugin.m4 \
$(top_srcdir)/configure.in
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
@@ -166,6 +167,8 @@ PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PERL = @PERL@
PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PTHREADLIB = @PTHREADLIB@
RANLIB = @RANLIB@
RTLIB = @RTLIB@
@@ -197,14 +200,17 @@ build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
+c_plugins = @c_plugins@
datadir = @datadir@
datarootdir = @datarootdir@
+dbusservicedir = @dbusservicedir@
default_pkcs11 = @default_pkcs11@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
gtk_CFLAGS = @gtk_CFLAGS@
gtk_LIBS = @gtk_LIBS@
+h_plugins = @h_plugins@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
@@ -219,24 +225,31 @@ ipsecgid = @ipsecgid@
ipsecgroup = @ipsecgroup@
ipsecuid = @ipsecuid@
ipsecuser = @ipsecuser@
+libcharon_plugins = @libcharon_plugins@
libdir = @libdir@
libexecdir = @libexecdir@
-libhydra_plugins = @libhydra_plugins@
-libstrongswan_plugins = @libstrongswan_plugins@
linux_headers = @linux_headers@
localedir = @localedir@
localstatedir = @localstatedir@
lt_ECHO = @lt_ECHO@
+maemo_CFLAGS = @maemo_CFLAGS@
+maemo_LIBS = @maemo_LIBS@
+manager_plugins = @manager_plugins@
mandir = @mandir@
+medsrv_plugins = @medsrv_plugins@
mkdir_p = @mkdir_p@
nm_CFLAGS = @nm_CFLAGS@
nm_LIBS = @nm_LIBS@
nm_ca_dir = @nm_ca_dir@
oldincludedir = @oldincludedir@
+openac_plugins = @openac_plugins@
+p_plugins = @p_plugins@
pdfdir = @pdfdir@
piddir = @piddir@
+pki_plugins = @pki_plugins@
plugindir = @plugindir@
pluto_plugins = @pluto_plugins@
+pool_plugins = @pool_plugins@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
@@ -244,7 +257,10 @@ random_device = @random_device@
resolv_conf = @resolv_conf@
routing_table = @routing_table@
routing_table_prio = @routing_table_prio@
+s_plugins = @s_plugins@
sbindir = @sbindir@
+scepclient_plugins = @scepclient_plugins@
+scripts_plugins = @scripts_plugins@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
strongswan_conf = @strongswan_conf@
diff --git a/src/libcharon/plugins/nm/nm_creds.c b/src/libcharon/plugins/nm/nm_creds.c
index 193838e6b..638787019 100644
--- a/src/libcharon/plugins/nm/nm_creds.c
+++ b/src/libcharon/plugins/nm/nm_creds.c
@@ -51,6 +51,16 @@ struct private_nm_creds_t {
char *pass;
/**
+ * Private key decryption password / smartcard pin
+ */
+ char *keypass;
+
+ /**
+ * private key ID of smartcard key
+ */
+ chunk_t keyid;
+
+ /**
* users certificate
*/
certificate_t *usercert;
@@ -239,8 +249,14 @@ static bool shared_enumerate(shared_enumerator_t *this, shared_key_t **key,
return FALSE;
}
*key = this->key;
- *me = ID_MATCH_PERFECT;
- *other = ID_MATCH_ANY;
+ if (me)
+ {
+ *me = ID_MATCH_PERFECT;
+ }
+ if (other)
+ {
+ *other = ID_MATCH_ANY;
+ }
this->done = TRUE;
return TRUE;
}
@@ -262,18 +278,39 @@ static enumerator_t* create_shared_enumerator(private_nm_creds_t *this,
identification_t *other)
{
shared_enumerator_t *enumerator;
+ chunk_t key;
- if (!this->pass || !this->user)
+ switch (type)
{
- return NULL;
- }
- if (type != SHARED_EAP && type != SHARED_IKE)
- {
- return NULL;
- }
- if (me && !me->equals(me, this->user))
- {
- return NULL;
+ case SHARED_EAP:
+ case SHARED_IKE:
+ if (!this->pass || !this->user)
+ {
+ return NULL;
+ }
+ if (me && !me->equals(me, this->user))
+ {
+ return NULL;
+ }
+ key = chunk_create(this->pass, strlen(this->pass));
+ break;
+ case SHARED_PRIVATE_KEY_PASS:
+ if (!this->keypass)
+ {
+ return NULL;
+ }
+ key = chunk_create(this->keypass, strlen(this->keypass));
+ break;
+ case SHARED_PIN:
+ if (!this->keypass || !me ||
+ !chunk_equals(me->get_encoding(me), this->keyid))
+ {
+ return NULL;
+ }
+ key = chunk_create(this->keypass, strlen(this->keypass));
+ break;
+ default:
+ return NULL;
}
enumerator = malloc_thing(shared_enumerator_t);
@@ -282,9 +319,7 @@ static enumerator_t* create_shared_enumerator(private_nm_creds_t *this,
enumerator->this = this;
enumerator->done = FALSE;
this->lock->read_lock(this->lock);
- enumerator->key = shared_key_create(type,
- chunk_clone(chunk_create(this->pass,
- strlen(this->pass))));
+ enumerator->key = shared_key_create(type, chunk_clone(key));
return &enumerator->public;
}
@@ -370,6 +405,30 @@ static void set_username_password(private_nm_creds_t *this, identification_t *id
}
/**
+ * Implementation of nm_creds_t.set_key_password
+ */
+static void set_key_password(private_nm_creds_t *this, char *password)
+{
+ this->lock->write_lock(this->lock);
+ free(this->keypass);
+ this->keypass = password ? strdup(password) : NULL;
+ this->lock->unlock(this->lock);
+}
+
+/**
+ * Implementation of nm_creds_t.set_pin
+ */
+static void set_pin(private_nm_creds_t *this, chunk_t keyid, char *pin)
+{
+ this->lock->write_lock(this->lock);
+ free(this->keypass);
+ free(this->keyid.ptr);
+ this->keypass = pin ? strdup(pin) : NULL;
+ this->keyid = chunk_clone(keyid);
+ this->lock->unlock(this->lock);
+}
+
+/**
* Implementation of nm_creds_t.set_cert_and_key
*/
static void set_cert_and_key(private_nm_creds_t *this, certificate_t *cert,
@@ -396,12 +455,16 @@ static void clear(private_nm_creds_t *this)
}
DESTROY_IF(this->user);
free(this->pass);
+ free(this->keypass);
+ free(this->keyid.ptr);
DESTROY_IF(this->usercert);
DESTROY_IF(this->key);
this->key = NULL;
this->usercert = NULL;
this->pass = NULL;
this->user = NULL;
+ this->keypass = NULL;
+ this->keyid = chunk_empty;
}
/**
@@ -430,6 +493,8 @@ nm_creds_t *nm_creds_create()
this->public.add_certificate = (void(*)(nm_creds_t*, certificate_t *cert))add_certificate;
this->public.load_ca_dir = (void(*)(nm_creds_t*, char *dir))load_ca_dir;
this->public.set_username_password = (void(*)(nm_creds_t*, identification_t *id, char *password))set_username_password;
+ this->public.set_key_password = (void(*)(nm_creds_t*, char *password))set_key_password;
+ this->public.set_pin = (void(*)(nm_creds_t*, chunk_t keyid, char *pin))set_pin;
this->public.set_cert_and_key = (void(*)(nm_creds_t*, certificate_t *cert, private_key_t *key))set_cert_and_key;
this->public.clear = (void(*)(nm_creds_t*))clear;
this->public.destroy = (void(*)(nm_creds_t*))destroy;
@@ -441,6 +506,8 @@ nm_creds_t *nm_creds_create()
this->pass = NULL;
this->usercert = NULL;
this->key = NULL;
+ this->keypass = NULL;
+ this->keyid = chunk_empty;
return &this->public;
}
diff --git a/src/libcharon/plugins/nm/nm_creds.h b/src/libcharon/plugins/nm/nm_creds.h
index b55cff31e..91f645c7e 100644
--- a/src/libcharon/plugins/nm/nm_creds.h
+++ b/src/libcharon/plugins/nm/nm_creds.h
@@ -58,6 +58,22 @@ struct nm_creds_t {
*/
void (*set_username_password)(nm_creds_t *this, identification_t *id,
char *password);
+
+ /**
+ * Set the passphrase to use for private key decryption.
+ *
+ * @param password password to use
+ */
+ void (*set_key_password)(nm_creds_t *this, char *password);
+
+ /**
+ * Set the PIN to unlock a smartcard.
+ *
+ * @param keyid keyid of the smartcard key
+ * @param pin PIN
+ */
+ void (*set_pin)(nm_creds_t *this, chunk_t keyid, char *pin);
+
/**
* Set the certificate and private key to use for client authentication.
*
@@ -66,6 +82,7 @@ struct nm_creds_t {
*/
void (*set_cert_and_key)(nm_creds_t *this, certificate_t *cert,
private_key_t *key);
+
/**
* Clear the stored credentials.
*/
diff --git a/src/libcharon/plugins/nm/nm_plugin.c b/src/libcharon/plugins/nm/nm_plugin.c
index 250e6f7f9..fd0580bd6 100644
--- a/src/libcharon/plugins/nm/nm_plugin.c
+++ b/src/libcharon/plugins/nm/nm_plugin.c
@@ -122,7 +122,7 @@ plugin_t *nm_plugin_create()
/* bypass file permissions to read from users ssh-agent */
charon->keep_cap(charon, CAP_DAC_OVERRIDE);
- charon->processor->queue_job(charon->processor,
+ lib->processor->queue_job(lib->processor,
(job_t*)callback_job_create((callback_job_cb_t)run, this, NULL, NULL));
return &this->public.plugin;
diff --git a/src/libcharon/plugins/nm/nm_service.c b/src/libcharon/plugins/nm/nm_service.c
index 07318bbbf..72c5bbbb5 100644
--- a/src/libcharon/plugins/nm/nm_service.c
+++ b/src/libcharon/plugins/nm/nm_service.c
@@ -204,6 +204,59 @@ static bool ike_rekey(listener_t *listener, ike_sa_t *old, ike_sa_t *new)
}
/**
+ * Find a certificate for which we have a private key on a smartcard
+ */
+static identification_t *find_smartcard_key(NMStrongswanPluginPrivate *priv,
+ char *pin)
+{
+ enumerator_t *enumerator, *sans;
+ identification_t *id = NULL;
+ certificate_t *cert;
+ x509_t *x509;
+ private_key_t *key;
+ chunk_t keyid;
+
+ enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
+ CERT_X509, KEY_ANY, NULL, FALSE);
+ while (enumerator->enumerate(enumerator, &cert))
+ {
+ x509 = (x509_t*)cert;
+
+ /* there might be a lot of certificates, filter them by usage */
+ if ((x509->get_flags(x509) & X509_CLIENT_AUTH) &&
+ !(x509->get_flags(x509) & X509_CA))
+ {
+ keyid = x509->get_subjectKeyIdentifier(x509);
+ if (keyid.ptr)
+ {
+ /* try to find a private key by the certificate keyid */
+ priv->creds->set_pin(priv->creds, keyid, pin);
+ key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
+ KEY_ANY, BUILD_PKCS11_KEYID, keyid, BUILD_END);
+ if (key)
+ {
+ /* prefer a more convenient subjectAltName */
+ sans = x509->create_subjectAltName_enumerator(x509);
+ if (!sans->enumerate(sans, &id))
+ {
+ id = cert->get_subject(cert);
+ }
+ id = id->clone(id);
+ sans->destroy(sans);
+
+ DBG1(DBG_CFG, "using smartcard certificate '%Y'", id);
+ priv->creds->set_cert_and_key(priv->creds,
+ cert->get_ref(cert), key);
+ break;
+ }
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ return id;
+}
+
+/**
* Connect function called from NM via DBUS
*/
static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
@@ -224,7 +277,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
auth_class_t auth_class = AUTH_CLASS_EAP;
certificate_t *cert = NULL;
x509_t *x509;
- bool agent = FALSE;
+ bool agent = FALSE, smartcard = FALSE;
lifetime_cfg_t lifetime = {
.time = {
.life = 10800 /* 3h */,
@@ -279,6 +332,11 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
{
auth_class = AUTH_CLASS_PUBKEY;
}
+ else if (streq(str, "smartcard"))
+ {
+ auth_class = AUTH_CLASS_PUBKEY;
+ smartcard = TRUE;
+ }
}
/**
@@ -338,9 +396,26 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
if (auth_class == AUTH_CLASS_PUBKEY)
{
+ if (smartcard)
+ {
+ char *pin;
+
+ pin = (char*)nm_setting_vpn_get_secret(vpn, "password");
+ if (pin)
+ {
+ user = find_smartcard_key(priv, pin);
+ }
+ if (!user)
+ {
+ g_set_error(err, NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+ "no usable smartcard certificate found.");
+ gateway->destroy(gateway);
+ return FALSE;
+ }
+ }
/* ... or certificate/private key authenitcation */
- str = nm_setting_vpn_get_data_item(vpn, "usercert");
- if (str)
+ else if ((str = nm_setting_vpn_get_data_item(vpn, "usercert")))
{
public_key_t *public;
private_key_t *private = NULL;
@@ -380,16 +455,15 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
str = nm_setting_vpn_get_data_item(vpn, "userkey");
if (!agent && str)
{
- chunk_t secret;
+ char *secret;
- secret.ptr = (char*)nm_setting_vpn_get_secret(vpn, "password");
- if (secret.ptr)
+ secret = (char*)nm_setting_vpn_get_secret(vpn, "password");
+ if (secret)
{
- secret.len = strlen(secret.ptr);
+ priv->creds->set_key_password(priv->creds, secret);
}
private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
- KEY_RSA, BUILD_FROM_FILE, str,
- BUILD_PASSPHRASE, secret, BUILD_END);
+ KEY_RSA, BUILD_FROM_FILE, str, BUILD_END);
if (!private)
{
g_set_error(err, NM_VPN_PLUGIN_ERROR,
@@ -524,17 +598,10 @@ static gboolean need_secrets(NMVPNPlugin *plugin, NMConnection *connection,
if (path)
{
private_key_t *key;
- chunk_t secret;
- secret.ptr = (char*)nm_setting_vpn_get_secret(settings, "password");
- if (secret.ptr)
- {
- secret.len = strlen(secret.ptr);
- }
/* try to load/decrypt the private key */
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
- KEY_RSA, BUILD_FROM_FILE, path,
- BUILD_PASSPHRASE, secret, BUILD_END);
+ KEY_RSA, BUILD_FROM_FILE, path, BUILD_END);
if (key)
{
key->destroy(key);
@@ -542,6 +609,13 @@ static gboolean need_secrets(NMVPNPlugin *plugin, NMConnection *connection,
}
}
}
+ else if streq(method, "smartcard")
+ {
+ if (nm_setting_vpn_get_secret(settings, "password"))
+ {
+ return FALSE;
+ }
+ }
}
*setting_name = NM_SETTING_VPN_SETTING_NAME;
return TRUE;