diff options
Diffstat (limited to 'src')
-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 | ||||
-rw-r--r-- | src/libstrongswan/credentials/builder.h | 6 | ||||
-rw-r--r-- | src/libstrongswan/plugins/pem/pem_builder.c | 89 | ||||
-rwxr-xr-x | src/openac/openac.c | 12 | ||||
-rw-r--r-- | src/pluto/certs.c | 84 | ||||
-rw-r--r-- | src/pluto/certs.h | 2 | ||||
-rw-r--r-- | src/pluto/defs.h | 9 | ||||
-rw-r--r-- | src/pluto/keys.c | 120 |
11 files changed, 301 insertions, 228 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; } diff --git a/src/libstrongswan/credentials/builder.h b/src/libstrongswan/credentials/builder.h index 996ce8362..dc87da2a4 100644 --- a/src/libstrongswan/credentials/builder.h +++ b/src/libstrongswan/credentials/builder.h @@ -57,12 +57,6 @@ enum builder_part_t { BUILD_BLOB_PGP, /** DNS public key blob (RFC 4034, RSA specifc RFC 3110), chunk_t */ 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 */ BUILD_KEY_SIZE, /** private key to use for signing, private_key_t* */ diff --git a/src/libstrongswan/plugins/pem/pem_builder.c b/src/libstrongswan/plugins/pem/pem_builder.c index a15c3f258..34527d992 100644 --- a/src/libstrongswan/plugins/pem/pem_builder.c +++ b/src/libstrongswan/plugins/pem/pem_builder.c @@ -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) */ -static status_t pem_to_bin(chunk_t *blob, chunk_t(*cb)(void*,int), void *cb_data, - bool *pgp) +static status_t pem_to_bin(chunk_t *blob, bool *pgp) { typedef enum { 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 line = chunk_empty; chunk_t iv = chunk_empty; - chunk_t passphrase; - int try = 0; u_char iv_buf[HASH_SIZE_MD5]; + status_t status = NOT_FOUND; + enumerator_t *enumerator; + shared_key_t *shared; dst.len = 0; 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; } - if (!cb) - { - DBG1(DBG_LIB, " missing passphrase"); - return INVALID_ARG; - } - while (TRUE) + + enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr, + SHARED_PRIVATE_KEY_PASS, NULL, NULL); + while (enumerator->enumerate(enumerator, &shared, NULL, NULL)) { - passphrase = cb(cb_data, ++try); - if (!passphrase.len || !passphrase.ptr) + chunk_t passphrase, chunk; + + passphrase = shared->get_key(shared); + chunk = chunk_clone(*blob); + status = pem_decrypt(&chunk, alg, key_size, iv, passphrase); + if (status == SUCCESS) { - return INVALID_ARG; + memcpy(blob->ptr, chunk.ptr, chunk.len); + blob->len = chunk.len; } - switch (pem_decrypt(blob, alg, key_size, iv, passphrase)) - { - case INVALID_ARG: - /* bad passphrase, retry */ - continue; - case SUCCESS: - return SUCCESS; - default: - return FAILED; + free(chunk.ptr); + if (status != INVALID_ARG) + { /* try again only if passphrase invalid */ + break; } } + enumerator->destroy(enumerator); + return status; } /** * load the credential from a blob */ 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) { 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); if (!is_asn1(blob)) { - if (pem_to_bin(&blob, cb, cb_data, &pgp) != SUCCESS) + if (pem_to_bin(&blob, &pgp) != SUCCESS) { chunk_clear(&blob); 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 */ 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) { void *cred = NULL; @@ -425,8 +423,7 @@ static void *load_from_file(char *file, credential_type_t type, int subtype, return NULL; } - cred = load_from_blob(chunk_create(addr, sb.st_size), type, subtype, - cb, cb_data, flags); + cred = load_from_blob(chunk_create(addr, sb.st_size), type, subtype, flags); munmap(addr, sb.st_size); 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 */ 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) { char buf[8096]; @@ -464,20 +460,7 @@ static void *load_from_fd(int fd, credential_type_t type, int subtype, return NULL; } } - return load_from_blob(chunk_create(buf, total), type, subtype, - 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; + return load_from_blob(chunk_create(buf, total), type, subtype, flags); } /** @@ -487,9 +470,7 @@ static void *pem_load(credential_type_t type, int subtype, va_list args) { char *file = NULL; int fd = -1; - chunk_t pem = chunk_empty, passphrase = chunk_empty; - chunk_t (*cb)(void *data, int try) = NULL; - void *cb_data = NULL; + chunk_t pem = chunk_empty; int flags = 0; while (TRUE) @@ -505,18 +486,6 @@ static void *pem_load(credential_type_t type, int subtype, va_list args) case BUILD_BLOB_PEM: pem = va_arg(args, chunk_t); 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: flags = va_arg(args, int); continue; @@ -530,15 +499,15 @@ static void *pem_load(credential_type_t type, int subtype, va_list args) if (pem.len) { - return load_from_blob(pem, type, subtype, cb, cb_data, flags); + return load_from_blob(pem, type, subtype, flags); } if (file) { - return load_from_file(file, type, subtype, cb, cb_data, flags); + return load_from_file(file, type, subtype, flags); } if (fd != -1) { - return load_from_fd(fd, type, subtype, cb, cb_data, flags); + return load_from_fd(fd, type, subtype, flags); } return NULL; } diff --git a/src/openac/openac.c b/src/openac/openac.c index 3f28b0ac4..5de8f5b7c 100755 --- a/src/openac/openac.c +++ b/src/openac/openac.c @@ -36,6 +36,7 @@ #include <credentials/certificates/x509.h> #include <credentials/certificates/ac.h> #include <credentials/keys/private_key.h> +#include <credentials/sets/mem_cred.h> #include <utils/optionsfrom.h> #define OPENAC_PATH IPSEC_CONFDIR "/openac" @@ -437,10 +438,19 @@ int main(int argc, char **argv) /* load the signer's RSA private key */ 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, BUILD_FROM_FILE, keyfile, - BUILD_PASSPHRASE, passphrase, BUILD_END); + lib->credmgr->remove_set(lib->credmgr, &mem->set); + mem->destroy(mem); if (signerKey == NULL) { goto end; diff --git a/src/pluto/certs.c b/src/pluto/certs.c index 24e8ffb27..414f2430a 100644 --- a/src/pluto/certs.c +++ b/src/pluto/certs.c @@ -98,90 +98,6 @@ cert_t* cert_add(cert_t *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 */ cert_t* load_cert(char *filename, const char *label, x509_flag_t flags) diff --git a/src/pluto/certs.h b/src/pluto/certs.h index 21e856a3c..b31c4c3ed 100644 --- a/src/pluto/certs.h +++ b/src/pluto/certs.h @@ -65,8 +65,6 @@ extern const cert_t cert_empty; */ 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_host_cert(char *filename); extern cert_t* load_ca_cert(char *filename); diff --git a/src/pluto/defs.h b/src/pluto/defs.h index 8491f4ae8..1eeae28b0 100644 --- a/src/pluto/defs.h +++ b/src/pluto/defs.h @@ -66,15 +66,6 @@ extern const char* check_expiry(time_t expiration_date, #define MAX_PROMPT_PASS_TRIALS 5 #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 '..' */ typedef struct dirent dirent_t; extern int file_select(const dirent_t *entry); diff --git a/src/pluto/keys.c b/src/pluto/keys.c index 6db757ba7..dc78b0e7f 100644 --- a/src/pluto/keys.c +++ b/src/pluto/keys.c @@ -37,6 +37,8 @@ #include <library.h> #include <asn1/asn1.h> #include <credentials/certificates/pgp_certificate.h> +#include <credentials/sets/mem_cred.h> +#include <credentials/sets/callback_cred.h> #include "constants.h" #include "defs.h" @@ -539,6 +541,123 @@ end: 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 * 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)); pass.prompt = FALSE; pass.fd = whackfd; + pass.try = 1; /* we expect the filename of a PKCS#1 private key file */ |