stroke: Load credentials from PKCS#12 files (P12 token)
authorTobias Brunner <tobias@strongswan.org>
Wed, 17 Apr 2013 11:49:13 +0000 (13:49 +0200)
committerTobias Brunner <tobias@strongswan.org>
Wed, 8 May 2013 13:02:41 +0000 (15:02 +0200)
man/ipsec.secrets.5.in
src/libcharon/plugins/stroke/stroke_cred.c

index 319d485..ee20c96 100644 (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
index f24082e..7034100 100644 (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'",
@@ -923,6 +941,58 @@ static bool load_private(mem_cred_t *secrets, chunk_t line, int line_nr,
 }
 
 /**
+ * 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
  */
 static bool load_shared(mem_cred_t *secrets, chunk_t line, int line_nr,
@@ -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;
                }
        }