diff options
Diffstat (limited to 'src/libcharon')
-rw-r--r-- | src/libcharon/plugins/nm/nm_creds.c | 64 | ||||
-rw-r--r-- | src/libcharon/plugins/nm/nm_creds.h | 9 | ||||
-rw-r--r-- | src/libcharon/plugins/nm/nm_service.c | 20 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_cred.c | 114 |
4 files changed, 141 insertions, 66 deletions
diff --git a/src/libcharon/plugins/nm/nm_creds.c b/src/libcharon/plugins/nm/nm_creds.c index 193838e6b..4ee94362f 100644 --- a/src/libcharon/plugins/nm/nm_creds.c +++ b/src/libcharon/plugins/nm/nm_creds.c @@ -51,6 +51,11 @@ struct private_nm_creds_t { char *pass; /** + * Private key decryption password + */ + char *keypass; + + /** * users certificate */ certificate_t *usercert; @@ -239,8 +244,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 +273,31 @@ 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; + default: + return NULL; } enumerator = malloc_thing(shared_enumerator_t); @@ -282,9 +306,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 +392,17 @@ 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_cert_and_key */ static void set_cert_and_key(private_nm_creds_t *this, certificate_t *cert, @@ -430,6 +463,7 @@ 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_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; diff --git a/src/libcharon/plugins/nm/nm_creds.h b/src/libcharon/plugins/nm/nm_creds.h index b55cff31e..44936dd6a 100644 --- a/src/libcharon/plugins/nm/nm_creds.h +++ b/src/libcharon/plugins/nm/nm_creds.h @@ -58,6 +58,14 @@ 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 certificate and private key to use for client authentication. * @@ -66,6 +74,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_service.c b/src/libcharon/plugins/nm/nm_service.c index 07318bbbf..910b01cc8 100644 --- a/src/libcharon/plugins/nm/nm_service.c +++ b/src/libcharon/plugins/nm/nm_service.c @@ -380,16 +380,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 +523,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); diff --git a/src/libcharon/plugins/stroke/stroke_cred.c b/src/libcharon/plugins/stroke/stroke_cred.c index cfa33a746..69e2054f8 100644 --- a/src/libcharon/plugins/stroke/stroke_cred.c +++ b/src/libcharon/plugins/stroke/stroke_cred.c @@ -674,47 +674,57 @@ static err_t extract_secret(chunk_t *secret, chunk_t *line) } /** - * Data to pass to passphrase_cb + * Data for passphrase callback */ typedef struct { /** socket we use for prompting */ FILE *prompt; /** private key file */ - char *file; - /** buffer for passphrase */ - char buf[256]; + char *path; + /** number of tries */ + int try; } passphrase_cb_data_t; /** - * Passphrase callback to read from stroke fd + * Callback function to receive Passphrases */ -chunk_t passphrase_cb(passphrase_cb_data_t *data, int try) +static shared_key_t* passphrase_cb(passphrase_cb_data_t *data, + identification_t *me, identification_t *other, + id_match_t *match_me, id_match_t *match_other) { - chunk_t secret = chunk_empty;; + chunk_t secret; + char buf[256]; - if (try > 5) - { - fprintf(data->prompt, "invalid passphrase, too many trials\n"); - return chunk_empty; - } - if (try == 1) - { - fprintf(data->prompt, "Private key '%s' is encrypted\n", data->file); - } - else + if (data->try > 1) { - fprintf(data->prompt, "invalid passphrase\n"); + if (data->try > 5) + { + fprintf(data->prompt, "PIN invalid, giving up.\n"); + return NULL; + } + fprintf(data->prompt, "PIN invalid!\n"); } + data->try++; + fprintf(data->prompt, "Private key '%s' is encrypted.\n", data->path); fprintf(data->prompt, "Passphrase:\n"); - if (fgets(data->buf, sizeof(data->buf), data->prompt)) + if (fgets(buf, sizeof(buf), data->prompt)) { - secret = chunk_create(data->buf, strlen(data->buf)); - if (secret.len) + secret = chunk_create(buf, strlen(buf)); + if (secret.len > 1) { /* trim appended \n */ secret.len--; + if (match_me) + { + *match_me = ID_MATCH_PERFECT; + } + if (match_other) + { + *match_other = ID_MATCH_NONE; + } + return shared_key_create(SHARED_PRIVATE_KEY_PASS, chunk_clone(secret)); } } - return secret; + return NULL; } /** @@ -748,7 +758,7 @@ static shared_key_t* pin_cb(pin_cb_data_t *data, if (data->try > 1) { - fprintf(data->prompt, "PIN invalid, giving up.\n", data->card); + fprintf(data->prompt, "PIN invalid, aborting.\n"); return NULL; } data->try++; @@ -859,6 +869,7 @@ static bool load_pin(private_stroke_cred_t *this, chunk_t line, int line_nr, chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL); if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7)) { + free(secret.ptr); if (!prompt) { /* no IO channel to prompt, skip */ free(chunk.ptr); @@ -933,8 +944,8 @@ static bool load_private(private_stroke_cred_t *this, chunk_t line, int line_nr, { char path[PATH_MAX]; chunk_t filename; - chunk_t secret = chunk_empty; - private_key_t *key = NULL; + chunk_t secret; + private_key_t *key; err_t ugh = extract_value(&filename, &line); @@ -972,23 +983,53 @@ static bool load_private(private_stroke_cred_t *this, chunk_t line, int line_nr, } if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7)) { - if (prompt) + callback_cred_t *cb = NULL; + passphrase_cb_data_t pp_data = { + .prompt = prompt, + .path = path, + .try = 1, + }; + + free(secret.ptr); + if (!prompt) { - passphrase_cb_data_t data = { - .prompt = prompt, - .file = path, - }; - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, - key_type, BUILD_FROM_FILE, path, - BUILD_PASSPHRASE_CALLBACK, - passphrase_cb, &data, BUILD_END); + return TRUE; } + /* use callback credential set to prompt for the passphrase */ + pp_data.prompt = prompt; + pp_data.path = path; + pp_data.try = 1; + cb = callback_cred_create_shared((void*)passphrase_cb, &pp_data); + lib->credmgr->add_local_set(lib->credmgr, &cb->set); + + /* unlock, as the builder might ask for a secret */ + this->lock->unlock(this->lock); + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type, + BUILD_FROM_FILE, path, BUILD_END); + this->lock->write_lock(this->lock); + + lib->credmgr->remove_local_set(lib->credmgr, &cb->set); + cb->destroy(cb); } else { + mem_cred_t *mem = NULL; + shared_key_t *shared; + + /* provide our pin in a temporary credential set */ + shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, secret); + mem = mem_cred_create(); + mem->add_shared(mem, shared, NULL); + lib->credmgr->add_local_set(lib->credmgr, &mem->set); + + /* unlock, as the builder might ask for a secret */ + this->lock->unlock(this->lock); key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type, - BUILD_FROM_FILE, path, - BUILD_PASSPHRASE, secret, BUILD_END); + BUILD_FROM_FILE, path, BUILD_END); + this->lock->write_lock(this->lock); + + lib->credmgr->remove_local_set(lib->credmgr, &mem->set); + mem->destroy(mem); } if (key) { @@ -1000,7 +1041,6 @@ static bool load_private(private_stroke_cred_t *this, chunk_t line, int line_nr, { DBG1(DBG_CFG, " loading private key from '%s' failed", path); } - chunk_clear(&secret); return TRUE; } |