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

This commit is contained in:
Tobias Brunner
2013-05-08 15:02:41 +02:00
parent 904390e887
commit 7971278c92
2 changed files with 109 additions and 19 deletions
+17 -4
View File
@@ -91,6 +91,9 @@ defines an RSA private key
.B ECDSA .B ECDSA
defines an ECDSA private key defines an ECDSA private key
.TP .TP
.B P12
defines a PKCS#12 container
.TP
.B EAP .B EAP
defines EAP credentials defines EAP credentials
.TP .TP
@@ -133,16 +136,26 @@ Similarly, a character sequence beginning with
.B 0s .B 0s
is interpreted as Base64 encoded binary data. is interpreted as Base64 encoded binary data.
.TP .TP
.B [ <selectors> ] : RSA <private key file> [ <passphrase> | %prompt ] .B : RSA <private key file> [ <passphrase> | %prompt ]
.TQ .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 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 \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 encrypted, the \fIpassphrase\fP must be defined. Instead of a passphrase
.B %prompt .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. whenever it is required to decrypt the key.
.TP .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> .B <user id> : EAP <secret>
The format of \fIsecret\fP is the same as that of \fBPSK\fP secrets. The format of \fIsecret\fP is the same as that of \fBPSK\fP secrets.
.br .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). the module name defined in strongswan.conf(5).
Instead of specifying the pin code statically, Instead of specifying the pin code statically,
.B %prompt .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 .LP
.SH FILES .SH FILES
+92 -15
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2008-2012 Tobias Brunner * Copyright (C) 2008-2013 Tobias Brunner
* Copyright (C) 2008 Martin Willi * Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil * Hochschule fuer Technik Rapperswil
* *
@@ -32,6 +32,7 @@
#include <credentials/certificates/x509.h> #include <credentials/certificates/x509.h>
#include <credentials/certificates/crl.h> #include <credentials/certificates/crl.h>
#include <credentials/certificates/ac.h> #include <credentials/certificates/ac.h>
#include <credentials/containers/pkcs12.h>
#include <credentials/sets/mem_cred.h> #include <credentials/sets/mem_cred.h>
#include <credentials/sets/callback_cred.h> #include <credentials/sets/callback_cred.h>
#include <collections/linked_list.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 * 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; bool force_ca_cert;
@@ -225,7 +226,7 @@ METHOD(stroke_cred_t, load_ca, certificate_t*,
cert->destroy(cert); cert->destroy(cert);
return NULL; 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); cert->get_subject(cert), filename);
return this->creds->add_cert_ref(this->creds, TRUE, cert); 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, static bool load_from_file(chunk_t line, int line_nr, FILE *prompt,
FILE *prompt, key_type_t key_type) char *path, int type, int subtype,
void **result)
{ {
char path[PATH_MAX];
chunk_t filename; chunk_t filename;
chunk_t secret = chunk_empty; chunk_t secret = chunk_empty;
private_key_t *key;
err_t ugh = extract_value(&filename, &line); 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 == '/') if (*filename.ptr == '/')
{ {
/* absolute path name */ /* absolute path name */
snprintf(path, sizeof(path), "%.*s", (int)filename.len, filename.ptr); snprintf(path, PATH_MAX, "%.*s", (int)filename.len, filename.ptr);
} }
else else
{ {
/* relative path name */ /* 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); (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); free(secret.ptr);
if (!prompt) if (!prompt)
{ {
*result = NULL;
return TRUE; return TRUE;
} }
/* use callback credential set to prompt for the passphrase */ /* 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); cb = callback_cred_create_shared((void*)passphrase_cb, &pp_data);
lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE); lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE);
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type, *result = lib->creds->create(lib->creds, type, subtype,
BUILD_FROM_FILE, path, BUILD_END); BUILD_FROM_FILE, path, BUILD_END);
lib->credmgr->remove_local_set(lib->credmgr, &cb->set); lib->credmgr->remove_local_set(lib->credmgr, &cb->set);
cb->destroy(cb); 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); mem->add_shared(mem, shared, NULL);
lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE); lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type, *result = lib->creds->create(lib->creds, type, subtype,
BUILD_FROM_FILE, path, BUILD_END); BUILD_FROM_FILE, path, BUILD_END);
lib->credmgr->remove_local_set(lib->credmgr, &mem->set); lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
mem->destroy(mem); 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) if (key)
{ {
DBG1(DBG_CFG, " loaded %N private key from '%s'", 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; 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 * Load a shared key
*/ */
@@ -1140,6 +1210,13 @@ static void load_secrets(private_stroke_cred_t *this, mem_cred_t *secrets,
break; break;
} }
} }
else if (match("P12", &token))
{
if (!load_pkcs12(secrets, line, line_nr, prompt))
{
break;
}
}
else if (match("PIN", &token)) else if (match("PIN", &token))
{ {
if (!load_pin(secrets, line, line_nr, prompt)) 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 else
{ {
DBG1(DBG_CFG, "line %d: token must be either " 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; break;
} }
} }