stroke: Load credentials from PKCS#12 files (P12 token)

This commit is contained in:
Tobias Brunner 2013-04-17 13:49:13 +02:00
parent 904390e887
commit 7971278c92
2 changed files with 109 additions and 19 deletions

View File

@ -91,6 +91,9 @@ defines an RSA private key
.B ECDSA
defines an ECDSA private key
.TP
.B P12
defines a PKCS#12 container
.TP
.B EAP
defines EAP credentials
.TP
@ -133,16 +136,26 @@ Similarly, a character sequence beginning with
.B 0s
is interpreted as Base64 encoded binary data.
.TP
.B [ <selectors> ] : RSA <private key file> [ <passphrase> | %prompt ]
.B : RSA <private key file> [ <passphrase> | %prompt ]
.TQ
.B [ <selectors> ] : ECDSA <private key file> [ <passphrase> | %prompt ]
.B : ECDSA <private key file> [ <passphrase> | %prompt ]
For the private key file both absolute paths or paths relative to
\fI/etc/ipsec.d/private\fP are accepted. If the private key file is
encrypted, the \fIpassphrase\fP must be defined. Instead of a passphrase
.B %prompt
can be used which then causes the daemons to ask the user for the password
can be used which then causes the daemon to ask the user for the password
whenever it is required to decrypt the key.
.TP
.B : P12 <PKCS#12 file> [ <passphrase> | %prompt ]
For the PKCS#12 file both absolute paths or paths relative to
\fI/etc/ipsec.d/private\fP are accepted. If the container is
encrypted, the \fIpassphrase\fP must be defined. Instead of a passphrase
.B %prompt
can be used which then causes the daemon to ask the user for the password
whenever it is required to decrypt the container. Private keys, client and CA
certificates are extracted from the container. To use such a client certificate
in a connection set leftid to one of the subjects of the certificate.
.TP
.B <user id> : EAP <secret>
The format of \fIsecret\fP is the same as that of \fBPSK\fP secrets.
.br
@ -165,7 +178,7 @@ key. The slot number defines the slot on the token, the module name refers to
the module name defined in strongswan.conf(5).
Instead of specifying the pin code statically,
.B %prompt
can be specified, which causes the daemons to ask the user for the pin code.
can be specified, which causes the daemon to ask the user for the pin code.
.LP
.SH FILES

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2012 Tobias Brunner
* Copyright (C) 2008-2013 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@ -32,6 +32,7 @@
#include <credentials/certificates/x509.h>
#include <credentials/certificates/crl.h>
#include <credentials/certificates/ac.h>
#include <credentials/containers/pkcs12.h>
#include <credentials/sets/mem_cred.h>
#include <credentials/sets/callback_cred.h>
#include <collections/linked_list.h>
@ -72,7 +73,7 @@ struct private_stroke_cred_t {
/**
* ignore missing CA basic constraint (i.e. treat all certificates in
* ipsec.conf ca sections and ipsec.d/cacert as CA certificates)
* ipsec.conf ca sections and ipsec.d/cacerts as CA certificates)
*/
bool force_ca_cert;
@ -225,7 +226,7 @@ METHOD(stroke_cred_t, load_ca, certificate_t*,
cert->destroy(cert);
return NULL;
}
DBG1(DBG_CFG, " loaded ca certificate \"%Y\" from '%s",
DBG1(DBG_CFG, " loaded ca certificate \"%Y\" from '%s'",
cert->get_subject(cert), filename);
return this->creds->add_cert_ref(this->creds, TRUE, cert);
}
@ -821,15 +822,14 @@ static bool load_pin(mem_cred_t *secrets, chunk_t line, int line_nr,
}
/**
* Load a private key
* Load a private key or PKCS#12 container from a file
*/
static bool load_private(mem_cred_t *secrets, 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;
err_t ugh = extract_value(&filename, &line);
@ -846,12 +846,12 @@ static bool load_private(mem_cred_t *secrets, chunk_t line, int line_nr,
if (*filename.ptr == '/')
{
/* absolute path name */
snprintf(path, sizeof(path), "%.*s", (int)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,
snprintf(path, PATH_MAX, "%s/%.*s", PRIVATE_KEY_DIR,
(int)filename.len, filename.ptr);
}
@ -877,6 +877,7 @@ static bool load_private(mem_cred_t *secrets, chunk_t line, int line_nr,
free(secret.ptr);
if (!prompt)
{
*result = NULL;
return TRUE;
}
/* use callback credential set to prompt for the passphrase */
@ -886,8 +887,8 @@ static bool load_private(mem_cred_t *secrets, chunk_t line, int line_nr,
cb = callback_cred_create_shared((void*)passphrase_cb, &pp_data);
lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE);
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type,
BUILD_FROM_FILE, path, BUILD_END);
*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);
@ -903,12 +904,29 @@ static bool load_private(mem_cred_t *secrets, chunk_t line, int line_nr,
mem->add_shared(mem, shared, NULL);
lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type,
BUILD_FROM_FILE, path, BUILD_END);
*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'",
@ -922,6 +940,58 @@ static bool load_private(mem_cred_t *secrets, chunk_t line, int line_nr,
return TRUE;
}
/**
* Load a PKCS#12 container
*/
static bool load_pkcs12(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);
}
secrets->add_cert(secrets, 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
*/
@ -1140,6 +1210,13 @@ static void load_secrets(private_stroke_cred_t *this, mem_cred_t *secrets,
break;
}
}
else if (match("P12", &token))
{
if (!load_pkcs12(secrets, line, line_nr, prompt))
{
break;
}
}
else if (match("PIN", &token))
{
if (!load_pin(secrets, line, line_nr, prompt))
@ -1160,7 +1237,7 @@ static void load_secrets(private_stroke_cred_t *this, mem_cred_t *secrets,
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;
}
}