/*
- * Copyright (C) 2008 Tobias Brunner
+ * Copyright (C) 2008-2013 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* for more details.
*/
+#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+#ifdef HAVE_GLOB_H
#include <glob.h>
-#include <libgen.h>
+#endif
#include "stroke_cred.h"
-#include "stroke_shared_key.h"
#include <credentials/certificates/x509.h>
#include <credentials/certificates/crl.h>
#include <credentials/certificates/ac.h>
-#include <utils/linked_list.h>
+#include <credentials/containers/pkcs12.h>
+#include <credentials/sets/mem_cred.h>
+#include <credentials/sets/callback_cred.h>
+#include <collections/linked_list.h>
#include <utils/lexparser.h>
#include <threading/rwlock.h>
#include <daemon.h>
stroke_cred_t public;
/**
- * list of trusted peer/signer/CA certificates (certificate_t)
- */
- linked_list_t *certs;
-
- /**
- * list of shared secrets (private_shared_key_t)
+ * secrets file with credential information
*/
- linked_list_t *shared;
+ char *secrets_file;
/**
- * list of private keys (private_key_t)
+ * credentials
*/
- linked_list_t *private;
+ mem_cred_t *creds;
/**
- * read-write lock to lists
+ * ignore missing CA basic constraint (i.e. treat all certificates in
+ * ipsec.conf ca sections and ipsec.d/cacerts as CA certificates)
*/
- rwlock_t *lock;
+ bool force_ca_cert;
/**
* cache CRLs to disk?
bool cachecrl;
};
-/**
- * data to pass to various filters
- */
-typedef struct {
- private_stroke_cred_t *this;
- identification_t *id;
- certificate_type_t type;
-} id_data_t;
-
-/**
- * destroy id enumerator data and unlock list
- */
-static void id_data_destroy(id_data_t *data)
-{
- data->this->lock->unlock(data->this->lock);
- free(data);
-}
-
-/**
- * filter function for private key enumerator
- */
-static bool private_filter(id_data_t *data,
- private_key_t **in, private_key_t **out)
-{
- private_key_t *key;
-
- key = *in;
- if (data->id == NULL)
- {
- *out = key;
- return TRUE;
- }
- if (key->has_fingerprint(key, data->id->get_encoding(data->id)))
- {
- *out = key;
- return TRUE;
- }
- return FALSE;
-}
+/** Length of smartcard specifier parts (module, keyid) */
+#define SC_PART_LEN 128
/**
- * Implements credential_set_t.create_private_enumerator
+ * Kind of smartcard specifier token
*/
-static enumerator_t* create_private_enumerator(private_stroke_cred_t *this,
- key_type_t type, identification_t *id)
-{
- id_data_t *data;
-
- data = malloc_thing(id_data_t);
- data->this = this;
- data->id = id;
-
- this->lock->read_lock(this->lock);
- return enumerator_create_filter(this->private->create_enumerator(this->private),
- (void*)private_filter, data,
- (void*)id_data_destroy);
-}
+typedef enum {
+ SC_FORMAT_SLOT_MODULE_KEYID,
+ SC_FORMAT_SLOT_KEYID,
+ SC_FORMAT_KEYID,
+ SC_FORMAT_INVALID,
+} smartcard_format_t;
/**
- * filter function for certs enumerator
+ * Parse a smartcard specifier token
*/
-static bool certs_filter(id_data_t *data, certificate_t **in, certificate_t **out)
+static smartcard_format_t parse_smartcard(char *smartcard, u_int *slot,
+ char *module, char *keyid)
{
- public_key_t *public;
- certificate_t *cert = *in;
-
- if (data->type != CERT_ANY && data->type != cert->get_type(cert))
- {
- return FALSE;
- }
- if (data->id == NULL || cert->has_subject(cert, data->id))
- {
- *out = *in;
- return TRUE;
- }
+ /* The token has one of the following three formats:
+ * - %smartcard<slot>@<module>:<keyid>
+ * - %smartcard<slot>:<keyid>
+ * - %smartcard:<keyid>
+ */
+ char buf[2 * SC_PART_LEN], *pos;
- public = cert->get_public_key(cert);
- if (public)
+ if (sscanf(smartcard, "%%smartcard%u@%255s", slot, buf) == 2)
{
- if (public->has_fingerprint(public, data->id->get_encoding(data->id)))
+ pos = strchr(buf, ':');
+ if (!pos)
{
- public->destroy(public);
- *out = *in;
- return TRUE;
+ return SC_FORMAT_INVALID;
}
- public->destroy(public);
- }
- return FALSE;
-}
-
-/**
- * Implements credential_set_t.create_cert_enumerator
- */
-static enumerator_t* create_cert_enumerator(private_stroke_cred_t *this,
- certificate_type_t cert, key_type_t key,
- identification_t *id, bool trusted)
-{
- id_data_t *data;
-
- if (trusted && (cert == CERT_X509_CRL || cert == CERT_X509_AC))
- {
- return NULL;
- }
- data = malloc_thing(id_data_t);
- data->this = this;
- data->id = id;
- data->type = cert;
-
- this->lock->read_lock(this->lock);
- return enumerator_create_filter(this->certs->create_enumerator(this->certs),
- (void*)certs_filter, data,
- (void*)id_data_destroy);
-}
-
-typedef struct {
- private_stroke_cred_t *this;
- identification_t *me;
- identification_t *other;
- shared_key_type_t type;
-} shared_data_t;
-
-/**
- * free shared key enumerator data and unlock list
- */
-static void shared_data_destroy(shared_data_t *data)
-{
- data->this->lock->unlock(data->this->lock);
- free(data);
-}
-
-/**
- * filter function for certs enumerator
- */
-static bool shared_filter(shared_data_t *data,
- stroke_shared_key_t **in, shared_key_t **out,
- void **unused1, id_match_t *me,
- void **unused2, id_match_t *other)
-{
- id_match_t my_match = ID_MATCH_NONE, other_match = ID_MATCH_NONE;
- stroke_shared_key_t *stroke = *in;
- shared_key_t *shared = &stroke->shared;
-
- if (data->type != SHARED_ANY && shared->get_type(shared) != data->type)
- {
- return FALSE;
- }
-
- if (data->me)
- {
- my_match = stroke->has_owner(stroke, data->me);
- }
- if (data->other)
- {
- other_match = stroke->has_owner(stroke, data->other);
- }
- if ((data->me || data->other) && (!my_match && !other_match))
- {
- return FALSE;
+ *pos++ = '\0';
+ snprintf(module, SC_PART_LEN, "%s", buf);
+ snprintf(keyid, SC_PART_LEN, "%s", pos);
+ return SC_FORMAT_SLOT_MODULE_KEYID;
}
- *out = shared;
- if (me)
+ if (sscanf(smartcard, "%%smartcard%u:%127s", slot, keyid) == 2)
{
- *me = my_match;
+ return SC_FORMAT_SLOT_KEYID;
}
- if (other)
+ if (sscanf(smartcard, "%%smartcard:%127s", keyid) == 1)
{
- *other = other_match;
+ return SC_FORMAT_KEYID;
}
- return TRUE;
+ return SC_FORMAT_INVALID;
}
/**
- * Implements credential_set_t.create_shared_enumerator
+ * Load a credential from a smartcard
*/
-static enumerator_t* create_shared_enumerator(private_stroke_cred_t *this,
- shared_key_type_t type, identification_t *me,
- identification_t *other)
+static certificate_t *load_from_smartcard(smartcard_format_t format,
+ u_int slot, char *module, char *keyid,
+ credential_type_t type, int subtype)
{
- shared_data_t *data = malloc_thing(shared_data_t);
-
- data->this = this;
- data->me = me;
- data->other = other;
- data->type = type;
- this->lock->read_lock(this->lock);
- return enumerator_create_filter(this->shared->create_enumerator(this->shared),
- (void*)shared_filter, data,
- (void*)shared_data_destroy);
-}
-
-/**
- * Add a certificate to chain
- */
-static certificate_t* add_cert(private_stroke_cred_t *this, certificate_t *cert)
-{
- certificate_t *current;
- enumerator_t *enumerator;
- bool new = TRUE;
+ chunk_t chunk;
+ void *cred;
- this->lock->read_lock(this->lock);
- enumerator = this->certs->create_enumerator(this->certs);
- while (enumerator->enumerate(enumerator, (void**)¤t))
+ chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
+ switch (format)
{
- if (current->equals(current, cert))
- {
- /* cert already in queue */
- cert->destroy(cert);
- cert = current;
- new = FALSE;
+ case SC_FORMAT_SLOT_MODULE_KEYID:
+ cred = lib->creds->create(lib->creds, type, subtype,
+ BUILD_PKCS11_SLOT, slot,
+ BUILD_PKCS11_MODULE, module,
+ BUILD_PKCS11_KEYID, chunk, BUILD_END);
+ break;
+ case SC_FORMAT_SLOT_KEYID:
+ cred = lib->creds->create(lib->creds, type, subtype,
+ BUILD_PKCS11_SLOT, slot,
+ BUILD_PKCS11_KEYID, chunk, BUILD_END);
+ break;
+ case SC_FORMAT_KEYID:
+ cred = lib->creds->create(lib->creds, type, subtype,
+ BUILD_PKCS11_KEYID, chunk, BUILD_END);
+ break;
+ default:
+ cred = NULL;
break;
- }
}
- enumerator->destroy(enumerator);
+ free(chunk.ptr);
- if (new)
- {
- this->certs->insert_last(this->certs, cert);
- }
- this->lock->unlock(this->lock);
- return cert;
+ return cred;
}
-/**
- * Implementation of stroke_cred_t.load_ca.
- */
-static certificate_t* load_ca(private_stroke_cred_t *this, char *filename)
+METHOD(stroke_cred_t, load_ca, certificate_t*,
+ private_stroke_cred_t *this, char *filename)
{
- certificate_t *cert;
+ certificate_t *cert = NULL;
char path[PATH_MAX];
- if (*filename == '/')
+ if (strpfx(filename, "%smartcard"))
{
- snprintf(path, sizeof(path), "%s", filename);
+ smartcard_format_t format;
+ char module[SC_PART_LEN], keyid[SC_PART_LEN];
+ u_int slot;
+
+ format = parse_smartcard(filename, &slot, module, keyid);
+ if (format != SC_FORMAT_INVALID)
+ {
+ cert = (certificate_t*)load_from_smartcard(format,
+ slot, module, keyid, CRED_CERTIFICATE, CERT_X509);
+ }
}
else
{
- snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename);
- }
+ if (*filename == '/')
+ {
+ snprintf(path, sizeof(path), "%s", filename);
+ }
+ else
+ {
+ snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename);
+ }
- cert = lib->creds->create(lib->creds,
- CRED_CERTIFICATE, CERT_X509,
- BUILD_FROM_FILE, path,
- BUILD_END);
+ if (this->force_ca_cert)
+ { /* we treat this certificate as a CA certificate even if it has no
+ * CA basic constraint */
+ cert = lib->creds->create(lib->creds,
+ CRED_CERTIFICATE, CERT_X509,
+ BUILD_FROM_FILE, path, BUILD_X509_FLAG, X509_CA,
+ BUILD_END);
+ }
+ else
+ {
+ cert = lib->creds->create(lib->creds,
+ CRED_CERTIFICATE, CERT_X509,
+ BUILD_FROM_FILE, path,
+ BUILD_END);
+ }
+ }
if (cert)
{
x509_t *x509 = (x509_t*)cert;
cert->destroy(cert);
return NULL;
}
- return (certificate_t*)add_cert(this, cert);
+ DBG1(DBG_CFG, " loaded ca certificate \"%Y\" from '%s'",
+ cert->get_subject(cert), filename);
+ return this->creds->add_cert_ref(this->creds, TRUE, cert);
}
return NULL;
}
-/**
- * Add X.509 CRL to chain
- */
-static bool add_crl(private_stroke_cred_t *this, crl_t* crl)
+METHOD(stroke_cred_t, load_peer, certificate_t*,
+ private_stroke_cred_t *this, char *filename)
{
- certificate_t *current, *cert = &crl->certificate;
- enumerator_t *enumerator;
- bool new = TRUE, found = FALSE;
+ certificate_t *cert = NULL;
+ char path[PATH_MAX];
- this->lock->write_lock(this->lock);
- enumerator = this->certs->create_enumerator(this->certs);
- while (enumerator->enumerate(enumerator, (void**)¤t))
+ if (strpfx(filename, "%smartcard"))
{
- if (current->get_type(current) == CERT_X509_CRL)
- {
- crl_t *crl_c = (crl_t*)current;
- chunk_t authkey = crl->get_authKeyIdentifier(crl);
- chunk_t authkey_c = crl_c->get_authKeyIdentifier(crl_c);
-
- /* if compare authorityKeyIdentifiers if available */
- if (authkey.ptr && authkey_c.ptr && chunk_equals(authkey, authkey_c))
- {
- found = TRUE;
- }
- else
- {
- identification_t *issuer = cert->get_issuer(cert);
- identification_t *issuer_c = current->get_issuer(current);
+ smartcard_format_t format;
+ char module[SC_PART_LEN], keyid[SC_PART_LEN];
+ u_int slot;
- /* otherwise compare issuer distinguished names */
- if (issuer->equals(issuer, issuer_c))
- {
- found = TRUE;
- }
- }
- if (found)
- {
- new = crl_is_newer(crl, crl_c);
- if (new)
- {
- this->certs->remove_at(this->certs, enumerator);
- }
- else
- {
- cert->destroy(cert);
- }
- break;
- }
+ format = parse_smartcard(filename, &slot, module, keyid);
+ if (format != SC_FORMAT_INVALID)
+ {
+ cert = (certificate_t*)load_from_smartcard(format,
+ slot, module, keyid, CRED_CERTIFICATE, CERT_X509);
}
}
- enumerator->destroy(enumerator);
+ else
+ {
+ if (*filename == '/')
+ {
+ snprintf(path, sizeof(path), "%s", filename);
+ }
+ else
+ {
+ snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
+ }
- if (new)
+ cert = lib->creds->create(lib->creds,
+ CRED_CERTIFICATE, CERT_ANY,
+ BUILD_FROM_FILE, path,
+ BUILD_END);
+ }
+ if (cert)
{
- this->certs->insert_last(this->certs, cert);
+ cert = this->creds->add_cert_ref(this->creds, TRUE, cert);
+ DBG1(DBG_CFG, " loaded certificate \"%Y\" from '%s'",
+ cert->get_subject(cert), filename);
+ return cert;
}
- this->lock->unlock(this->lock);
- return new;
-}
-
-/**
- * Add X.509 attribute certificate to chain
- */
-static bool add_ac(private_stroke_cred_t *this, ac_t* ac)
-{
- certificate_t *cert = &ac->certificate;
-
- this->lock->write_lock(this->lock);
- this->certs->insert_last(this->certs, cert);
- this->lock->unlock(this->lock);
- return TRUE;
+ DBG1(DBG_CFG, " loading certificate from '%s' failed", filename);
+ return NULL;
}
-/**
- * Implementation of stroke_cred_t.load_peer.
- */
-static certificate_t* load_peer(private_stroke_cred_t *this, char *filename)
+METHOD(stroke_cred_t, load_pubkey, certificate_t*,
+ private_stroke_cred_t *this, char *filename, identification_t *identity)
{
certificate_t *cert;
+ public_key_t *key;
char path[PATH_MAX];
+ builder_part_t build_part;
+ key_type_t type = KEY_ANY;
- if (*filename == '/')
+ if (streq(filename, "%dns"))
{
- snprintf(path, sizeof(path), "%s", filename);
+ return NULL;
+ }
+ if (strncaseeq(filename, "dns:", 4))
+ { /* RFC 3110 format */
+ build_part = BUILD_BLOB_DNSKEY;
+ /* not a complete RR, only RSA supported */
+ type = KEY_RSA;
+ filename += 4;
+ }
+ else if (strncaseeq(filename, "ssh:", 4))
+ { /* SSH key */
+ build_part = BUILD_BLOB_SSHKEY;
+ filename += 4;
}
else
- {
- snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
+ { /* try PKCS#1 by default */
+ build_part = BUILD_BLOB_ASN1_DER;
}
+ if (strncaseeq(filename, "0x", 2) || strncaseeq(filename, "0s", 2))
+ {
+ chunk_t printable_key, raw_key;
- cert = lib->creds->create(lib->creds,
- CRED_CERTIFICATE, CERT_ANY,
- BUILD_FROM_FILE, path,
- BUILD_END);
- if (cert)
+ printable_key = chunk_create(filename + 2, strlen(filename) - 2);
+ raw_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, type,
+ build_part, raw_key, BUILD_END);
+ chunk_free(&raw_key);
+ if (key)
+ {
+ cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
+ CERT_TRUSTED_PUBKEY,
+ BUILD_PUBLIC_KEY, key,
+ BUILD_SUBJECT, identity,
+ BUILD_END);
+ type = key->get_type(key);
+ 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 public key for \"%Y\" failed", identity);
+ }
+ else
{
- cert = add_cert(this, cert);
- DBG1(DBG_CFG, " loaded certificate \"%Y\" from '%s'",
- cert->get_subject(cert), filename);
- return cert->get_ref(cert);
+ 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);
+ key = cert->get_public_key(cert);
+ type = key->get_type(key);
+ key->destroy(key);
+ DBG1(DBG_CFG, " loaded %N public key for \"%Y\" from '%s'",
+ key_type_names, type, identity, filename);
+ return cert;
+ }
+ DBG1(DBG_CFG, " loading public key for \"%Y\" from '%s' failed",
+ identity, filename);
}
- DBG1(DBG_CFG, " loading certificate from '%s' failed", filename);
return NULL;
}
{
case CERT_X509:
if (flag & X509_CA)
- { /* for CA certificates, we strictly require
- * the CA basic constraint to be set */
- cert = lib->creds->create(lib->creds,
+ {
+ if (this->force_ca_cert)
+ { /* treat this certificate as CA cert even it has no
+ * CA basic constraint */
+ cert = lib->creds->create(lib->creds,
+ CRED_CERTIFICATE, CERT_X509,
+ BUILD_FROM_FILE, file, BUILD_X509_FLAG,
+ X509_CA, BUILD_END);
+ }
+ else
+ {
+ cert = lib->creds->create(lib->creds,
CRED_CERTIFICATE, CERT_X509,
BUILD_FROM_FILE, file, BUILD_END);
+ }
if (cert)
{
x509_t *x509 = (x509_t*)cert;
}
else
{
- DBG1(DBG_CFG, " loaded ca certificate \"%Y\" from '%s'",
- cert->get_subject(cert), file);
+ DBG1(DBG_CFG, " loaded ca certificate \"%Y\" "
+ "from '%s'", cert->get_subject(cert), file);
}
}
else
}
if (cert)
{
- add_cert(this, cert);
+ this->creds->add_cert(this->creds, TRUE, cert);
}
break;
case CERT_X509_CRL:
BUILD_END);
if (cert)
{
- add_crl(this, (crl_t*)cert);
+ this->creds->add_crl(this->creds, (crl_t*)cert);
DBG1(DBG_CFG, " loaded crl from '%s'", file);
}
else
BUILD_END);
if (cert)
{
- add_ac(this, (ac_t*)cert);
+ this->creds->add_cert(this->creds, FALSE, cert);
DBG1(DBG_CFG, " loaded attribute certificate from '%s'",
file);
}
enumerator->destroy(enumerator);
}
-/**
- * Implementation of credential_set_t.cache_cert.
- */
-static void cache_cert(private_stroke_cred_t *this, certificate_t *cert)
+METHOD(stroke_cred_t, cache_cert, void,
+ private_stroke_cred_t *this, certificate_t *cert)
{
if (cert->get_type(cert) == CERT_X509_CRL && this->cachecrl)
{
crl_t *crl = (crl_t*)cert;
cert->get_ref(cert);
- if (add_crl(this, crl))
+ if (this->creds->add_crl(this->creds, crl))
{
char buf[BUF_LEN];
chunk_t chunk, hex;
chunk = crl->get_authKeyIdentifier(crl);
hex = chunk_to_hex(chunk, NULL, FALSE);
- snprintf(buf, sizeof(buf), "%s/%s.crl", CRL_DIR, hex);
+ snprintf(buf, sizeof(buf), "%s/%s.crl", CRL_DIR, hex.ptr);
free(hex.ptr);
if (cert->get_encoding(cert, CERT_ASN1_DER, &chunk))
{
- chunk_write(chunk, buf, "crl", 022, TRUE);
+ if (chunk_write(chunk, buf, 022, TRUE))
+ {
+ DBG1(DBG_CFG, " written crl file '%s' (%d bytes)",
+ buf, chunk.len);
+ }
+ else
+ {
+ DBG1(DBG_CFG, " writing crl file '%s' failed: %s",
+ buf, strerror(errno));
+ }
free(chunk.ptr);
}
}
}
}
-/**
- * Implementation of stroke_cred_t.cachecrl.
- */
-static void cachecrl(private_stroke_cred_t *this, bool enabled)
+METHOD(stroke_cred_t, cachecrl, void,
+ private_stroke_cred_t *this, bool enabled)
{
DBG1(DBG_CFG, "crl caching to %s %s",
CRL_DIR, enabled ? "enabled" : "disabled");
}
/**
- * Data to pass to passphrase_cb
+ * Data for passphrase callback
*/
typedef struct {
+ /** cached passphrases */
+ mem_cred_t *cache;
/** socket we use for prompting */
FILE *prompt;
+ /** type of secret to unlock */
+ int type;
/** 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,
+ shared_key_type_t type, identification_t *me,
+ identification_t *other, id_match_t *match_me,
+ id_match_t *match_other)
{
- chunk_t secret = chunk_empty;;
+ static const int max_tries = 3;
+ shared_key_t *shared;
+ chunk_t secret;
+ char buf[256];
- if (try > 5)
+ if (type != SHARED_ANY && type != SHARED_PRIVATE_KEY_PASS)
{
- fprintf(data->prompt, "invalid passphrase, too many trials\n");
- return chunk_empty;
+ return NULL;
+ }
+
+ data->try++;
+ if (data->try > max_tries + 1)
+ { /* another builder might call this after we gave up, fail silently */
+ return NULL;
}
- if (try == 1)
+ if (data->try > max_tries)
{
- fprintf(data->prompt, "Private key '%s' is encrypted\n", data->file);
+ fprintf(data->prompt, "Passphrase invalid, giving up.\n");
+ return NULL;
}
- else
+ if (data->try > 1)
{
- fprintf(data->prompt, "invalid passphrase\n");
+ fprintf(data->prompt, "Passphrase invalid!\n");
}
+ fprintf(data->prompt, "%s '%s' is encrypted.\n",
+ data->type == CRED_PRIVATE_KEY ? "Private key" : "PKCS#12 file",
+ 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;
+ }
+ shared = shared_key_create(SHARED_PRIVATE_KEY_PASS,
+ chunk_clone(secret));
+ data->cache->add_shared(data->cache, shared->get_ref(shared), NULL);
+ return shared;
}
}
- return secret;
+ return NULL;
}
/**
- * Smartcard PIN callback to read from stroke fd
+ * Data for PIN callback
*/
-chunk_t smartcard_cb(passphrase_cb_data_t *data, int try)
+typedef struct {
+ /** socket we use for prompting */
+ FILE *prompt;
+ /** card label */
+ char *card;
+ /** card keyid */
+ chunk_t keyid;
+ /** number of tries */
+ int try;
+} pin_cb_data_t;
+
+/**
+ * Callback function to receive PINs
+ */
+static shared_key_t* pin_cb(pin_cb_data_t *data, shared_key_type_t type,
+ 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 != 1)
+ if (type != SHARED_ANY && type != SHARED_PIN)
{
- fprintf(data->prompt, "invalid passphrase, aborting\n");
- return chunk_empty;
+ return NULL;
}
- fprintf(data->prompt, "Login to '%s' required\n", data->file);
- fprintf(data->prompt, "Passphrase:\n");
- if (fgets(data->buf, sizeof(data->buf), data->prompt))
+
+ if (!me || !chunk_equals(me->get_encoding(me), data->keyid))
+ {
+ return NULL;
+ }
+
+ data->try++;
+ if (data->try > 1)
+ {
+ fprintf(data->prompt, "PIN invalid, aborting.\n");
+ return NULL;
+ }
+ fprintf(data->prompt, "Login to '%s' required\n", data->card);
+ fprintf(data->prompt, "PIN:\n");
+ 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_PIN, chunk_clone(secret));
}
}
- return secret;
+ return NULL;
}
/**
* Load a smartcard with a PIN
*/
-static bool load_pin(private_stroke_cred_t *this, chunk_t line, int line_nr,
+static bool load_pin(mem_cred_t *secrets, chunk_t line, int line_nr,
FILE *prompt)
{
chunk_t sc = chunk_empty, secret = chunk_empty;
- char smartcard[64], keyid[64], module[64], *pos;
+ char smartcard[BUF_LEN], keyid[SC_PART_LEN], module[SC_PART_LEN];
private_key_t *key = NULL;
u_int slot;
chunk_t chunk;
- enum {
- SC_FORMAT_SLOT_MODULE_KEYID,
- SC_FORMAT_SLOT_KEYID,
- SC_FORMAT_KEYID,
- } format;
+ shared_key_t *shared;
+ identification_t *id;
+ mem_cred_t *mem = NULL;
+ callback_cred_t *cb = NULL;
+ pin_cb_data_t pin_data;
+ smartcard_format_t format;
err_t ugh = extract_value(&sc, &line);
DBG1(DBG_CFG, "line %d: expected %%smartcard specifier", line_nr);
return FALSE;
}
- snprintf(smartcard, sizeof(smartcard), "%.*s", sc.len, sc.ptr);
+ snprintf(smartcard, sizeof(smartcard), "%.*s", (int)sc.len, sc.ptr);
smartcard[sizeof(smartcard) - 1] = '\0';
- /* parse slot and key id. Three formats are supported:
- * - %smartcard<slot>@<module>:<keyid>
- * - %smartcard<slot>:<keyid>
- * - %smartcard:<keyid>
- */
- if (sscanf(smartcard, "%%smartcard%u@%s", &slot, module) == 2)
- {
- pos = strchr(module, ':');
- if (!pos)
- {
- DBG1(DBG_CFG, "line %d: the given %%smartcard specifier is "
- "invalid", line_nr);
- return FALSE;
- }
- *pos = '\0';
- strcpy(keyid, pos + 1);
- format = SC_FORMAT_SLOT_MODULE_KEYID;
- }
- else if (sscanf(smartcard, "%%smartcard%u:%s", &slot, keyid) == 2)
- {
- format = SC_FORMAT_SLOT_KEYID;
- }
- else if (sscanf(smartcard, "%%smartcard:%s", keyid) == 1)
- {
- format = SC_FORMAT_KEYID;
- }
- else
+ format = parse_smartcard(smartcard, &slot, module, keyid);
+ if (format == SC_FORMAT_INVALID)
{
DBG1(DBG_CFG, "line %d: the given %%smartcard specifier is not"
" supported or invalid", line_nr);
}
chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
-
- if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7))
+ if (secret.len == 7 && strpfx(secret.ptr, "%prompt"))
{
- if (prompt)
- {
- passphrase_cb_data_t data = {
- .prompt = prompt,
- .file = smartcard,
- };
-
- switch (format)
- {
- case SC_FORMAT_SLOT_MODULE_KEYID:
- key = lib->creds->create(lib->creds,
- CRED_PRIVATE_KEY, KEY_ANY,
- BUILD_PKCS11_SLOT, slot,
- BUILD_PKCS11_MODULE, module,
- BUILD_PKCS11_KEYID, chunk,
- BUILD_PASSPHRASE_CALLBACK,
- smartcard_cb, &data, BUILD_END);
- break;
- case SC_FORMAT_SLOT_KEYID:
- key = lib->creds->create(lib->creds,
- CRED_PRIVATE_KEY, KEY_ANY,
- BUILD_PKCS11_SLOT, slot,
- BUILD_PKCS11_KEYID, chunk,
- BUILD_PASSPHRASE_CALLBACK,
- smartcard_cb, &data, BUILD_END);
- break;
- case SC_FORMAT_KEYID:
- key = lib->creds->create(lib->creds,
- CRED_PRIVATE_KEY, KEY_ANY,
- BUILD_PKCS11_KEYID, chunk,
- BUILD_PASSPHRASE_CALLBACK,
- smartcard_cb, &data, BUILD_END);
- break;
- }
+ free(secret.ptr);
+ if (!prompt)
+ { /* no IO channel to prompt, skip */
+ chunk_clear(&chunk);
+ return TRUE;
}
+ /* use callback credential set to prompt for the pin */
+ pin_data.prompt = prompt;
+ pin_data.card = smartcard;
+ pin_data.keyid = chunk;
+ pin_data.try = 0;
+ cb = callback_cred_create_shared((void*)pin_cb, &pin_data);
+ lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE);
}
else
{
- switch (format)
- {
- case SC_FORMAT_SLOT_MODULE_KEYID:
- key = lib->creds->create(lib->creds,
- CRED_PRIVATE_KEY, KEY_ANY,
- BUILD_PKCS11_SLOT, slot,
- BUILD_PKCS11_MODULE, module,
- BUILD_PKCS11_KEYID, chunk,
- BUILD_PASSPHRASE, secret, BUILD_END);
- break;
- case SC_FORMAT_SLOT_KEYID:
- key = lib->creds->create(lib->creds,
- CRED_PRIVATE_KEY, KEY_ANY,
- BUILD_PKCS11_SLOT, slot,
- BUILD_PKCS11_KEYID, chunk,
- BUILD_PASSPHRASE, secret, BUILD_END);
- break;
- case SC_FORMAT_KEYID:
- key = lib->creds->create(lib->creds,
- CRED_PRIVATE_KEY, KEY_ANY,
- BUILD_PKCS11_KEYID, chunk,
- BUILD_PASSPHRASE, secret, BUILD_END);
- break;
- }
+ /* provide our pin in a temporary credential set */
+ shared = shared_key_create(SHARED_PIN, secret);
+ id = identification_create_from_encoding(ID_KEY_ID, chunk);
+ mem = mem_cred_create();
+ mem->add_shared(mem, shared, id, NULL);
+ lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
}
- free(chunk.ptr);
+
+ /* unlock: smartcard needs the pin and potentially calls public set */
+ key = (private_key_t*)load_from_smartcard(format, slot, module, keyid,
+ CRED_PRIVATE_KEY, KEY_ANY);
+ if (mem)
+ {
+ lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
+ mem->destroy(mem);
+ }
+ if (cb)
+ {
+ lib->credmgr->remove_local_set(lib->credmgr, &cb->set);
+ cb->destroy(cb);
+ }
+ chunk_clear(&chunk);
+
if (key)
{
- DBG1(DBG_CFG, " loaded private key from %.*s", sc.len, sc.ptr);
- this->private->insert_last(this->private, key);
+ DBG1(DBG_CFG, " loaded private key from %.*s", (int)sc.len, sc.ptr);
+ secrets->add_key(secrets, key);
}
- chunk_clear(&secret);
return TRUE;
}
/**
- * Load a private key
+ * Load a private key or PKCS#12 container from a file
*/
-static bool load_private(private_stroke_cred_t *this, chunk_t line, int line_nr,
- FILE *prompt, key_type_t key_type)
+static bool load_from_file(chunk_t line, int line_nr, FILE *prompt,
+ char *path, int type, int subtype,
+ void **result)
{
- char path[PATH_MAX];
chunk_t filename;
chunk_t secret = chunk_empty;
- private_key_t *key = NULL;
err_t ugh = extract_value(&filename, &line);
if (*filename.ptr == '/')
{
/* absolute path name */
- snprintf(path, sizeof(path), "%.*s", filename.len, filename.ptr);
+ snprintf(path, PATH_MAX, "%.*s", (int)filename.len, filename.ptr);
}
else
{
/* relative path name */
- snprintf(path, sizeof(path), "%s/%.*s", PRIVATE_KEY_DIR,
- filename.len, filename.ptr);
+ snprintf(path, PATH_MAX, "%s/%.*s", PRIVATE_KEY_DIR,
+ (int)filename.len, filename.ptr);
}
/* check for optional passphrase */
return FALSE;
}
}
- if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7))
+ if (secret.len == 7 && strpfx(secret.ptr, "%prompt"))
{
- if (prompt)
+ callback_cred_t *cb;
+ passphrase_cb_data_t pp_data = {
+ .prompt = prompt,
+ .type = type,
+ .path = path,
+ .try = 0,
+ };
+
+ 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);
+ *result = NULL;
+ return TRUE;
}
+ /* add cache first so if valid passphrases are needed multiple times
+ * the callback is not called anymore */
+ pp_data.cache = mem_cred_create();
+ lib->credmgr->add_local_set(lib->credmgr, &pp_data.cache->set, FALSE);
+ /* use callback credential set to prompt for the passphrase */
+ cb = callback_cred_create_shared((void*)passphrase_cb, &pp_data);
+ lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE);
+
+ *result = lib->creds->create(lib->creds, type, subtype,
+ BUILD_FROM_FILE, path, BUILD_END);
+
+ lib->credmgr->remove_local_set(lib->credmgr, &cb->set);
+ cb->destroy(cb);
+ lib->credmgr->remove_local_set(lib->credmgr, &pp_data.cache->set);
+ pp_data.cache->destroy(pp_data.cache);
}
else
{
- key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type,
- BUILD_FROM_FILE, path,
- BUILD_PASSPHRASE, secret, BUILD_END);
+ 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);
+ if (eat_whitespace(&line))
+ { /* if there is a second passphrase add that too, could be needed for
+ * PKCS#12 files using different passwords for MAC and encryption */
+ ugh = extract_secret(&secret, &line);
+ if (ugh != NULL)
+ {
+ DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh);
+ mem->destroy(mem);
+ return FALSE;
+ }
+ shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, secret);
+ mem->add_shared(mem, shared, NULL);
+ }
+ lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
+
+ *result = lib->creds->create(lib->creds, type, subtype,
+ BUILD_FROM_FILE, path, BUILD_END);
+
+ lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
+ mem->destroy(mem);
+ }
+ return TRUE;
+}
+
+/**
+ * Load a private key
+ */
+static bool load_private(mem_cred_t *secrets, chunk_t line, int line_nr,
+ FILE *prompt, key_type_t key_type)
+{
+ char path[PATH_MAX];
+ private_key_t *key;
+
+ if (!load_from_file(line, line_nr, prompt, path, CRED_PRIVATE_KEY,
+ key_type, (void**)&key))
+ {
+ return FALSE;
}
if (key)
{
DBG1(DBG_CFG, " loaded %N private key from '%s'",
key_type_names, key->get_type(key), path);
- this->private->insert_last(this->private, key);
+ secrets->add_key(secrets, key);
}
else
{
DBG1(DBG_CFG, " loading private key from '%s' failed", path);
}
- chunk_clear(&secret);
+ return TRUE;
+}
+
+/**
+ * Load a PKCS#12 container
+ */
+static bool load_pkcs12(private_stroke_cred_t *this, mem_cred_t *secrets,
+ chunk_t line, int line_nr, FILE *prompt)
+{
+ enumerator_t *enumerator;
+ char path[PATH_MAX];
+ certificate_t *cert;
+ private_key_t *key;
+ pkcs12_t *pkcs12;
+
+ if (!load_from_file(line, line_nr, prompt, path, CRED_CONTAINER,
+ CONTAINER_PKCS12, (void**)&pkcs12))
+ {
+ return FALSE;
+ }
+ if (!pkcs12)
+ {
+ DBG1(DBG_CFG, " loading credentials from '%s' failed", path);
+ return TRUE;
+ }
+ enumerator = pkcs12->create_cert_enumerator(pkcs12);
+ while (enumerator->enumerate(enumerator, &cert))
+ {
+ x509_t *x509 = (x509_t*)cert;
+
+ if (x509->get_flags(x509) & X509_CA)
+ {
+ DBG1(DBG_CFG, " loaded ca certificate \"%Y\" from '%s'",
+ cert->get_subject(cert), path);
+ }
+ else
+ {
+ DBG1(DBG_CFG, " loaded certificate \"%Y\" from '%s'",
+ cert->get_subject(cert), path);
+ }
+ this->creds->add_cert(this->creds, TRUE, cert->get_ref(cert));
+ }
+ enumerator->destroy(enumerator);
+ enumerator = pkcs12->create_key_enumerator(pkcs12);
+ while (enumerator->enumerate(enumerator, &key))
+ {
+ DBG1(DBG_CFG, " loaded %N private key from '%s'",
+ key_type_names, key->get_type(key), path);
+ secrets->add_key(secrets, key->get_ref(key));
+ }
+ enumerator->destroy(enumerator);
+ pkcs12->container.destroy(&pkcs12->container);
return TRUE;
}
/**
* Load a shared key
*/
-static bool load_shared(private_stroke_cred_t *this, chunk_t line, int line_nr,
+static bool load_shared(mem_cred_t *secrets, chunk_t line, int line_nr,
shared_key_type_t type, chunk_t ids)
{
- stroke_shared_key_t *shared_key;
+ shared_key_t *shared_key;
+ linked_list_t *owners;
chunk_t secret = chunk_empty;
bool any = TRUE;
DBG1(DBG_CFG, "line %d: malformed secret: %s", line_nr, ugh);
return FALSE;
}
- shared_key = stroke_shared_key_create(type, secret);
+ shared_key = shared_key_create(type, secret);
DBG1(DBG_CFG, " loaded %N secret for %s", shared_key_type_names, type,
ids.len > 0 ? (char*)ids.ptr : "%any");
DBG4(DBG_CFG, " secret: %#B", &secret);
- this->shared->insert_last(this->shared, shared_key);
+ owners = linked_list_create();
while (ids.len > 0)
{
chunk_t id;
if (ugh != NULL)
{
DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
+ shared_key->destroy(shared_key);
+ owners->destroy_offset(owners, offsetof(identification_t, destroy));
return FALSE;
}
if (id.len == 0)
continue;
}
- shared_key->add_owner(shared_key, peer_id);
+ owners->insert_last(owners, peer_id);
any = FALSE;
}
if (any)
{
- shared_key->add_owner(shared_key,
+ owners->insert_last(owners,
identification_create_from_encoding(ID_ANY, chunk_empty));
}
+ secrets->add_shared_list(secrets, shared_key, owners);
return TRUE;
}
/**
* reload ipsec.secrets
*/
-static void load_secrets(private_stroke_cred_t *this, char *file, int level,
- FILE *prompt)
+static void load_secrets(private_stroke_cred_t *this, mem_cred_t *secrets,
+ char *file, int level, FILE *prompt)
{
- size_t bytes;
int line_nr = 0;
- chunk_t chunk, src, line;
- FILE *fd;
- private_key_t *private;
- shared_key_t *shared;
+ chunk_t *src, line;
DBG1(DBG_CFG, "loading secrets from '%s'", file);
-
- fd = fopen(file, "r");
- if (fd == NULL)
+ src = chunk_map(file, FALSE);
+ if (!src)
{
- DBG1(DBG_CFG, "opening secrets file '%s' failed", file);
+ DBG1(DBG_CFG, "opening secrets file '%s' failed: %s", file,
+ strerror(errno));
return;
}
- /* TODO: do error checks */
- fseek(fd, 0, SEEK_END);
- chunk.len = ftell(fd);
- rewind(fd);
- chunk.ptr = malloc(chunk.len);
- bytes = fread(chunk.ptr, 1, chunk.len, fd);
- fclose(fd);
- src = chunk;
-
- if (level == 0)
+ if (!secrets)
{
- this->lock->write_lock(this->lock);
-
- /* flush secrets on non-recursive invocation */
- while (this->shared->remove_last(this->shared,
- (void**)&shared) == SUCCESS)
- {
- shared->destroy(shared);
- }
- while (this->private->remove_last(this->private,
- (void**)&private) == SUCCESS)
- {
- private->destroy(private);
- }
+ secrets = mem_cred_create();
}
- while (fetchline(&src, &line))
+ while (fetchline(src, &line))
{
chunk_t ids, token;
shared_key_type_t type;
{
continue;
}
- if (line.len > strlen("include ") &&
- strneq(line.ptr, "include ", strlen("include ")))
+ if (line.len > strlen("include ") && strpfx(line.ptr, "include "))
{
- glob_t buf;
char **expanded, *dir, pattern[PATH_MAX];
u_char *pos;
DBG1(DBG_CFG, "include pattern too long, ignored");
continue;
}
- snprintf(pattern, sizeof(pattern), "%.*s", line.len, line.ptr);
+ snprintf(pattern, sizeof(pattern), "%.*s",
+ (int)line.len, line.ptr);
}
else
{ /* use directory of current file if relative */
- dir = strdup(file);
- dir = dirname(dir);
+ dir = path_dirname(file);
if (line.len + 1 + strlen(dir) + 1 > sizeof(pattern))
{
continue;
}
snprintf(pattern, sizeof(pattern), "%s/%.*s",
- dir, line.len, line.ptr);
+ dir, (int)line.len, line.ptr);
free(dir);
}
- if (glob(pattern, GLOB_ERR, NULL, &buf) != 0)
+#ifdef HAVE_GLOB_H
{
- DBG1(DBG_CFG, "expanding file expression '%s' failed", pattern);
- globfree(&buf);
- }
- else
- {
- for (expanded = buf.gl_pathv; *expanded != NULL; expanded++)
+ glob_t buf;
+ if (glob(pattern, GLOB_ERR, NULL, &buf) != 0)
{
- load_secrets(this, *expanded, level + 1, prompt);
+ DBG1(DBG_CFG, "expanding file expression '%s' failed",
+ pattern);
}
+ else
+ {
+ for (expanded = buf.gl_pathv; *expanded != NULL; expanded++)
+ {
+ load_secrets(this, secrets, *expanded, level + 1,
+ prompt);
+ }
+ }
+ globfree(&buf);
}
- globfree(&buf);
+#else /* HAVE_GLOB_H */
+ /* if glob(3) is not available, try to load pattern directly */
+ load_secrets(this, secrets, pattern, level + 1, prompt);
+#endif /* HAVE_GLOB_H */
continue;
}
- if (line.len > 2 && strneq(": ", line.ptr, 2))
+ if (line.len > 2 && strpfx(line.ptr, ": "))
{
/* no ids, skip the ':' */
ids = chunk_empty;
}
if (match("RSA", &token) || match("ECDSA", &token))
{
- if (!load_private(this, line, line_nr, prompt,
+ if (!load_private(secrets, line, line_nr, prompt,
match("RSA", &token) ? KEY_RSA : KEY_ECDSA))
{
break;
}
}
+ else if (match("P12", &token))
+ {
+ if (!load_pkcs12(this, secrets, line, line_nr, prompt))
+ {
+ break;
+ }
+ }
else if (match("PIN", &token))
{
- if (!load_pin(this, line, line_nr, prompt))
+ if (!load_pin(secrets, line, line_nr, prompt))
{
break;
}
(match("NTLM", &token) && (type = SHARED_NT_HASH)) ||
(match("XAUTH", &token) && (type = SHARED_EAP)))
{
- if (!load_shared(this, line, line_nr, type, ids))
+ if (!load_shared(secrets, line, line_nr, type, ids))
{
break;
}
else
{
DBG1(DBG_CFG, "line %d: token must be either "
- "RSA, ECDSA, PSK, EAP, XAUTH or PIN", line_nr);
+ "RSA, ECDSA, P12, PIN, PSK, EAP, XAUTH or NTLM", line_nr);
break;
}
}
+ chunk_unmap(src);
+
if (level == 0)
- {
- this->lock->unlock(this->lock);
+ { /* replace secrets in active credential set */
+ this->creds->replace_secrets(this->creds, secrets, FALSE);
+ secrets->destroy(secrets);
}
- chunk_clear(&chunk);
}
/**
load_certdir(this, CRL_DIR, CERT_X509_CRL, 0);
}
-/**
- * Implementation of stroke_cred_t.reread.
- */
-static void reread(private_stroke_cred_t *this, stroke_msg_t *msg, FILE *prompt)
+METHOD(stroke_cred_t, reread, void,
+ private_stroke_cred_t *this, stroke_msg_t *msg, FILE *prompt)
{
if (msg->reread.flags & REREAD_SECRETS)
{
DBG1(DBG_CFG, "rereading secrets");
- load_secrets(this, SECRETS_FILE, 0, prompt);
+ load_secrets(this, NULL, this->secrets_file, 0, prompt);
}
if (msg->reread.flags & REREAD_CACERTS)
{
}
}
-/**
- * Implementation of stroke_cred_t.destroy
- */
-static void destroy(private_stroke_cred_t *this)
+METHOD(stroke_cred_t, add_shared, void,
+ private_stroke_cred_t *this, shared_key_t *shared, linked_list_t *owners)
{
- this->certs->destroy_offset(this->certs, offsetof(certificate_t, destroy));
- this->shared->destroy_offset(this->shared, offsetof(shared_key_t, destroy));
- this->private->destroy_offset(this->private, offsetof(private_key_t, destroy));
- this->lock->destroy(this->lock);
+ this->creds->add_shared_list(this->creds, shared, owners);
+}
+
+METHOD(stroke_cred_t, destroy, void,
+ private_stroke_cred_t *this)
+{
+ lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
+ this->creds->destroy(this->creds);
free(this);
}
*/
stroke_cred_t *stroke_cred_create()
{
- private_stroke_cred_t *this = malloc_thing(private_stroke_cred_t);
-
- this->public.set.create_private_enumerator = (void*)create_private_enumerator;
- this->public.set.create_cert_enumerator = (void*)create_cert_enumerator;
- this->public.set.create_shared_enumerator = (void*)create_shared_enumerator;
- this->public.set.create_cdp_enumerator = (void*)return_null;
- this->public.set.cache_cert = (void*)cache_cert;
- this->public.reread = (void(*)(stroke_cred_t*, stroke_msg_t *msg, FILE*))reread;
- this->public.load_ca = (certificate_t*(*)(stroke_cred_t*, char *filename))load_ca;
- this->public.load_peer = (certificate_t*(*)(stroke_cred_t*, char *filename))load_peer;
- this->public.cachecrl = (void(*)(stroke_cred_t*, bool enabled))cachecrl;
- this->public.destroy = (void(*)(stroke_cred_t*))destroy;
-
- this->certs = linked_list_create();
- this->shared = linked_list_create();
- this->private = linked_list_create();
- this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
+ private_stroke_cred_t *this;
- load_certs(this);
- load_secrets(this, SECRETS_FILE, 0, NULL);
+ INIT(this,
+ .public = {
+ .set = {
+ .create_private_enumerator = (void*)return_null,
+ .create_cert_enumerator = (void*)return_null,
+ .create_shared_enumerator = (void*)return_null,
+ .create_cdp_enumerator = (void*)return_null,
+ .cache_cert = (void*)_cache_cert,
+ },
+ .reread = _reread,
+ .load_ca = _load_ca,
+ .load_peer = _load_peer,
+ .load_pubkey = _load_pubkey,
+ .add_shared = _add_shared,
+ .cachecrl = _cachecrl,
+ .destroy = _destroy,
+ },
+ .secrets_file = lib->settings->get_str(lib->settings,
+ "%s.plugins.stroke.secrets_file", SECRETS_FILE,
+ lib->ns),
+ .creds = mem_cred_create(),
+ );
+
+ lib->credmgr->add_set(lib->credmgr, &this->creds->set);
+
+ this->force_ca_cert = lib->settings->get_bool(lib->settings,
+ "%s.plugins.stroke.ignore_missing_ca_basic_constraint",
+ FALSE, lib->ns);
- this->cachecrl = FALSE;
+ load_certs(this);
+ load_secrets(this, NULL, this->secrets_file, 0, NULL);
return &this->public;
}
-