Obseleted BUILD_PASSPHRASE(_CALLBACK) for private key loading, use credential sets
This commit is contained in:
@@ -50,6 +50,11 @@ struct private_nm_creds_t {
|
||||
*/
|
||||
char *pass;
|
||||
|
||||
/**
|
||||
* Private key decryption password
|
||||
*/
|
||||
char *keypass;
|
||||
|
||||
/**
|
||||
* users certificate
|
||||
*/
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -369,6 +391,17 @@ static void set_username_password(private_nm_creds_t *this, identification_t *id
|
||||
this->lock->unlock(this->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
if (data->try > 1)
|
||||
{
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user