aboutsummaryrefslogtreecommitdiffstats
path: root/src/libcharon/plugins/stroke
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/plugins/stroke')
-rw-r--r--src/libcharon/plugins/stroke/stroke_config.c185
-rw-r--r--src/libcharon/plugins/stroke/stroke_config.h10
-rw-r--r--src/libcharon/plugins/stroke/stroke_cred.c82
-rw-r--r--src/libcharon/plugins/stroke/stroke_cred.h24
-rw-r--r--src/libcharon/plugins/stroke/stroke_list.c50
-rw-r--r--src/libcharon/plugins/stroke/stroke_socket.c24
6 files changed, 364 insertions, 11 deletions
diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c
index 8ca1464fb..89e1e0a91 100644
--- a/src/libcharon/plugins/stroke/stroke_config.c
+++ b/src/libcharon/plugins/stroke/stroke_config.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -263,7 +264,7 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
{
identification_t *identity;
certificate_t *certificate;
- char *auth, *id, *cert, *ca;
+ char *auth, *id, *pubkey, *cert, *ca;
stroke_end_t *end, *other_end;
auth_cfg_t *cfg;
@@ -358,6 +359,18 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
}
cfg->add(cfg, AUTH_RULE_IDENTITY, identity);
+ /* add raw RSA public key */
+ pubkey = end->rsakey;
+ if (pubkey && !streq(pubkey, "") && !streq(pubkey, "%cert"))
+ {
+ certificate = this->cred->load_pubkey(this->cred, KEY_RSA, pubkey,
+ identity);
+ if (certificate)
+ {
+ cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
+ }
+ }
+
/* CA constraint */
if (ca)
{
@@ -931,6 +944,175 @@ METHOD(stroke_config_t, del, void,
}
}
+METHOD(stroke_config_t, set_user_credentials, void,
+ private_stroke_config_t *this, stroke_msg_t *msg, FILE *prompt)
+{
+ enumerator_t *enumerator, *children, *remote_auth;
+ peer_cfg_t *peer, *found = NULL;
+ auth_cfg_t *auth_cfg, *remote_cfg;
+ auth_class_t auth_class;
+ child_cfg_t *child;
+ identification_t *id, *identity, *gw = NULL;
+ shared_key_type_t type = SHARED_ANY;
+ chunk_t password = chunk_empty;
+
+ this->mutex->lock(this->mutex);
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, (void**)&peer))
+ { /* find the peer (or child) config with the given name */
+ if (streq(peer->get_name(peer), msg->user_creds.name))
+ {
+ found = peer;
+ }
+ else
+ {
+ children = peer->create_child_cfg_enumerator(peer);
+ while (children->enumerate(children, &child))
+ {
+ if (streq(child->get_name(child), msg->user_creds.name))
+ {
+ found = peer;
+ break;
+ }
+ }
+ children->destroy(children);
+ }
+
+ if (found)
+ {
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (!found)
+ {
+ DBG1(DBG_CFG, " no config named '%s'", msg->user_creds.name);
+ fprintf(prompt, "no config named '%s'\n", msg->user_creds.name);
+ this->mutex->unlock(this->mutex);
+ return;
+ }
+
+ id = identification_create_from_string(msg->user_creds.username);
+ if (strlen(msg->user_creds.username) == 0 ||
+ !id || id->get_type(id) == ID_ANY)
+ {
+ DBG1(DBG_CFG, " invalid username '%s'", msg->user_creds.username);
+ fprintf(prompt, "invalid username '%s'\n", msg->user_creds.username);
+ this->mutex->unlock(this->mutex);
+ DESTROY_IF(id);
+ return;
+ }
+
+ /* replace/set the username in the first EAP auth_cfg, also look for a
+ * suitable remote ID.
+ * note that adding the identity here is not fully thread-safe as the
+ * peer_cfg and in turn the auth_cfg could be in use. for the default use
+ * case (setting user credentials before upping the connection) this will
+ * not be a problem, though. */
+ enumerator = found->create_auth_cfg_enumerator(found, TRUE);
+ remote_auth = found->create_auth_cfg_enumerator(found, FALSE);
+ while (enumerator->enumerate(enumerator, (void**)&auth_cfg))
+ {
+ if (remote_auth->enumerate(remote_auth, (void**)&remote_cfg))
+ { /* fall back on rightid, in case aaa_identity is not specified */
+ identity = remote_cfg->get(remote_cfg, AUTH_RULE_IDENTITY);
+ if (identity && identity->get_type(identity) != ID_ANY)
+ {
+ gw = identity;
+ }
+ }
+
+ auth_class = (uintptr_t)auth_cfg->get(auth_cfg, AUTH_RULE_AUTH_CLASS);
+ if (auth_class == AUTH_CLASS_EAP)
+ {
+ auth_cfg->add(auth_cfg, AUTH_RULE_EAP_IDENTITY, id->clone(id));
+ /* if aaa_identity is specified use that as remote ID */
+ identity = auth_cfg->get(auth_cfg, AUTH_RULE_AAA_IDENTITY);
+ if (identity && identity->get_type(identity) != ID_ANY)
+ {
+ gw = identity;
+ }
+ DBG1(DBG_CFG, " configured EAP-Identity %Y", id);
+ type = SHARED_EAP;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ remote_auth->destroy(remote_auth);
+ /* clone the gw ID before unlocking the mutex */
+ if (gw)
+ {
+ gw = gw->clone(gw);
+ }
+ this->mutex->unlock(this->mutex);
+
+ if (type == SHARED_ANY)
+ {
+ DBG1(DBG_CFG, " config '%s' unsuitable for user credentials",
+ msg->user_creds.name);
+ fprintf(prompt, "config '%s' unsuitable for user credentials\n",
+ msg->user_creds.name);
+ id->destroy(id);
+ DESTROY_IF(gw);
+ return;
+ }
+
+ if (msg->user_creds.password)
+ {
+ char *pass;
+
+ pass = msg->user_creds.password;
+ password = chunk_clone(chunk_create(pass, strlen(pass)));
+ memwipe(pass, strlen(pass));
+ }
+ else
+ { /* prompt the user for the password */
+ char buf[256];
+
+ fprintf(prompt, "Password:\n");
+ if (fgets(buf, sizeof(buf), prompt))
+ {
+ password = chunk_clone(chunk_create(buf, strlen(buf)));
+ if (password.len > 0)
+ { /* trim trailing \n */
+ password.len--;
+ }
+ memwipe(buf, sizeof(buf));
+ }
+ }
+
+ if (password.len)
+ {
+ shared_key_t *shared;
+ linked_list_t *owners;
+
+ shared = shared_key_create(type, password);
+
+ owners = linked_list_create();
+ owners->insert_last(owners, id->clone(id));
+ if (gw && gw->get_type(gw) != ID_ANY)
+ {
+ owners->insert_last(owners, gw->clone(gw));
+ DBG1(DBG_CFG, " added %N secret for %Y %Y", shared_key_type_names,
+ type, id, gw);
+ }
+ else
+ {
+ DBG1(DBG_CFG, " added %N secret for %Y", shared_key_type_names,
+ type, id);
+ }
+ this->cred->add_shared(this->cred, shared, owners);
+ DBG4(DBG_CFG, " secret: %#B", &password);
+ }
+ else
+ { /* in case a user answers the password prompt by just pressing enter */
+ chunk_clear(&password);
+ }
+ id->destroy(id);
+ DESTROY_IF(gw);
+}
+
METHOD(stroke_config_t, destroy, void,
private_stroke_config_t *this)
{
@@ -955,6 +1137,7 @@ stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred)
},
.add = _add,
.del = _del,
+ .set_user_credentials = _set_user_credentials,
.destroy = _destroy,
},
.list = linked_list_create(),
diff --git a/src/libcharon/plugins/stroke/stroke_config.h b/src/libcharon/plugins/stroke/stroke_config.h
index 05e4665ca..450d517f3 100644
--- a/src/libcharon/plugins/stroke/stroke_config.h
+++ b/src/libcharon/plugins/stroke/stroke_config.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -53,6 +54,15 @@ struct stroke_config_t {
void (*del)(stroke_config_t *this, stroke_msg_t *msg);
/**
+ * Set the username and password for a connection in this backend.
+ *
+ * @param msg received stroke message
+ * @param prompt I/O channel to prompt for the password
+ */
+ void (*set_user_credentials)(stroke_config_t *this, stroke_msg_t *msg,
+ FILE *prompt);
+
+ /**
* Destroy a stroke_config instance.
*/
void (*destroy)(stroke_config_t *this);
diff --git a/src/libcharon/plugins/stroke/stroke_cred.c b/src/libcharon/plugins/stroke/stroke_cred.c
index cdf69135a..535ece233 100644
--- a/src/libcharon/plugins/stroke/stroke_cred.c
+++ b/src/libcharon/plugins/stroke/stroke_cred.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2011 Tobias Brunner
+ * Copyright (C) 2008-2012 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -158,6 +158,78 @@ METHOD(stroke_cred_t, load_peer, certificate_t*,
return NULL;
}
+METHOD(stroke_cred_t, load_pubkey, certificate_t*,
+ private_stroke_cred_t *this, key_type_t type, char *filename,
+ identification_t *identity)
+{
+ certificate_t *cert;
+ char path[PATH_MAX];
+
+ if (streq(filename, "%dns"))
+ {
+
+ }
+ else if (strncaseeq(filename, "0x", 2) || strncaseeq(filename, "0s", 2))
+ {
+ chunk_t printable_key, rfc3110_key;
+ public_key_t *key;
+
+ printable_key = chunk_create(filename + 2, strlen(filename) - 2);
+ rfc3110_key = strncaseeq(filename, "0x", 2) ?
+ chunk_from_hex(printable_key, NULL) :
+ chunk_from_base64(printable_key, NULL);
+ key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
+ BUILD_BLOB_DNSKEY, rfc3110_key,
+ BUILD_END);
+ free(rfc3110_key.ptr);
+ if (key)
+ {
+ cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
+ CERT_TRUSTED_PUBKEY,
+ BUILD_PUBLIC_KEY, key,
+ BUILD_SUBJECT, identity,
+ BUILD_END);
+ key->destroy(key);
+ if (cert)
+ {
+ cert = this->creds->add_cert_ref(this->creds, TRUE, cert);
+ DBG1(DBG_CFG, " loaded %N public key for \"%Y\"",
+ key_type_names, type, identity);
+ return cert;
+ }
+ }
+ DBG1(DBG_CFG, " loading %N public key for \"%Y\" failed",
+ key_type_names, type, identity);
+ }
+ else
+ {
+ if (*filename == '/')
+ {
+ snprintf(path, sizeof(path), "%s", filename);
+ }
+ else
+ {
+ snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
+ }
+
+ cert = lib->creds->create(lib->creds,
+ CRED_CERTIFICATE, CERT_TRUSTED_PUBKEY,
+ BUILD_FROM_FILE, path,
+ BUILD_SUBJECT, identity,
+ BUILD_END);
+ if (cert)
+ {
+ cert = this->creds->add_cert_ref(this->creds, TRUE, cert);
+ DBG1(DBG_CFG, " loaded %N public key for \"%Y\" from '%s'",
+ key_type_names, type, identity, filename);
+ return cert;
+ }
+ DBG1(DBG_CFG, " loading %N public key for \"%Y\" from '%s' failed",
+ key_type_names, type, identity, filename);
+ }
+ return NULL;
+}
+
/**
* load trusted certificates from a directory
*/
@@ -1065,6 +1137,12 @@ METHOD(stroke_cred_t, reread, void,
}
}
+METHOD(stroke_cred_t, add_shared, void,
+ private_stroke_cred_t *this, shared_key_t *shared, linked_list_t *owners)
+{
+ this->creds->add_shared_list(this->creds, shared, owners);
+}
+
METHOD(stroke_cred_t, destroy, void,
private_stroke_cred_t *this)
{
@@ -1092,6 +1170,8 @@ stroke_cred_t *stroke_cred_create()
.reread = _reread,
.load_ca = _load_ca,
.load_peer = _load_peer,
+ .load_pubkey = _load_pubkey,
+ .add_shared = _add_shared,
.cachecrl = _cachecrl,
.destroy = _destroy,
},
diff --git a/src/libcharon/plugins/stroke/stroke_cred.h b/src/libcharon/plugins/stroke/stroke_cred.h
index ccee7d87c..83e648819 100644
--- a/src/libcharon/plugins/stroke/stroke_cred.h
+++ b/src/libcharon/plugins/stroke/stroke_cred.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -26,6 +27,7 @@
#include <stroke_msg.h>
#include <credentials/credential_set.h>
#include <credentials/certificates/certificate.h>
+#include <utils/linked_list.h>
typedef struct stroke_cred_t stroke_cred_t;
@@ -56,7 +58,7 @@ struct stroke_cred_t {
certificate_t* (*load_ca)(stroke_cred_t *this, char *filename);
/**
- * Load a peer certificate and serve it rhrough the credential_set.
+ * Load a peer certificate and serve it through the credential_set.
*
* @param filename file to load peer cert from
* @return reference to loaded certificate, or NULL
@@ -64,6 +66,26 @@ struct stroke_cred_t {
certificate_t* (*load_peer)(stroke_cred_t *this, char *filename);
/**
+ * Load a raw public key and serve it through the credential_set.
+ *
+ * @param type type of the raw public key (RSA or ECDSA)
+ * @param filename file to load raw public key from
+ * @param identity identity of the raw public key owner
+ * @return reference to loaded raw public key, or NULL
+ */
+ certificate_t* (*load_pubkey)(stroke_cred_t *this, key_type_t type,
+ char *filename, identification_t *identity);
+
+ /**
+ * Add a shared secret to serve through the credential_set.
+ *
+ * @param shared shared key to add, gets owned
+ * @param owners list of owners (identification_t*), gets owned
+ */
+ void (*add_shared)(stroke_cred_t *this, shared_key_t *shared,
+ linked_list_t *owners);
+
+ /**
* Enable/Disable CRL caching to disk.
*
* @param enabled TRUE to enable, FALSE to disable
diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c
index 6b256f29b..c3dea8419 100644
--- a/src/libcharon/plugins/stroke/stroke_list.c
+++ b/src/libcharon/plugins/stroke/stroke_list.c
@@ -708,12 +708,14 @@ static void list_public_key(public_key_t *public, FILE *out)
static void stroke_list_pubkeys(linked_list_t *list, bool utc, FILE *out)
{
bool first = TRUE;
-
- enumerator_t *enumerator = list->create_enumerator(list);
+ time_t now = time(NULL), notBefore, notAfter;
+ enumerator_t *enumerator;
certificate_t *cert;
+ enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, (void**)&cert))
{
+ identification_t *subject = cert->get_subject(cert);
public_key_t *public = cert->get_public_key(cert);
if (public)
@@ -726,6 +728,41 @@ static void stroke_list_pubkeys(linked_list_t *list, bool utc, FILE *out)
}
fprintf(out, "\n");
+ /* list subject if available */
+ if (subject->get_type(subject) != ID_KEY_ID)
+ {
+ fprintf(out, " subject: %#Y\n", subject);
+ }
+
+ /* list validity if available*/
+ cert->get_validity(cert, &now, &notBefore, &notAfter);
+ if (notBefore != UNDEFINED_TIME && notAfter != UNDEFINED_TIME)
+ {
+ fprintf(out, " validity: not before %T, ", &notBefore, utc);
+ if (now < notBefore)
+ {
+ fprintf(out, "not valid yet (valid in %V)\n", &now, &notBefore);
+ }
+ else
+ {
+ fprintf(out, "ok\n");
+ }
+ fprintf(out, " not after %T, ", &notAfter, utc);
+ if (now > notAfter)
+ {
+ fprintf(out, "expired (%V ago)\n", &now, &notAfter);
+ }
+ else
+ {
+ fprintf(out, "ok");
+ if (now > notAfter - CERT_WARNING_INTERVAL * 60 * 60 * 24)
+ {
+ fprintf(out, " (expires in %V)", &now, &notAfter);
+ }
+ fprintf(out, " \n");
+ }
+ }
+
list_public_key(public, out);
public->destroy(public);
}
@@ -842,7 +879,7 @@ static void stroke_list_certs(linked_list_t *list, char *label,
fprintf(out, " subject: \"%Y\"\n", cert->get_subject(cert));
fprintf(out, " issuer: \"%Y\"\n", cert->get_issuer(cert));
- serial = x509->get_serial(x509);
+ serial = chunk_skip_zero(x509->get_serial(x509));
fprintf(out, " serial: %#B\n", &serial);
/* list validity */
@@ -955,7 +992,7 @@ static void stroke_list_acerts(linked_list_t *list, bool utc, FILE *out)
{
fprintf(out, " hissuer: \"%Y\"\n", id);
}
- chunk = ac->get_holderSerial(ac);
+ chunk = chunk_skip_zero(ac->get_holderSerial(ac));
if (chunk.ptr)
{
fprintf(out, " hserial: %#B\n", &chunk);
@@ -967,7 +1004,7 @@ static void stroke_list_acerts(linked_list_t *list, bool utc, FILE *out)
groups->destroy(groups);
}
fprintf(out, " issuer: \"%Y\"\n", cert->get_issuer(cert));
- chunk = ac->get_serial(ac);
+ chunk = chunk_skip_zero(ac->get_serial(ac));
fprintf(out, " serial: %#B\n", &chunk);
/* list validity */
@@ -1024,13 +1061,14 @@ static void stroke_list_crls(linked_list_t *list, bool utc, FILE *out)
fprintf(out, " issuer: \"%Y\"\n", cert->get_issuer(cert));
/* list optional crlNumber */
- chunk = crl->get_serial(crl);
+ chunk = chunk_skip_zero(crl->get_serial(crl));
if (chunk.ptr)
{
fprintf(out, " serial: %#B\n", &chunk);
}
if (crl->is_delta_crl(crl, &chunk))
{
+ chunk = chunk_skip_zero(chunk);
fprintf(out, " delta for: %#B\n", &chunk);
}
diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c
index 4956b011f..7ef15db3c 100644
--- a/src/libcharon/plugins/stroke/stroke_socket.c
+++ b/src/libcharon/plugins/stroke/stroke_socket.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Tobias Brunner
+ * Copyright (C) 2011-2012 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -185,6 +185,7 @@ static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end)
pop_string(msg, &end->auth2);
pop_string(msg, &end->id);
pop_string(msg, &end->id2);
+ pop_string(msg, &end->rsakey);
pop_string(msg, &end->cert);
pop_string(msg, &end->cert2);
pop_string(msg, &end->ca);
@@ -200,6 +201,7 @@ static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end)
DBG2(DBG_CFG, " %sauth2=%s", label, end->auth2);
DBG2(DBG_CFG, " %sid=%s", label, end->id);
DBG2(DBG_CFG, " %sid2=%s", label, end->id2);
+ DBG2(DBG_CFG, " %srsakey=%s", label, end->rsakey);
DBG2(DBG_CFG, " %scert=%s", label, end->cert);
DBG2(DBG_CFG, " %scert2=%s", label, end->cert2);
DBG2(DBG_CFG, " %sca=%s", label, end->ca);
@@ -427,7 +429,7 @@ static void stroke_export(private_stroke_socket_t *this,
{
pop_string(msg, &msg->export.selector);
- if (msg->purge.flags & EXPORT_X509)
+ if (msg->export.flags & EXPORT_X509)
{
enumerator_t *enumerator;
identification_t *id;
@@ -475,6 +477,21 @@ static void stroke_memusage(private_stroke_socket_t *this,
}
/**
+ * Set username and password for a connection
+ */
+static void stroke_user_creds(private_stroke_socket_t *this,
+ stroke_msg_t *msg, FILE *out)
+{
+ pop_string(msg, &msg->user_creds.name);
+ pop_string(msg, &msg->user_creds.username);
+ pop_string(msg, &msg->user_creds.password);
+
+ DBG1(DBG_CFG, "received stroke: user-creds '%s'", msg->user_creds.name);
+
+ this->config->set_user_credentials(this->config, msg, out);
+}
+
+/**
* set the verbosity debug output
*/
static void stroke_loglevel(private_stroke_socket_t *this,
@@ -647,6 +664,9 @@ static job_requeue_t process(stroke_job_context_t *ctx)
case STR_MEMUSAGE:
stroke_memusage(this, msg, out);
break;
+ case STR_USER_CREDS:
+ stroke_user_creds(this, msg, out);
+ break;
default:
DBG1(DBG_CFG, "received unknown stroke");
break;