aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2013-04-17 11:43:06 +0200
committerTobias Brunner <tobias@strongswan.org>2013-05-08 15:02:40 +0200
commit780900ab0e747a4dbdf70bfa2a40f1cd19581744 (patch)
treef4fac5f8aae166d35988d05d0f881cef606ac6ac
parent651d5ab8e72f2dd2ce40544b59d974007afdc880 (diff)
downloadstrongswan-780900ab0e747a4dbdf70bfa2a40f1cd19581744.tar.bz2
strongswan-780900ab0e747a4dbdf70bfa2a40f1cd19581744.tar.xz
openssl: Add PKCS#12 parsing via OpenSSL
-rw-r--r--src/libstrongswan/plugins/openssl/Makefile.am1
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_pkcs12.c266
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_pkcs12.h37
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_plugin.c3
4 files changed, 307 insertions, 0 deletions
diff --git a/src/libstrongswan/plugins/openssl/Makefile.am b/src/libstrongswan/plugins/openssl/Makefile.am
index 0ca27983f..7ae5ea43e 100644
--- a/src/libstrongswan/plugins/openssl/Makefile.am
+++ b/src/libstrongswan/plugins/openssl/Makefile.am
@@ -24,6 +24,7 @@ libstrongswan_openssl_la_SOURCES = \
openssl_x509.c openssl_x509.h \
openssl_crl.c openssl_crl.h \
openssl_pkcs7.c openssl_pkcs7.h \
+ openssl_pkcs12.c openssl_pkcs12.h \
openssl_rng.c openssl_rng.h \
openssl_hmac.c openssl_hmac.h \
openssl_gcm.c openssl_gcm.h
diff --git a/src/libstrongswan/plugins/openssl/openssl_pkcs12.c b/src/libstrongswan/plugins/openssl/openssl_pkcs12.c
new file mode 100644
index 000000000..d16b2cc05
--- /dev/null
+++ b/src/libstrongswan/plugins/openssl/openssl_pkcs12.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE /* for asprintf() */
+#include <stdio.h>
+#include <openssl/pkcs12.h>
+
+#include "openssl_pkcs12.h"
+#include "openssl_util.h"
+
+#include <library.h>
+#include <credentials/sets/mem_cred.h>
+
+typedef struct private_pkcs12_t private_pkcs12_t;
+
+/**
+ * Private data of a pkcs12_t object.
+ */
+struct private_pkcs12_t {
+
+ /**
+ * Public pkcs12_t interface.
+ */
+ pkcs12_t public;
+
+ /**
+ * OpenSSL PKCS#12 structure
+ */
+ PKCS12 *p12;
+
+ /**
+ * Credentials contained in container
+ */
+ mem_cred_t *creds;
+};
+
+/**
+ * Decode certificate and add it to our credential set
+ */
+static bool add_cert(private_pkcs12_t *this, X509 *x509)
+{
+ certificate_t *cert = NULL;
+ chunk_t encoding;
+
+ if (!x509)
+ { /* no certificate is ok */
+ return TRUE;
+ }
+ encoding = openssl_i2chunk(X509, x509);
+ if (encoding.ptr)
+ {
+ cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+ BUILD_BLOB_ASN1_DER, encoding,
+ BUILD_END);
+ if (cert)
+ {
+ this->creds->add_cert(this->creds, FALSE, cert);
+ }
+ }
+ chunk_free(&encoding);
+ X509_free(x509);
+ return cert != NULL;
+}
+
+/**
+ * Add CA certificates to our credential set
+ */
+static bool add_cas(private_pkcs12_t *this, STACK_OF(X509) *cas)
+{
+ bool success = TRUE;
+ int i;
+
+ if (!cas)
+ { /* no CAs is ok */
+ return TRUE;
+ }
+ for (i = 0; i < sk_X509_num(cas); i++)
+ {
+ if (!add_cert(this, sk_X509_value(cas, i)))
+ { /* continue to free all X509 objects */
+ success = FALSE;
+ }
+ }
+ sk_X509_free(cas);
+ return success;
+}
+
+/**
+ * Decode private key and add it to our credential set
+ */
+static bool add_key(private_pkcs12_t *this, EVP_PKEY *private)
+{
+ private_key_t *key = NULL;
+ chunk_t encoding;
+ key_type_t type;
+
+ if (!private)
+ { /* no private key is ok */
+ return TRUE;
+ }
+ switch (EVP_PKEY_type(private->type))
+ {
+ case EVP_PKEY_RSA:
+ type = KEY_RSA;
+ break;
+ case EVP_PKEY_EC:
+ type = KEY_ECDSA;
+ break;
+ default:
+ EVP_PKEY_free(private);
+ return FALSE;
+ }
+ encoding = openssl_i2chunk(PrivateKey, private);
+ if (encoding.ptr)
+ {
+ key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
+ BUILD_BLOB_ASN1_DER, encoding,
+ BUILD_END);
+ if (key)
+ {
+ this->creds->add_key(this->creds, key);
+ }
+ }
+ chunk_clear(&encoding);
+ EVP_PKEY_free(private);
+ return key != NULL;
+}
+
+/**
+ * Decrypt PKCS#12 file and unpack credentials
+ */
+static bool decrypt_and_unpack(private_pkcs12_t *this)
+{
+ enumerator_t *enumerator;
+ shared_key_t *shared;
+ STACK_OF(X509) *cas = NULL;
+ EVP_PKEY *private;
+ X509 *cert;
+ chunk_t key;
+ char *password;
+ bool success = FALSE;
+
+ enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
+ SHARED_PRIVATE_KEY_PASS, NULL, NULL);
+ while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
+ {
+ key = shared->get_key(shared);
+ if (!key.ptr || asprintf(&password, "%.*s", (int)key.len, key.ptr) < 0)
+ {
+ password = NULL;
+ }
+ if (PKCS12_parse(this->p12, password, &private, &cert, &cas))
+ {
+ success = add_key(this, private);
+ success &= add_cert(this, cert);
+ success &= add_cas(this, cas);
+ free(password);
+ break;
+ }
+ free(password);
+ }
+ enumerator->destroy(enumerator);
+ return success;
+}
+
+METHOD(container_t, get_type, container_type_t,
+ private_pkcs12_t *this)
+{
+ return CONTAINER_PKCS12;
+}
+
+METHOD(pkcs12_t, create_cert_enumerator, enumerator_t*,
+ private_pkcs12_t *this)
+{
+ return this->creds->set.create_cert_enumerator(&this->creds->set, CERT_ANY,
+ KEY_ANY, NULL, FALSE);
+}
+
+METHOD(pkcs12_t, create_key_enumerator, enumerator_t*,
+ private_pkcs12_t *this)
+{
+ return this->creds->set.create_private_enumerator(&this->creds->set,
+ KEY_ANY, NULL);
+}
+
+METHOD(container_t, destroy, void,
+ private_pkcs12_t *this)
+{
+ if (this->p12)
+ {
+ PKCS12_free(this->p12);
+ }
+ this->creds->destroy(this->creds);
+ free(this);
+}
+
+/**
+ * Parse a PKCS#12 container
+ */
+static pkcs12_t *parse(chunk_t blob)
+{
+ private_pkcs12_t *this;
+ BIO *bio;
+
+ INIT(this,
+ .public = {
+ .container = {
+ .get_type = _get_type,
+ .create_signature_enumerator = (void*)enumerator_create_empty,
+ .get_data = (void*)return_false,
+ .get_encoding = (void*)return_false,
+ .destroy = _destroy,
+ },
+ .create_cert_enumerator = _create_cert_enumerator,
+ .create_key_enumerator = _create_key_enumerator,
+ },
+ .creds = mem_cred_create(),
+ );
+
+ bio = BIO_new_mem_buf(blob.ptr, blob.len);
+ this->p12 = d2i_PKCS12_bio(bio, NULL);
+ BIO_free(bio);
+
+ if (!this->p12 || !decrypt_and_unpack(this))
+ {
+ destroy(this);
+ return NULL;
+ }
+ return &this->public;
+}
+
+/*
+ * Defined in header
+ */
+pkcs12_t *openssl_pkcs12_load(container_type_t type, va_list args)
+{
+ chunk_t blob = chunk_empty;
+
+ while (TRUE)
+ {
+ switch (va_arg(args, builder_part_t))
+ {
+ case BUILD_BLOB_ASN1_DER:
+ blob = va_arg(args, chunk_t);
+ continue;
+ case BUILD_END:
+ break;
+ default:
+ return NULL;
+ }
+ break;
+ }
+ return blob.len ? parse(blob) : NULL;
+}
diff --git a/src/libstrongswan/plugins/openssl/openssl_pkcs12.h b/src/libstrongswan/plugins/openssl/openssl_pkcs12.h
new file mode 100644
index 000000000..5c3e5933d
--- /dev/null
+++ b/src/libstrongswan/plugins/openssl/openssl_pkcs12.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup openssl_pkcs12 openssl_pkcs12
+ * @{ @ingroup openssl_p
+ */
+
+#ifndef OPENSSL_PKCS12_H_
+#define OPENSSL_PKCS12_H_
+
+#include <credentials/containers/pkcs12.h>
+
+/**
+ * Load a PKCS#12 container.
+ *
+ * The argument list must contain a single BUILD_BLOB_ASN1_DER argument.
+ *
+ * @param type type of the container, CONTAINER_PKCS12
+ * @param args builder_part_t argument list
+ * @return container, NULL on failure
+ */
+pkcs12_t *openssl_pkcs12_load(container_type_t type, va_list args);
+
+#endif /** OPENSSL_PKCS12_H_ @}*/
diff --git a/src/libstrongswan/plugins/openssl/openssl_plugin.c b/src/libstrongswan/plugins/openssl/openssl_plugin.c
index 2371008fd..174f94e05 100644
--- a/src/libstrongswan/plugins/openssl/openssl_plugin.c
+++ b/src/libstrongswan/plugins/openssl/openssl_plugin.c
@@ -42,6 +42,7 @@
#include "openssl_x509.h"
#include "openssl_crl.h"
#include "openssl_pkcs7.h"
+#include "openssl_pkcs12.h"
#include "openssl_rng.h"
#include "openssl_hmac.h"
#include "openssl_gcm.h"
@@ -394,6 +395,8 @@ METHOD(plugin_t, get_features, int,
PLUGIN_PROVIDE(CONTAINER_DECODE, CONTAINER_PKCS7),
#endif /* OPENSSL_NO_CMS */
#endif /* OPENSSL_VERSION_NUMBER */
+ PLUGIN_REGISTER(CONTAINER_DECODE, openssl_pkcs12_load, TRUE),
+ PLUGIN_PROVIDE(CONTAINER_DECODE, CONTAINER_PKCS12),
#ifndef OPENSSL_NO_ECDH
/* EC DH groups */
PLUGIN_REGISTER(DH, openssl_ec_diffie_hellman_create),