summaryrefslogtreecommitdiff
path: root/src/libstrongswan/plugins/openssl
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/plugins/openssl')
-rw-r--r--src/libstrongswan/plugins/openssl/Makefile.am1
-rw-r--r--src/libstrongswan/plugins/openssl/Makefile.in36
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_crl.c4
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c2
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c2
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_ec_private_key.c2
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_ec_public_key.c2
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_pkcs7.c790
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_pkcs7.h37
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_plugin.c7
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_rng.c2
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c2
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c2
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_util.c2
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_x509.c8
15 files changed, 876 insertions, 23 deletions
diff --git a/src/libstrongswan/plugins/openssl/Makefile.am b/src/libstrongswan/plugins/openssl/Makefile.am
index c59888663..f971a5e08 100644
--- a/src/libstrongswan/plugins/openssl/Makefile.am
+++ b/src/libstrongswan/plugins/openssl/Makefile.am
@@ -23,6 +23,7 @@ libstrongswan_openssl_la_SOURCES = \
openssl_ec_public_key.c openssl_ec_public_key.h \
openssl_x509.c openssl_x509.h \
openssl_crl.c openssl_crl.h \
+ openssl_pkcs7.c openssl_pkcs7.h \
openssl_rng.c openssl_rng.h \
openssl_hmac.c openssl_hmac.h
diff --git a/src/libstrongswan/plugins/openssl/Makefile.in b/src/libstrongswan/plugins/openssl/Makefile.in
index ada44ead3..6d4e2b0d8 100644
--- a/src/libstrongswan/plugins/openssl/Makefile.in
+++ b/src/libstrongswan/plugins/openssl/Makefile.in
@@ -1,9 +1,9 @@
-# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
-# Inc.
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -73,6 +73,12 @@ am__nobase_list = $(am__nobase_strip_setup); \
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
am__installdirs = "$(DESTDIR)$(plugindir)"
LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES)
libstrongswan_openssl_la_DEPENDENCIES =
@@ -82,7 +88,7 @@ am_libstrongswan_openssl_la_OBJECTS = openssl_plugin.lo \
openssl_rsa_private_key.lo openssl_rsa_public_key.lo \
openssl_ec_diffie_hellman.lo openssl_ec_private_key.lo \
openssl_ec_public_key.lo openssl_x509.lo openssl_crl.lo \
- openssl_rng.lo openssl_hmac.lo
+ openssl_pkcs7.lo openssl_rng.lo openssl_hmac.lo
libstrongswan_openssl_la_OBJECTS = \
$(am_libstrongswan_openssl_la_OBJECTS)
libstrongswan_openssl_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
@@ -128,6 +134,7 @@ CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLIB = @DLLIB@
+DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
@@ -155,6 +162,7 @@ LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MYSQLCFLAG = @MYSQLCFLAG@
MYSQLCONFIG = @MYSQLCONFIG@
@@ -182,6 +190,7 @@ RANLIB = @RANLIB@
RTLIB = @RTLIB@
RUBY = @RUBY@
RUBYINCLUDE = @RUBYINCLUDE@
+RUBYLIB = @RUBYLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
@@ -194,6 +203,7 @@ abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
@@ -247,7 +257,6 @@ libexecdir = @libexecdir@
linux_headers = @linux_headers@
localedir = @localedir@
localstatedir = @localstatedir@
-lt_ECHO = @lt_ECHO@
maemo_CFLAGS = @maemo_CFLAGS@
maemo_LIBS = @maemo_LIBS@
manager_plugins = @manager_plugins@
@@ -312,6 +321,7 @@ libstrongswan_openssl_la_SOURCES = \
openssl_ec_public_key.c openssl_ec_public_key.h \
openssl_x509.c openssl_x509.h \
openssl_crl.c openssl_crl.h \
+ openssl_pkcs7.c openssl_pkcs7.h \
openssl_rng.c openssl_rng.h \
openssl_hmac.c openssl_hmac.h
@@ -391,7 +401,7 @@ clean-pluginLTLIBRARIES:
echo "rm -f \"$${dir}/so_locations\""; \
rm -f "$${dir}/so_locations"; \
done
-libstrongswan-openssl.la: $(libstrongswan_openssl_la_OBJECTS) $(libstrongswan_openssl_la_DEPENDENCIES)
+libstrongswan-openssl.la: $(libstrongswan_openssl_la_OBJECTS) $(libstrongswan_openssl_la_DEPENDENCIES) $(EXTRA_libstrongswan_openssl_la_DEPENDENCIES)
$(libstrongswan_openssl_la_LINK) $(am_libstrongswan_openssl_la_rpath) $(libstrongswan_openssl_la_OBJECTS) $(libstrongswan_openssl_la_LIBADD) $(LIBS)
mostlyclean-compile:
@@ -408,6 +418,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_ec_public_key.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_hasher.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_hmac.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_pkcs7.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_plugin.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_rng.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_rsa_private_key.Plo@am__quote@
@@ -542,10 +553,15 @@ install-am: all-am
installcheck: installcheck-am
install-strip:
- $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
- install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
- `test -z '$(STRIP)' || \
- echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
mostlyclean-generic:
clean-generic:
diff --git a/src/libstrongswan/plugins/openssl/openssl_crl.c b/src/libstrongswan/plugins/openssl/openssl_crl.c
index e529ff8a5..d4f36f58b 100644
--- a/src/libstrongswan/plugins/openssl/openssl_crl.c
+++ b/src/libstrongswan/plugins/openssl/openssl_crl.c
@@ -42,8 +42,8 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
-#include <debug.h>
-#include <utils/enumerator.h>
+#include <utils/debug.h>
+#include <collections/enumerator.h>
#include <credentials/certificates/x509.h>
typedef struct private_openssl_crl_t private_openssl_crl_t;
diff --git a/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c b/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c
index b27aa3391..4dc5663f1 100644
--- a/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c
+++ b/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c
@@ -18,7 +18,7 @@
#include "openssl_diffie_hellman.h"
-#include <debug.h>
+#include <utils/debug.h>
typedef struct private_openssl_diffie_hellman_t private_openssl_diffie_hellman_t;
diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c b/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c
index 9e4067589..d846278c8 100644
--- a/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c
+++ b/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c
@@ -23,7 +23,7 @@
#include "openssl_ec_diffie_hellman.h"
#include "openssl_util.h"
-#include <debug.h>
+#include <utils/debug.h>
typedef struct private_openssl_ec_diffie_hellman_t private_openssl_ec_diffie_hellman_t;
diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c b/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c
index 950504573..d350d050b 100644
--- a/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c
+++ b/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c
@@ -22,7 +22,7 @@
#include "openssl_ec_public_key.h"
#include "openssl_util.h"
-#include <debug.h>
+#include <utils/debug.h>
#include <openssl/evp.h>
#include <openssl/ecdsa.h>
diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c b/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c
index 9cb68a3ab..3f5125b31 100644
--- a/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c
+++ b/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c
@@ -21,7 +21,7 @@
#include "openssl_ec_public_key.h"
#include "openssl_util.h"
-#include <debug.h>
+#include <utils/debug.h>
#include <openssl/evp.h>
#include <openssl/ecdsa.h>
diff --git a/src/libstrongswan/plugins/openssl/openssl_pkcs7.c b/src/libstrongswan/plugins/openssl/openssl_pkcs7.c
new file mode 100644
index 000000000..ccc426235
--- /dev/null
+++ b/src/libstrongswan/plugins/openssl/openssl_pkcs7.c
@@ -0,0 +1,790 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 revosec AG
+ *
+ * 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.
+ */
+
+#include <openssl/opensslconf.h>
+
+#ifndef OPENSSL_NO_CMS
+
+#include "openssl_pkcs7.h"
+#include "openssl_util.h"
+
+#include <library.h>
+#include <utils/debug.h>
+#include <asn1/oid.h>
+#include <credentials/sets/mem_cred.h>
+
+#include <openssl/cms.h>
+
+typedef struct private_openssl_pkcs7_t private_openssl_pkcs7_t;
+
+/**
+ * Private data of an openssl_pkcs7_t object.
+ */
+struct private_openssl_pkcs7_t {
+
+ /**
+ * Public pkcs7_t interface.
+ */
+ pkcs7_t public;
+
+ /**
+ * Type of this container
+ */
+ container_type_t type;
+
+ /**
+ * OpenSSL CMS structure
+ */
+ CMS_ContentInfo *cms;
+};
+
+/**
+ * OpenSSL does not allow us to read the signature to verify it with our own
+ * crypto API. We define the internal CMS_SignerInfo structure here to get it.
+ */
+struct CMS_SignerInfo_st {
+ long version;
+ void *sid;
+ X509_ALGOR *digestAlgorithm;
+ STACK_OF(X509_ATTRIBUTE) *signedAttrs;
+ X509_ALGOR *signatureAlgorithm;
+ ASN1_OCTET_STRING *signature;
+ /* and more... */
+};
+
+/**
+ * And we also need access to the wrappend CMS_KeyTransRecipientInfo to
+ * read the encrypted key
+ */
+struct CMS_KeyTransRecipientInfo_st {
+ long version;
+ void *rid;
+ X509_ALGOR *keyEncryptionAlgorithm;
+ ASN1_OCTET_STRING *encryptedKey;
+};
+
+struct CMS_RecipientInfo_st {
+ int type;
+ struct CMS_KeyTransRecipientInfo_st *ktri;
+ /* and more in union... */
+};
+
+struct CMS_EncryptedContentInfo_st {
+ ASN1_OBJECT *contentType;
+ X509_ALGOR *contentEncryptionAlgorithm;
+ ASN1_OCTET_STRING *encryptedContent;
+ /* and more... */
+};
+
+struct CMS_EnvelopedData_st {
+ long version;
+ void *originatorInfo;
+ STACK_OF(CMS_RecipientInfo) *recipientInfos;
+ struct CMS_EncryptedContentInfo_st *encryptedContentInfo;
+ /* and more... */
+};
+
+struct CMS_ContentInfo_st {
+ ASN1_OBJECT *contentType;
+ struct CMS_EnvelopedData_st *envelopedData;
+ /* and more in union... */
+};
+
+/**
+ * We can't include asn1.h, declare function prototypes directly
+ */
+chunk_t asn1_wrap(int, const char *mode, ...);
+int asn1_unwrap(chunk_t*, chunk_t*);
+
+/**
+ * Enumerator over certificates
+ */
+typedef struct {
+ /** implements enumerator_t */
+ enumerator_t public;
+ /** Stack of X509 certificates */
+ STACK_OF(X509) *certs;
+ /** current enumerator position in certificates */
+ int i;
+ /** currently enumerating certificate_t */
+ certificate_t *cert;
+} cert_enumerator_t;
+
+METHOD(enumerator_t, cert_destroy, void,
+ cert_enumerator_t *this)
+{
+ DESTROY_IF(this->cert);
+ free(this);
+}
+
+METHOD(enumerator_t, cert_enumerate, bool,
+ cert_enumerator_t *this, certificate_t **out)
+{
+ if (!this->certs)
+ {
+ return FALSE;
+ }
+ while (this->i < sk_X509_num(this->certs))
+ {
+ chunk_t encoding;
+ X509 *x509;
+
+ /* clean up previous round */
+ DESTROY_IF(this->cert);
+ this->cert = NULL;
+
+ x509 = sk_X509_value(this->certs, this->i++);
+ encoding = openssl_i2chunk(X509, x509);
+ this->cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+ BUILD_BLOB_ASN1_DER, encoding,
+ BUILD_END);
+ free(encoding.ptr);
+ if (!this->cert)
+ {
+ continue;
+ }
+ *out = this->cert;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+METHOD(pkcs7_t, create_cert_enumerator, enumerator_t*,
+ private_openssl_pkcs7_t *this)
+{
+ cert_enumerator_t *enumerator;
+
+ if (this->type == CONTAINER_PKCS7_SIGNED_DATA)
+ {
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)_cert_enumerate,
+ .destroy = _cert_destroy,
+ },
+ .certs = CMS_get1_certs(this->cms),
+ );
+ return &enumerator->public;
+ }
+ return enumerator_create_empty();
+}
+
+/**
+ * Enumerator for signatures
+ */
+typedef struct {
+ /** implements enumerator_t */
+ enumerator_t public;
+ /** Stack of signerinfos */
+ STACK_OF(CMS_SignerInfo) *signers;
+ /** current enumerator position in signers */
+ int i;
+ /** currently enumerating auth config */
+ auth_cfg_t *auth;
+ /** full CMS */
+ CMS_ContentInfo *cms;
+ /** credential set containing wrapped certificates */
+ mem_cred_t *creds;
+} signature_enumerator_t;
+
+/**
+ * Verify signerInfo signature
+ */
+static auth_cfg_t *verify_signature(CMS_SignerInfo *si, int hash_oid)
+{
+ enumerator_t *enumerator;
+ public_key_t *key;
+ certificate_t *cert;
+ auth_cfg_t *auth, *found = NULL;
+ identification_t *issuer, *serial;
+ chunk_t attrs = chunk_empty, sig, attr;
+ X509_NAME *name;
+ ASN1_INTEGER *snr;
+ int i;
+
+ if (CMS_SignerInfo_get0_signer_id(si, NULL, &name, &snr) != 1)
+ {
+ return NULL;
+ }
+ issuer = openssl_x509_name2id(name);
+ if (!issuer)
+ {
+ return NULL;
+ }
+ serial = identification_create_from_encoding(
+ ID_KEY_ID, openssl_asn1_str2chunk(snr));
+
+ /* reconstruct DER encoded attributes to verify signature */
+ for (i = 0; i < CMS_signed_get_attr_count(si); i++)
+ {
+ attr = openssl_i2chunk(X509_ATTRIBUTE, CMS_signed_get_attr(si, i));
+ attrs = chunk_cat("mm", attrs, attr);
+ }
+ /* wrap in a ASN1_SET */
+ attrs = asn1_wrap(0x31, "m", attrs);
+
+ /* TODO: find a better way to access and verify the signature */
+ sig = openssl_asn1_str2chunk(si->signature);
+ enumerator = lib->credmgr->create_trusted_enumerator(lib->credmgr,
+ KEY_RSA, serial, FALSE);
+ while (enumerator->enumerate(enumerator, &cert, &auth))
+ {
+ if (issuer->equals(issuer, cert->get_issuer(cert)))
+ {
+ key = cert->get_public_key(cert);
+ if (key)
+ {
+ if (key->verify(key, signature_scheme_from_oid(hash_oid),
+ attrs, sig))
+ {
+ found = auth->clone(auth);
+ key->destroy(key);
+ break;
+ }
+ key->destroy(key);
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ issuer->destroy(issuer);
+ serial->destroy(serial);
+ free(attrs.ptr);
+
+ return found;
+}
+
+/**
+ * Verify the message digest in the signerInfo attributes
+ */
+static bool verify_digest(CMS_ContentInfo *cms, CMS_SignerInfo *si, int hash_oid)
+{
+ ASN1_OCTET_STRING *os, **osp;
+ hash_algorithm_t hash_alg;
+ chunk_t digest, content, hash;
+ hasher_t *hasher;
+
+ os = CMS_signed_get0_data_by_OBJ(si,
+ OBJ_nid2obj(NID_pkcs9_messageDigest), -3, V_ASN1_OCTET_STRING);
+ if (!os)
+ {
+ return FALSE;
+ }
+ digest = openssl_asn1_str2chunk(os);
+ osp = CMS_get0_content(cms);
+ if (!osp)
+ {
+ return FALSE;
+ }
+ content = openssl_asn1_str2chunk(*osp);
+
+ hash_alg = hasher_algorithm_from_oid(hash_oid);
+ hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
+ if (!hasher)
+ {
+ DBG1(DBG_LIB, "hash algorithm %N not supported",
+ hash_algorithm_names, hash_alg);
+ return FALSE;
+ }
+ if (!hasher->allocate_hash(hasher, content, &hash))
+ {
+ hasher->destroy(hasher);
+ return FALSE;
+ }
+ hasher->destroy(hasher);
+
+ if (!chunk_equals(digest, hash))
+ {
+ free(hash.ptr);
+ DBG1(DBG_LIB, "invalid messageDigest");
+ return FALSE;
+ }
+ free(hash.ptr);
+ return TRUE;
+}
+
+METHOD(enumerator_t, signature_enumerate, bool,
+ signature_enumerator_t *this, auth_cfg_t **out)
+{
+ if (!this->signers)
+ {
+ return FALSE;
+ }
+ while (this->i < sk_CMS_SignerInfo_num(this->signers))
+ {
+ CMS_SignerInfo *si;
+ X509_ALGOR *digest, *sig;
+ int hash_oid;
+
+ /* clean up previous round */
+ DESTROY_IF(this->auth);
+ this->auth = NULL;
+
+ si = sk_CMS_SignerInfo_value(this->signers, this->i++);
+
+ CMS_SignerInfo_get0_algs(si, NULL, NULL, &digest, &sig);
+ hash_oid = openssl_asn1_known_oid(digest->algorithm);
+ if (openssl_asn1_known_oid(sig->algorithm) != OID_RSA_ENCRYPTION)
+ {
+ DBG1(DBG_LIB, "only RSA digest encryption supported");
+ continue;
+ }
+ this->auth = verify_signature(si, hash_oid);
+ if (!this->auth)
+ {
+ DBG1(DBG_LIB, "unable to verify pkcs7 attributes signature");
+ continue;
+ }
+ if (!verify_digest(this->cms, si, hash_oid))
+ {
+ continue;
+ }
+ *out = this->auth;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+METHOD(enumerator_t, signature_destroy, void,
+ signature_enumerator_t *this)
+{
+ lib->credmgr->remove_local_set(lib->credmgr, &this->creds->set);
+ this->creds->destroy(this->creds);
+ DESTROY_IF(this->auth);
+ free(this);
+}
+
+METHOD(container_t, create_signature_enumerator, enumerator_t*,
+ private_openssl_pkcs7_t *this)
+{
+ signature_enumerator_t *enumerator;
+
+ if (this->type == CONTAINER_PKCS7_SIGNED_DATA)
+ {
+ enumerator_t *certs;
+ certificate_t *cert;
+
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)_signature_enumerate,
+ .destroy = _signature_destroy,
+ },
+ .cms = this->cms,
+ .signers = CMS_get0_SignerInfos(this->cms),
+ .creds = mem_cred_create(),
+ );
+
+ /* make available wrapped certs during signature checking */
+ certs = create_cert_enumerator(this);
+ while (certs->enumerate(certs, &cert))
+ {
+ enumerator->creds->add_cert(enumerator->creds, FALSE,
+ cert->get_ref(cert));
+ }
+ certs->destroy(certs);
+
+ lib->credmgr->add_local_set(lib->credmgr, &enumerator->creds->set,
+ FALSE);
+
+ return &enumerator->public;
+ }
+ return enumerator_create_empty();
+}
+
+
+METHOD(container_t, get_type, container_type_t,
+ private_openssl_pkcs7_t *this)
+{
+ return this->type;
+}
+
+METHOD(pkcs7_t, get_attribute, bool,
+ private_openssl_pkcs7_t *this, int oid,
+ enumerator_t *enumerator, chunk_t *value)
+{
+ signature_enumerator_t *e;
+ CMS_SignerInfo *si;
+ X509_ATTRIBUTE *attr;
+ ASN1_TYPE *type;
+ chunk_t chunk, wrapped;
+ int i;
+
+ e = (signature_enumerator_t*)enumerator;
+ if (e->i <= 0)
+ {
+ return FALSE;
+ }
+
+ /* "i" gets incremeneted after enumerate(), hence read from previous */
+ si = sk_CMS_SignerInfo_value(e->signers, e->i - 1);
+ for (i = 0; i < CMS_signed_get_attr_count(si); i++)
+ {
+ attr = CMS_signed_get_attr(si, i);
+ if (!attr->single && sk_ASN1_TYPE_num(attr->value.set) == 1 &&
+ openssl_asn1_known_oid(attr->object) == oid)
+ {
+ /* get first value in SET */
+ type = sk_ASN1_TYPE_value(attr->value.set, 0);
+ chunk = wrapped = openssl_i2chunk(ASN1_TYPE, type);
+ if (asn1_unwrap(&chunk, &chunk) != 0x100 /* ASN1_INVALID */)
+ {
+ *value = chunk_clone(chunk);
+ free(wrapped.ptr);
+ return TRUE;
+ }
+ free(wrapped.ptr);
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Find a private key for issuerAndSerialNumber
+ */
+static private_key_t *find_private(identification_t *issuer,
+ identification_t *serial)
+{
+ enumerator_t *enumerator;
+ certificate_t *cert;
+ public_key_t *public;
+ private_key_t *private = NULL;
+ identification_t *id;
+ chunk_t fp;
+
+ enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
+ CERT_X509, KEY_RSA, serial, FALSE);
+ while (enumerator->enumerate(enumerator, &cert))
+ {
+ if (issuer->equals(issuer, cert->get_issuer(cert)))
+ {
+ public = cert->get_public_key(cert);
+ if (public)
+ {
+ if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &fp))
+ {
+ id = identification_create_from_encoding(ID_KEY_ID, fp);
+ private = lib->credmgr->get_private(lib->credmgr,
+ KEY_ANY, id, NULL);
+ id->destroy(id);
+ }
+ public->destroy(public);
+ }
+ }
+ if (private)
+ {
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return private;
+}
+
+/**
+ * Decrypt enveloped-data with a decrypted symmetric key
+ */
+static bool decrypt_symmetric(private_openssl_pkcs7_t *this, chunk_t key,
+ chunk_t encrypted, chunk_t *plain)
+{
+ encryption_algorithm_t encr;
+ X509_ALGOR *alg;
+ crypter_t *crypter;
+ chunk_t iv;
+ size_t key_size;
+
+ /* read encryption algorithm from interal structures; TODO fixup */
+ alg = this->cms->envelopedData->encryptedContentInfo->
+ contentEncryptionAlgorithm;
+ encr = encryption_algorithm_from_oid(openssl_asn1_known_oid(alg->algorithm),
+ &key_size);
+ if (alg->parameter->type != V_ASN1_OCTET_STRING)
+ {
+ return FALSE;
+ }
+ iv = openssl_asn1_str2chunk(alg->parameter->value.octet_string);
+
+ crypter = lib->crypto->create_crypter(lib->crypto, encr, key_size / 8);
+ if (!crypter)
+ {
+ DBG1(DBG_LIB, "crypter %N-%d not available",
+ encryption_algorithm_names, alg, key_size);
+ return FALSE;
+ }
+ if (key.len != crypter->get_key_size(crypter))
+ {
+ DBG1(DBG_LIB, "symmetric key length is wrong");
+ crypter->destroy(crypter);
+ return FALSE;
+ }
+ if (iv.len != crypter->get_iv_size(crypter))
+ {
+ DBG1(DBG_LIB, "IV length is wrong");
+ crypter->destroy(crypter);
+ return FALSE;
+ }
+ if (!crypter->set_key(crypter, key) ||
+ !crypter->decrypt(crypter, encrypted, iv, plain))
+ {
+ crypter->destroy(crypter);
+ return FALSE;
+ }
+ crypter->destroy(crypter);
+ return TRUE;
+}
+
+/**
+ * Remove enveloped-data PKCS#7 padding from plain data
+ */
+static bool remove_padding(chunk_t *data)
+{
+ u_char *pos;
+ u_char pattern;
+ size_t padding;
+
+ if (!data->len)
+ {
+ return FALSE;
+ }
+ pos = data->ptr + data->len - 1;
+ padding = pattern = *pos;
+
+ if (padding > data->len)
+ {
+ DBG1(DBG_LIB, "padding greater than data length");
+ return FALSE;
+ }
+ data->len -= padding;
+
+ while (padding-- > 0)
+ {
+ if (*pos-- != pattern)
+ {
+ DBG1(DBG_LIB, "wrong padding pattern");
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ * Decrypt PKCS#7 enveloped-data
+ */
+static bool decrypt(private_openssl_pkcs7_t *this,
+ chunk_t encrypted, chunk_t *plain)
+{
+ STACK_OF(CMS_RecipientInfo) *ris;
+ CMS_RecipientInfo *ri;
+ chunk_t chunk, key = chunk_empty;
+ int i;
+
+ ris = CMS_get0_RecipientInfos(this->cms);
+ for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
+ {
+ ri = sk_CMS_RecipientInfo_value(ris, i);
+ if (CMS_RecipientInfo_type(ri) == CMS_RECIPINFO_TRANS)
+ {
+ identification_t *serial, *issuer;
+ private_key_t *private;
+ X509_ALGOR *alg;
+ X509_NAME *name;
+ ASN1_INTEGER *sn;
+ u_char zero = 0;
+ int oid;
+
+ if (CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &alg) == 1 &&
+ CMS_RecipientInfo_ktri_get0_signer_id(ri, NULL, &name, &sn) == 1)
+ {
+ oid = openssl_asn1_known_oid(alg->algorithm);
+ if (oid != OID_RSA_ENCRYPTION)
+ {
+ DBG1(DBG_LIB, "only RSA encryption supported in PKCS#7");
+ continue;
+ }
+ issuer = openssl_x509_name2id(name);
+ if (!issuer)
+ {
+ continue;
+ }
+ chunk = openssl_asn1_str2chunk(sn);
+ if (chunk.len && chunk.ptr[0] & 0x80)
+ { /* if MSB is set, append a zero to make it non-negative */
+ chunk = chunk_cata("cc", chunk_from_thing(zero), chunk);
+ }
+ serial = identification_create_from_encoding(ID_KEY_ID, chunk);
+ private = find_private(issuer, serial);
+ issuer->destroy(issuer);
+ serial->destroy(serial);
+
+ if (private)
+ {
+ /* get encryptedKey from internal structure; TODO fixup */
+ chunk = openssl_asn1_str2chunk(ri->ktri->encryptedKey);
+ if (private->decrypt(private, ENCRYPT_RSA_PKCS1,
+ chunk, &key))
+ {
+ private->destroy(private);
+ break;
+ }
+ private->destroy(private);
+ }
+ }
+ }
+ }
+ if (!key.len)
+ {
+ DBG1(DBG_LIB, "no private key found to decrypt PKCS#7");
+ return FALSE;
+ }
+ if (!decrypt_symmetric(this, key, encrypted, plain))
+ {
+ chunk_clear(&key);
+ return FALSE;
+ }
+ chunk_clear(&key);
+ if (!remove_padding(plain))
+ {
+ free(plain->ptr);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+METHOD(container_t, get_data, bool,
+ private_openssl_pkcs7_t *this, chunk_t *data)
+{
+ ASN1_OCTET_STRING **os;
+ chunk_t chunk;
+
+ os = CMS_get0_content(this->cms);
+ if (os)
+ {
+ chunk = openssl_asn1_str2chunk(*os);
+ switch (this->type)
+ {
+ case CONTAINER_PKCS7_DATA:
+ case CONTAINER_PKCS7_SIGNED_DATA:
+ *data = chunk_clone(chunk);
+ return TRUE;
+ case CONTAINER_PKCS7_ENVELOPED_DATA:
+ return decrypt(this, chunk, data);
+ default:
+ break;
+ }
+ }
+ return FALSE;
+}
+
+METHOD(container_t, get_encoding, bool,
+ private_openssl_pkcs7_t *this, chunk_t *data)
+{
+ return FALSE;
+}
+
+METHOD(container_t, destroy, void,
+ private_openssl_pkcs7_t *this)
+{
+ CMS_ContentInfo_free(this->cms);
+ free(this);
+}
+
+/**
+ * Generic constructor
+ */
+static private_openssl_pkcs7_t* create_empty()
+{
+ private_openssl_pkcs7_t *this;
+
+ INIT(this,
+ .public = {
+ .container = {
+ .get_type = _get_type,
+ .create_signature_enumerator = _create_signature_enumerator,
+ .get_data = _get_data,
+ .get_encoding = _get_encoding,
+ .destroy = _destroy,
+ },
+ .get_attribute = _get_attribute,
+ .create_cert_enumerator = _create_cert_enumerator,
+ },
+ );
+
+ return this;
+}
+
+/**
+ * Parse a PKCS#7 container
+ */
+static bool parse(private_openssl_pkcs7_t *this, chunk_t blob)
+{
+ BIO *bio;
+
+ bio = BIO_new_mem_buf(blob.ptr, blob.len);
+ this->cms = d2i_CMS_bio(bio, NULL);
+ BIO_free(bio);
+
+ if (!this->cms)
+ {
+ return FALSE;
+ }
+ switch (openssl_asn1_known_oid((ASN1_OBJECT*)CMS_get0_type(this->cms)))
+ {
+ case OID_PKCS7_DATA:
+ this->type = CONTAINER_PKCS7_DATA;
+ break;
+ case OID_PKCS7_SIGNED_DATA:
+ this->type = CONTAINER_PKCS7_SIGNED_DATA;
+ break;
+ case OID_PKCS7_ENVELOPED_DATA:
+ this->type = CONTAINER_PKCS7_ENVELOPED_DATA;
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * See header
+ */
+pkcs7_t *openssl_pkcs7_load(container_type_t type, va_list args)
+{
+ chunk_t blob = chunk_empty;
+ private_openssl_pkcs7_t *this;
+
+ 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;
+ }
+ if (blob.len)
+ {
+ this = create_empty();
+ if (parse(this, blob))
+ {
+ return &this->public;
+ }
+ destroy(this);
+ }
+ return NULL;
+}
+
+#endif /* OPENSSL_NO_CMS */
diff --git a/src/libstrongswan/plugins/openssl/openssl_pkcs7.h b/src/libstrongswan/plugins/openssl/openssl_pkcs7.h
new file mode 100644
index 000000000..2c7939ebd
--- /dev/null
+++ b/src/libstrongswan/plugins/openssl/openssl_pkcs7.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 revosec AG
+ *
+ * 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_pkcs7 openssl_pkcs7
+ * @{ @ingroup openssl_p
+ */
+
+#ifndef OPENSSL_PKCS7_H_
+#define OPENSSL_PKCS7_H_
+
+#include <credentials/containers/pkcs7.h>
+
+/**
+ * Load a generic PKCS#7 container.
+ *
+ * The argument list must contain a single BUILD_BLOB_ASN1_DER argument.
+ *
+ * @param type type of the container, CONTAINER_PKCS7
+ * @param args builder_part_t argument list
+ * @return container, NULL on failure
+ */
+pkcs7_t *openssl_pkcs7_load(container_type_t type, va_list args);
+
+#endif /** OPENSSL_PKCS7_H_ @}*/
diff --git a/src/libstrongswan/plugins/openssl/openssl_plugin.c b/src/libstrongswan/plugins/openssl/openssl_plugin.c
index b69de981e..dd6a379d2 100644
--- a/src/libstrongswan/plugins/openssl/openssl_plugin.c
+++ b/src/libstrongswan/plugins/openssl/openssl_plugin.c
@@ -25,7 +25,7 @@
#include "openssl_plugin.h"
#include <library.h>
-#include <debug.h>
+#include <utils/debug.h>
#include <threading/thread.h>
#include <threading/mutex.h>
#include "openssl_util.h"
@@ -40,6 +40,7 @@
#include "openssl_ec_public_key.h"
#include "openssl_x509.h"
#include "openssl_crl.h"
+#include "openssl_pkcs7.h"
#include "openssl_rng.h"
#include "openssl_hmac.h"
@@ -365,6 +366,10 @@ METHOD(plugin_t, get_features, int,
PLUGIN_SDEPEND(PUBKEY, KEY_DSA),
PLUGIN_REGISTER(CERT_DECODE, openssl_crl_load, TRUE),
PLUGIN_PROVIDE(CERT_DECODE, CERT_X509_CRL),
+#ifndef OPENSSL_NO_CMS
+ PLUGIN_REGISTER(CONTAINER_DECODE, openssl_pkcs7_load, TRUE),
+ PLUGIN_PROVIDE(CONTAINER_DECODE, CONTAINER_PKCS7),
+#endif /* OPENSSL_NO_CMS */
#ifndef OPENSSL_NO_ECDH
/* EC DH groups */
PLUGIN_REGISTER(DH, openssl_ec_diffie_hellman_create),
diff --git a/src/libstrongswan/plugins/openssl/openssl_rng.c b/src/libstrongswan/plugins/openssl/openssl_rng.c
index c83244f60..d3d64f5e8 100644
--- a/src/libstrongswan/plugins/openssl/openssl_rng.c
+++ b/src/libstrongswan/plugins/openssl/openssl_rng.c
@@ -20,7 +20,7 @@
* THE SOFTWARE.
*/
-#include <debug.h>
+#include <utils/debug.h>
#include <openssl/rand.h>
#include <openssl/err.h>
diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c
index 98cd700bf..926e5928c 100644
--- a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c
+++ b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c
@@ -17,7 +17,7 @@
#include "openssl_rsa_private_key.h"
#include "openssl_rsa_public_key.h"
-#include <debug.h>
+#include <utils/debug.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c
index 5872a8159..0da5d2514 100644
--- a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c
+++ b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c
@@ -16,7 +16,7 @@
#include "openssl_rsa_public_key.h"
-#include <debug.h>
+#include <utils/debug.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
diff --git a/src/libstrongswan/plugins/openssl/openssl_util.c b/src/libstrongswan/plugins/openssl/openssl_util.c
index 1eb1c6723..bc10dd28c 100644
--- a/src/libstrongswan/plugins/openssl/openssl_util.c
+++ b/src/libstrongswan/plugins/openssl/openssl_util.c
@@ -16,7 +16,7 @@
#include "openssl_util.h"
-#include <debug.h>
+#include <utils/debug.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
diff --git a/src/libstrongswan/plugins/openssl/openssl_x509.c b/src/libstrongswan/plugins/openssl/openssl_x509.c
index e85c5cc90..676b97f7a 100644
--- a/src/libstrongswan/plugins/openssl/openssl_x509.c
+++ b/src/libstrongswan/plugins/openssl/openssl_x509.c
@@ -47,9 +47,9 @@
#include "openssl_x509.h"
#include "openssl_util.h"
-#include <debug.h>
+#include <utils/debug.h>
#include <asn1/oid.h>
-#include <utils/linked_list.h>
+#include <collections/linked_list.h>
typedef struct private_openssl_x509_t private_openssl_x509_t;
@@ -327,6 +327,10 @@ METHOD(certificate_t, has_subject, id_match_t,
{
return ID_MATCH_PERFECT;
}
+ if (chunk_equals(get_serial(this), encoding))
+ {
+ return ID_MATCH_PERFECT;
+ }
}
best = this->subject->matches(this->subject, subject);
enumerator = create_subjectAltName_enumerator(this);