diff options
Diffstat (limited to 'src/libcharon/plugins/stroke')
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_config.c | 185 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_config.h | 10 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_cred.c | 82 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_cred.h | 24 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_list.c | 50 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_socket.c | 24 |
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, ¬Before, ¬After); + if (notBefore != UNDEFINED_TIME && notAfter != UNDEFINED_TIME) + { + fprintf(out, " validity: not before %T, ", ¬Before, utc); + if (now < notBefore) + { + fprintf(out, "not valid yet (valid in %V)\n", &now, ¬Before); + } + else + { + fprintf(out, "ok\n"); + } + fprintf(out, " not after %T, ", ¬After, utc); + if (now > notAfter) + { + fprintf(out, "expired (%V ago)\n", &now, ¬After); + } + else + { + fprintf(out, "ok"); + if (now > notAfter - CERT_WARNING_INTERVAL * 60 * 60 * 24) + { + fprintf(out, " (expires in %V)", &now, ¬After); + } + 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; |