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;
|
char *pass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private key decryption password
|
||||||
|
*/
|
||||||
|
char *keypass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* users certificate
|
* users certificate
|
||||||
*/
|
*/
|
||||||
@@ -239,8 +244,14 @@ static bool shared_enumerate(shared_enumerator_t *this, shared_key_t **key,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
*key = this->key;
|
*key = this->key;
|
||||||
*me = ID_MATCH_PERFECT;
|
if (me)
|
||||||
*other = ID_MATCH_ANY;
|
{
|
||||||
|
*me = ID_MATCH_PERFECT;
|
||||||
|
}
|
||||||
|
if (other)
|
||||||
|
{
|
||||||
|
*other = ID_MATCH_ANY;
|
||||||
|
}
|
||||||
this->done = TRUE;
|
this->done = TRUE;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -262,18 +273,31 @@ static enumerator_t* create_shared_enumerator(private_nm_creds_t *this,
|
|||||||
identification_t *other)
|
identification_t *other)
|
||||||
{
|
{
|
||||||
shared_enumerator_t *enumerator;
|
shared_enumerator_t *enumerator;
|
||||||
|
chunk_t key;
|
||||||
|
|
||||||
if (!this->pass || !this->user)
|
switch (type)
|
||||||
{
|
{
|
||||||
return NULL;
|
case SHARED_EAP:
|
||||||
}
|
case SHARED_IKE:
|
||||||
if (type != SHARED_EAP && type != SHARED_IKE)
|
if (!this->pass || !this->user)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (me && !me->equals(me, this->user))
|
if (me && !me->equals(me, this->user))
|
||||||
{
|
{
|
||||||
return NULL;
|
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);
|
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->this = this;
|
||||||
enumerator->done = FALSE;
|
enumerator->done = FALSE;
|
||||||
this->lock->read_lock(this->lock);
|
this->lock->read_lock(this->lock);
|
||||||
enumerator->key = shared_key_create(type,
|
enumerator->key = shared_key_create(type, chunk_clone(key));
|
||||||
chunk_clone(chunk_create(this->pass,
|
|
||||||
strlen(this->pass))));
|
|
||||||
return &enumerator->public;
|
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);
|
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
|
* 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.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.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_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.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.clear = (void(*)(nm_creds_t*))clear;
|
||||||
this->public.destroy = (void(*)(nm_creds_t*))destroy;
|
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,
|
void (*set_username_password)(nm_creds_t *this, identification_t *id,
|
||||||
char *password);
|
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.
|
* 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,
|
void (*set_cert_and_key)(nm_creds_t *this, certificate_t *cert,
|
||||||
private_key_t *key);
|
private_key_t *key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the stored credentials.
|
* Clear the stored credentials.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -380,16 +380,15 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
|
|||||||
str = nm_setting_vpn_get_data_item(vpn, "userkey");
|
str = nm_setting_vpn_get_data_item(vpn, "userkey");
|
||||||
if (!agent && str)
|
if (!agent && str)
|
||||||
{
|
{
|
||||||
chunk_t secret;
|
char *secret;
|
||||||
|
|
||||||
secret.ptr = (char*)nm_setting_vpn_get_secret(vpn, "password");
|
secret = (char*)nm_setting_vpn_get_secret(vpn, "password");
|
||||||
if (secret.ptr)
|
if (secret)
|
||||||
{
|
{
|
||||||
secret.len = strlen(secret.ptr);
|
priv->creds->set_key_password(priv->creds, secret);
|
||||||
}
|
}
|
||||||
private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
|
private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
|
||||||
KEY_RSA, BUILD_FROM_FILE, str,
|
KEY_RSA, BUILD_FROM_FILE, str, BUILD_END);
|
||||||
BUILD_PASSPHRASE, secret, BUILD_END);
|
|
||||||
if (!private)
|
if (!private)
|
||||||
{
|
{
|
||||||
g_set_error(err, NM_VPN_PLUGIN_ERROR,
|
g_set_error(err, NM_VPN_PLUGIN_ERROR,
|
||||||
@@ -524,17 +523,10 @@ static gboolean need_secrets(NMVPNPlugin *plugin, NMConnection *connection,
|
|||||||
if (path)
|
if (path)
|
||||||
{
|
{
|
||||||
private_key_t *key;
|
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 */
|
/* try to load/decrypt the private key */
|
||||||
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
|
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
|
||||||
KEY_RSA, BUILD_FROM_FILE, path,
|
KEY_RSA, BUILD_FROM_FILE, path, BUILD_END);
|
||||||
BUILD_PASSPHRASE, secret, BUILD_END);
|
|
||||||
if (key)
|
if (key)
|
||||||
{
|
{
|
||||||
key->destroy(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 {
|
typedef struct {
|
||||||
/** socket we use for prompting */
|
/** socket we use for prompting */
|
||||||
FILE *prompt;
|
FILE *prompt;
|
||||||
/** private key file */
|
/** private key file */
|
||||||
char *file;
|
char *path;
|
||||||
/** buffer for passphrase */
|
/** number of tries */
|
||||||
char buf[256];
|
int try;
|
||||||
} passphrase_cb_data_t;
|
} 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");
|
if (data->try > 5)
|
||||||
return chunk_empty;
|
{
|
||||||
}
|
fprintf(data->prompt, "PIN invalid, giving up.\n");
|
||||||
if (try == 1)
|
return NULL;
|
||||||
{
|
}
|
||||||
fprintf(data->prompt, "Private key '%s' is encrypted\n", data->file);
|
fprintf(data->prompt, "PIN invalid!\n");
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf(data->prompt, "invalid passphrase\n");
|
|
||||||
}
|
}
|
||||||
|
data->try++;
|
||||||
|
fprintf(data->prompt, "Private key '%s' is encrypted.\n", data->path);
|
||||||
fprintf(data->prompt, "Passphrase:\n");
|
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));
|
secret = chunk_create(buf, strlen(buf));
|
||||||
if (secret.len)
|
if (secret.len > 1)
|
||||||
{ /* trim appended \n */
|
{ /* trim appended \n */
|
||||||
secret.len--;
|
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)
|
if (data->try > 1)
|
||||||
{
|
{
|
||||||
fprintf(data->prompt, "PIN invalid, giving up.\n", data->card);
|
fprintf(data->prompt, "PIN invalid, aborting.\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
data->try++;
|
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);
|
chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
|
||||||
if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7))
|
if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7))
|
||||||
{
|
{
|
||||||
|
free(secret.ptr);
|
||||||
if (!prompt)
|
if (!prompt)
|
||||||
{ /* no IO channel to prompt, skip */
|
{ /* no IO channel to prompt, skip */
|
||||||
free(chunk.ptr);
|
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];
|
char path[PATH_MAX];
|
||||||
chunk_t filename;
|
chunk_t filename;
|
||||||
chunk_t secret = chunk_empty;
|
chunk_t secret;
|
||||||
private_key_t *key = NULL;
|
private_key_t *key;
|
||||||
|
|
||||||
err_t ugh = extract_value(&filename, &line);
|
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 (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 = {
|
return TRUE;
|
||||||
.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);
|
|
||||||
}
|
}
|
||||||
|
/* 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
|
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,
|
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type,
|
||||||
BUILD_FROM_FILE, path,
|
BUILD_FROM_FILE, path, BUILD_END);
|
||||||
BUILD_PASSPHRASE, secret, BUILD_END);
|
this->lock->write_lock(this->lock);
|
||||||
|
|
||||||
|
lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
|
||||||
|
mem->destroy(mem);
|
||||||
}
|
}
|
||||||
if (key)
|
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);
|
DBG1(DBG_CFG, " loading private key from '%s' failed", path);
|
||||||
}
|
}
|
||||||
chunk_clear(&secret);
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,12 +57,6 @@ enum builder_part_t {
|
|||||||
BUILD_BLOB_PGP,
|
BUILD_BLOB_PGP,
|
||||||
/** DNS public key blob (RFC 4034, RSA specifc RFC 3110), chunk_t */
|
/** DNS public key blob (RFC 4034, RSA specifc RFC 3110), chunk_t */
|
||||||
BUILD_BLOB_DNSKEY,
|
BUILD_BLOB_DNSKEY,
|
||||||
/** passphrase for e.g. PEM decryption, smartcard unlock, chunk_t */
|
|
||||||
BUILD_PASSPHRASE,
|
|
||||||
/** passphrase callback, chunk_t(*fn)(void *user, int try), void *user.
|
|
||||||
* The callback is invoked until the returned passphrase is accepted, or
|
|
||||||
* a zero-length passphrase is returned. Try starts at 1. */
|
|
||||||
BUILD_PASSPHRASE_CALLBACK,
|
|
||||||
/** key size in bits, as used for key generation, u_int */
|
/** key size in bits, as used for key generation, u_int */
|
||||||
BUILD_KEY_SIZE,
|
BUILD_KEY_SIZE,
|
||||||
/** private key to use for signing, private_key_t* */
|
/** private key to use for signing, private_key_t* */
|
||||||
|
|||||||
@@ -167,8 +167,7 @@ static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg,
|
|||||||
/**
|
/**
|
||||||
* Converts a PEM encoded file into its binary form (RFC 1421, RFC 934)
|
* Converts a PEM encoded file into its binary form (RFC 1421, RFC 934)
|
||||||
*/
|
*/
|
||||||
static status_t pem_to_bin(chunk_t *blob, chunk_t(*cb)(void*,int), void *cb_data,
|
static status_t pem_to_bin(chunk_t *blob, bool *pgp)
|
||||||
bool *pgp)
|
|
||||||
{
|
{
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PEM_PRE = 0,
|
PEM_PRE = 0,
|
||||||
@@ -187,9 +186,10 @@ static status_t pem_to_bin(chunk_t *blob, chunk_t(*cb)(void*,int), void *cb_data
|
|||||||
chunk_t dst = *blob;
|
chunk_t dst = *blob;
|
||||||
chunk_t line = chunk_empty;
|
chunk_t line = chunk_empty;
|
||||||
chunk_t iv = chunk_empty;
|
chunk_t iv = chunk_empty;
|
||||||
chunk_t passphrase;
|
|
||||||
int try = 0;
|
|
||||||
u_char iv_buf[HASH_SIZE_MD5];
|
u_char iv_buf[HASH_SIZE_MD5];
|
||||||
|
status_t status = NOT_FOUND;
|
||||||
|
enumerator_t *enumerator;
|
||||||
|
shared_key_t *shared;
|
||||||
|
|
||||||
dst.len = 0;
|
dst.len = 0;
|
||||||
iv.ptr = iv_buf;
|
iv.ptr = iv_buf;
|
||||||
@@ -326,36 +326,35 @@ static status_t pem_to_bin(chunk_t *blob, chunk_t(*cb)(void*,int), void *cb_data
|
|||||||
{
|
{
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
if (!cb)
|
|
||||||
|
enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
|
||||||
|
SHARED_PRIVATE_KEY_PASS, NULL, NULL);
|
||||||
|
while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
|
||||||
{
|
{
|
||||||
DBG1(DBG_LIB, " missing passphrase");
|
chunk_t passphrase, chunk;
|
||||||
return INVALID_ARG;
|
|
||||||
}
|
passphrase = shared->get_key(shared);
|
||||||
while (TRUE)
|
chunk = chunk_clone(*blob);
|
||||||
{
|
status = pem_decrypt(&chunk, alg, key_size, iv, passphrase);
|
||||||
passphrase = cb(cb_data, ++try);
|
if (status == SUCCESS)
|
||||||
if (!passphrase.len || !passphrase.ptr)
|
|
||||||
{
|
{
|
||||||
return INVALID_ARG;
|
memcpy(blob->ptr, chunk.ptr, chunk.len);
|
||||||
|
blob->len = chunk.len;
|
||||||
}
|
}
|
||||||
switch (pem_decrypt(blob, alg, key_size, iv, passphrase))
|
free(chunk.ptr);
|
||||||
{
|
if (status != INVALID_ARG)
|
||||||
case INVALID_ARG:
|
{ /* try again only if passphrase invalid */
|
||||||
/* bad passphrase, retry */
|
break;
|
||||||
continue;
|
|
||||||
case SUCCESS:
|
|
||||||
return SUCCESS;
|
|
||||||
default:
|
|
||||||
return FAILED;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* load the credential from a blob
|
* load the credential from a blob
|
||||||
*/
|
*/
|
||||||
static void *load_from_blob(chunk_t blob, credential_type_t type, int subtype,
|
static void *load_from_blob(chunk_t blob, credential_type_t type, int subtype,
|
||||||
chunk_t(*cb)(void*,int), void *cb_data,
|
|
||||||
x509_flag_t flags)
|
x509_flag_t flags)
|
||||||
{
|
{
|
||||||
void *cred = NULL;
|
void *cred = NULL;
|
||||||
@@ -364,7 +363,7 @@ static void *load_from_blob(chunk_t blob, credential_type_t type, int subtype,
|
|||||||
blob = chunk_clone(blob);
|
blob = chunk_clone(blob);
|
||||||
if (!is_asn1(blob))
|
if (!is_asn1(blob))
|
||||||
{
|
{
|
||||||
if (pem_to_bin(&blob, cb, cb_data, &pgp) != SUCCESS)
|
if (pem_to_bin(&blob, &pgp) != SUCCESS)
|
||||||
{
|
{
|
||||||
chunk_clear(&blob);
|
chunk_clear(&blob);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -394,7 +393,6 @@ static void *load_from_blob(chunk_t blob, credential_type_t type, int subtype,
|
|||||||
* load the credential from a file
|
* load the credential from a file
|
||||||
*/
|
*/
|
||||||
static void *load_from_file(char *file, credential_type_t type, int subtype,
|
static void *load_from_file(char *file, credential_type_t type, int subtype,
|
||||||
chunk_t(*cb)(void*,int), void *cb_data,
|
|
||||||
x509_flag_t flags)
|
x509_flag_t flags)
|
||||||
{
|
{
|
||||||
void *cred = NULL;
|
void *cred = NULL;
|
||||||
@@ -425,8 +423,7 @@ static void *load_from_file(char *file, credential_type_t type, int subtype,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
cred = load_from_blob(chunk_create(addr, sb.st_size), type, subtype,
|
cred = load_from_blob(chunk_create(addr, sb.st_size), type, subtype, flags);
|
||||||
cb, cb_data, flags);
|
|
||||||
|
|
||||||
munmap(addr, sb.st_size);
|
munmap(addr, sb.st_size);
|
||||||
close(fd);
|
close(fd);
|
||||||
@@ -437,7 +434,6 @@ static void *load_from_file(char *file, credential_type_t type, int subtype,
|
|||||||
* load the credential from a file descriptor
|
* load the credential from a file descriptor
|
||||||
*/
|
*/
|
||||||
static void *load_from_fd(int fd, credential_type_t type, int subtype,
|
static void *load_from_fd(int fd, credential_type_t type, int subtype,
|
||||||
chunk_t(*cb)(void*,int), void *cb_data,
|
|
||||||
x509_flag_t flags)
|
x509_flag_t flags)
|
||||||
{
|
{
|
||||||
char buf[8096];
|
char buf[8096];
|
||||||
@@ -464,20 +460,7 @@ static void *load_from_fd(int fd, credential_type_t type, int subtype,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return load_from_blob(chunk_create(buf, total), type, subtype,
|
return load_from_blob(chunk_create(buf, total), type, subtype, flags);
|
||||||
cb, cb_data, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* passphrase callback to use if passphrase given
|
|
||||||
*/
|
|
||||||
static chunk_t given_passphrase_cb(chunk_t *passphrase, int try)
|
|
||||||
{
|
|
||||||
if (try > 1)
|
|
||||||
{ /* try only once for given passphrases */
|
|
||||||
return chunk_empty;
|
|
||||||
}
|
|
||||||
return *passphrase;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -487,9 +470,7 @@ static void *pem_load(credential_type_t type, int subtype, va_list args)
|
|||||||
{
|
{
|
||||||
char *file = NULL;
|
char *file = NULL;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
chunk_t pem = chunk_empty, passphrase = chunk_empty;
|
chunk_t pem = chunk_empty;
|
||||||
chunk_t (*cb)(void *data, int try) = NULL;
|
|
||||||
void *cb_data = NULL;
|
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
|
||||||
while (TRUE)
|
while (TRUE)
|
||||||
@@ -505,18 +486,6 @@ static void *pem_load(credential_type_t type, int subtype, va_list args)
|
|||||||
case BUILD_BLOB_PEM:
|
case BUILD_BLOB_PEM:
|
||||||
pem = va_arg(args, chunk_t);
|
pem = va_arg(args, chunk_t);
|
||||||
continue;
|
continue;
|
||||||
case BUILD_PASSPHRASE:
|
|
||||||
passphrase = va_arg(args, chunk_t);
|
|
||||||
if (passphrase.len && passphrase.ptr)
|
|
||||||
{
|
|
||||||
cb = (void*)given_passphrase_cb;
|
|
||||||
cb_data = &passphrase;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
case BUILD_PASSPHRASE_CALLBACK:
|
|
||||||
cb = va_arg(args, chunk_t(*)(void*,int));
|
|
||||||
cb_data = va_arg(args, void*);
|
|
||||||
continue;
|
|
||||||
case BUILD_X509_FLAG:
|
case BUILD_X509_FLAG:
|
||||||
flags = va_arg(args, int);
|
flags = va_arg(args, int);
|
||||||
continue;
|
continue;
|
||||||
@@ -530,15 +499,15 @@ static void *pem_load(credential_type_t type, int subtype, va_list args)
|
|||||||
|
|
||||||
if (pem.len)
|
if (pem.len)
|
||||||
{
|
{
|
||||||
return load_from_blob(pem, type, subtype, cb, cb_data, flags);
|
return load_from_blob(pem, type, subtype, flags);
|
||||||
}
|
}
|
||||||
if (file)
|
if (file)
|
||||||
{
|
{
|
||||||
return load_from_file(file, type, subtype, cb, cb_data, flags);
|
return load_from_file(file, type, subtype, flags);
|
||||||
}
|
}
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
{
|
{
|
||||||
return load_from_fd(fd, type, subtype, cb, cb_data, flags);
|
return load_from_fd(fd, type, subtype, flags);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-1
@@ -36,6 +36,7 @@
|
|||||||
#include <credentials/certificates/x509.h>
|
#include <credentials/certificates/x509.h>
|
||||||
#include <credentials/certificates/ac.h>
|
#include <credentials/certificates/ac.h>
|
||||||
#include <credentials/keys/private_key.h>
|
#include <credentials/keys/private_key.h>
|
||||||
|
#include <credentials/sets/mem_cred.h>
|
||||||
#include <utils/optionsfrom.h>
|
#include <utils/optionsfrom.h>
|
||||||
|
|
||||||
#define OPENAC_PATH IPSEC_CONFDIR "/openac"
|
#define OPENAC_PATH IPSEC_CONFDIR "/openac"
|
||||||
@@ -437,10 +438,19 @@ int main(int argc, char **argv)
|
|||||||
/* load the signer's RSA private key */
|
/* load the signer's RSA private key */
|
||||||
if (keyfile != NULL)
|
if (keyfile != NULL)
|
||||||
{
|
{
|
||||||
|
mem_cred_t *mem;
|
||||||
|
shared_key_t *shared;
|
||||||
|
|
||||||
|
mem = mem_cred_create();
|
||||||
|
lib->credmgr->add_set(lib->credmgr, &mem->set);
|
||||||
|
shared = shared_key_create(SHARED_PRIVATE_KEY_PASS,
|
||||||
|
chunk_clone(passphrase));
|
||||||
|
mem->add_shared(mem, shared, NULL);
|
||||||
signerKey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
|
signerKey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
|
||||||
BUILD_FROM_FILE, keyfile,
|
BUILD_FROM_FILE, keyfile,
|
||||||
BUILD_PASSPHRASE, passphrase,
|
|
||||||
BUILD_END);
|
BUILD_END);
|
||||||
|
lib->credmgr->remove_set(lib->credmgr, &mem->set);
|
||||||
|
mem->destroy(mem);
|
||||||
if (signerKey == NULL)
|
if (signerKey == NULL)
|
||||||
{
|
{
|
||||||
goto end;
|
goto end;
|
||||||
|
|||||||
@@ -97,90 +97,6 @@ cert_t* cert_add(cert_t *cert)
|
|||||||
return cert;
|
return cert;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Passphrase callback to read from whack fd
|
|
||||||
*/
|
|
||||||
chunk_t whack_pass_cb(prompt_pass_t *pass, int try)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
|
|
||||||
if (try > MAX_PROMPT_PASS_TRIALS)
|
|
||||||
{
|
|
||||||
whack_log(RC_LOG_SERIOUS, "invalid passphrase, too many trials");
|
|
||||||
return chunk_empty;
|
|
||||||
}
|
|
||||||
if (try == 1)
|
|
||||||
{
|
|
||||||
whack_log(RC_ENTERSECRET, "need passphrase for 'private key'");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
whack_log(RC_ENTERSECRET, "invalid passphrase, please try again");
|
|
||||||
}
|
|
||||||
|
|
||||||
n = read(pass->fd, pass->secret, PROMPT_PASS_LEN);
|
|
||||||
|
|
||||||
if (n == -1)
|
|
||||||
{
|
|
||||||
whack_log(RC_LOG_SERIOUS, "read(whackfd) failed");
|
|
||||||
return chunk_empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
pass->secret[n-1] = '\0';
|
|
||||||
|
|
||||||
if (strlen(pass->secret) == 0)
|
|
||||||
{
|
|
||||||
whack_log(RC_LOG_SERIOUS, "no passphrase entered, aborted");
|
|
||||||
return chunk_empty;
|
|
||||||
}
|
|
||||||
return chunk_create(pass->secret, strlen(pass->secret));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a PKCS#1 or PGP private key file
|
|
||||||
*/
|
|
||||||
private_key_t* load_private_key(char* filename, prompt_pass_t *pass,
|
|
||||||
key_type_t type)
|
|
||||||
{
|
|
||||||
private_key_t *key = NULL;
|
|
||||||
char *path;
|
|
||||||
|
|
||||||
path = concatenate_paths(PRIVATE_KEY_PATH, filename);
|
|
||||||
if (pass && pass->prompt && pass->fd != NULL_FD)
|
|
||||||
{ /* use passphrase callback */
|
|
||||||
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
|
|
||||||
BUILD_FROM_FILE, path,
|
|
||||||
BUILD_PASSPHRASE_CALLBACK, whack_pass_cb, pass,
|
|
||||||
BUILD_END);
|
|
||||||
if (key)
|
|
||||||
{
|
|
||||||
whack_log(RC_SUCCESS, "valid passphrase");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (pass)
|
|
||||||
{ /* use a given passphrase */
|
|
||||||
chunk_t password = chunk_create(pass->secret, strlen(pass->secret));
|
|
||||||
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
|
|
||||||
BUILD_FROM_FILE, path,
|
|
||||||
BUILD_PASSPHRASE, password, BUILD_END);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ /* no passphrase */
|
|
||||||
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
|
|
||||||
BUILD_FROM_FILE, path, BUILD_END);
|
|
||||||
|
|
||||||
}
|
|
||||||
if (key)
|
|
||||||
{
|
|
||||||
plog(" loaded private key from '%s'", filename);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
plog(" syntax error in private key file");
|
|
||||||
}
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a X.509 or OpenPGP certificate
|
* Loads a X.509 or OpenPGP certificate
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -65,8 +65,6 @@ extern const cert_t cert_empty;
|
|||||||
*/
|
*/
|
||||||
extern bool no_cr_send;
|
extern bool no_cr_send;
|
||||||
|
|
||||||
extern private_key_t* load_private_key(char* filename, prompt_pass_t *pass,
|
|
||||||
key_type_t type);
|
|
||||||
extern cert_t* load_cert(char *filename, const char *label, x509_flag_t flags);
|
extern cert_t* load_cert(char *filename, const char *label, x509_flag_t flags);
|
||||||
extern cert_t* load_host_cert(char *filename);
|
extern cert_t* load_host_cert(char *filename);
|
||||||
extern cert_t* load_ca_cert(char *filename);
|
extern cert_t* load_ca_cert(char *filename);
|
||||||
|
|||||||
@@ -66,15 +66,6 @@ extern const char* check_expiry(time_t expiration_date,
|
|||||||
#define MAX_PROMPT_PASS_TRIALS 5
|
#define MAX_PROMPT_PASS_TRIALS 5
|
||||||
#define PROMPT_PASS_LEN 64
|
#define PROMPT_PASS_LEN 64
|
||||||
|
|
||||||
/* struct used to prompt for a secret passphrase
|
|
||||||
* from a console with file descriptor fd
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
char secret[PROMPT_PASS_LEN+1];
|
|
||||||
bool prompt;
|
|
||||||
int fd;
|
|
||||||
} prompt_pass_t;
|
|
||||||
|
|
||||||
/* filter eliminating the directory entries '.' and '..' */
|
/* filter eliminating the directory entries '.' and '..' */
|
||||||
typedef struct dirent dirent_t;
|
typedef struct dirent dirent_t;
|
||||||
extern int file_select(const dirent_t *entry);
|
extern int file_select(const dirent_t *entry);
|
||||||
|
|||||||
@@ -37,6 +37,8 @@
|
|||||||
#include <library.h>
|
#include <library.h>
|
||||||
#include <asn1/asn1.h>
|
#include <asn1/asn1.h>
|
||||||
#include <credentials/certificates/pgp_certificate.h>
|
#include <credentials/certificates/pgp_certificate.h>
|
||||||
|
#include <credentials/sets/mem_cred.h>
|
||||||
|
#include <credentials/sets/callback_cred.h>
|
||||||
|
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
@@ -539,6 +541,123 @@ end:
|
|||||||
return ugh;
|
return ugh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* struct used to prompt for a secret passphrase
|
||||||
|
* from a console with file descriptor fd
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
char secret[PROMPT_PASS_LEN+1];
|
||||||
|
bool prompt;
|
||||||
|
int fd;
|
||||||
|
int try;
|
||||||
|
} prompt_pass_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Passphrase callback to read from whack fd
|
||||||
|
*/
|
||||||
|
static shared_key_t* whack_pass_cb(prompt_pass_t *pass,
|
||||||
|
identification_t *me, identification_t *other,
|
||||||
|
id_match_t *match_me, id_match_t *match_other)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (pass->try > MAX_PROMPT_PASS_TRIALS)
|
||||||
|
{
|
||||||
|
whack_log(RC_LOG_SERIOUS, "invalid passphrase, too many trials");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (pass->try == 1)
|
||||||
|
{
|
||||||
|
whack_log(RC_ENTERSECRET, "need passphrase for 'private key'");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
whack_log(RC_ENTERSECRET, "invalid passphrase, please try again");
|
||||||
|
}
|
||||||
|
pass->try++;
|
||||||
|
|
||||||
|
n = read(pass->fd, pass->secret, PROMPT_PASS_LEN);
|
||||||
|
if (n == -1)
|
||||||
|
{
|
||||||
|
whack_log(RC_LOG_SERIOUS, "read(whackfd) failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
pass->secret[n-1] = '\0';
|
||||||
|
|
||||||
|
if (strlen(pass->secret) == 0)
|
||||||
|
{
|
||||||
|
whack_log(RC_LOG_SERIOUS, "no passphrase entered, aborted");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
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(chunk_create(pass->secret, strlen(pass->secret))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a PKCS#1 or PGP private key file
|
||||||
|
*/
|
||||||
|
static private_key_t* load_private_key(char* filename, prompt_pass_t *pass,
|
||||||
|
key_type_t type)
|
||||||
|
{
|
||||||
|
private_key_t *key = NULL;
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
path = concatenate_paths(PRIVATE_KEY_PATH, filename);
|
||||||
|
if (pass && pass->prompt && pass->fd != NULL_FD)
|
||||||
|
{ /* use passphrase callback */
|
||||||
|
callback_cred_t *cb;
|
||||||
|
|
||||||
|
cb = callback_cred_create_shared((void*)whack_pass_cb, pass);
|
||||||
|
lib->credmgr->add_local_set(lib->credmgr, &cb->set);
|
||||||
|
|
||||||
|
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
|
||||||
|
BUILD_FROM_FILE, path, BUILD_END);
|
||||||
|
lib->credmgr->remove_local_set(lib->credmgr, &cb->set);
|
||||||
|
cb->destroy(cb);
|
||||||
|
if (key)
|
||||||
|
{
|
||||||
|
whack_log(RC_SUCCESS, "valid passphrase");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pass)
|
||||||
|
{ /* use a given passphrase */
|
||||||
|
mem_cred_t *mem;
|
||||||
|
shared_key_t *shared;
|
||||||
|
|
||||||
|
mem = mem_cred_create();
|
||||||
|
lib->credmgr->add_local_set(lib->credmgr, &mem->set);
|
||||||
|
shared = shared_key_create(SHARED_PRIVATE_KEY_PASS,
|
||||||
|
chunk_clone(chunk_create(pass->secret, strlen(pass->secret))));
|
||||||
|
mem->add_shared(mem, shared, NULL);
|
||||||
|
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
|
||||||
|
BUILD_FROM_FILE, path, BUILD_END);
|
||||||
|
lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
|
||||||
|
mem->destroy(mem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ /* no passphrase */
|
||||||
|
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
|
||||||
|
BUILD_FROM_FILE, path, BUILD_END);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (key)
|
||||||
|
{
|
||||||
|
plog(" loaded private key from '%s'", filename);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plog(" syntax error in private key file");
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* process a key file protected with optional passphrase which can either be
|
* process a key file protected with optional passphrase which can either be
|
||||||
* read from ipsec.secrets or prompted for by using whack
|
* read from ipsec.secrets or prompted for by using whack
|
||||||
@@ -552,6 +671,7 @@ static err_t process_keyfile(private_key_t **key, key_type_t type, int whackfd)
|
|||||||
memset(pass.secret,'\0', sizeof(pass.secret));
|
memset(pass.secret,'\0', sizeof(pass.secret));
|
||||||
pass.prompt = FALSE;
|
pass.prompt = FALSE;
|
||||||
pass.fd = whackfd;
|
pass.fd = whackfd;
|
||||||
|
pass.try = 1;
|
||||||
|
|
||||||
/* we expect the filename of a PKCS#1 private key file */
|
/* we expect the filename of a PKCS#1 private key file */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user