summaryrefslogtreecommitdiff
path: root/usr/src/lib/libkmf/plugins/kmf_openssl
diff options
context:
space:
mode:
authorwyllys <none@none>2006-11-10 15:34:56 -0800
committerwyllys <none@none>2006-11-10 15:34:56 -0800
commit99ebb4ca412cb0a19d77a3899a87c055b9c30fa8 (patch)
treea972f78468519a4e00234388688f45a506e934ba /usr/src/lib/libkmf/plugins/kmf_openssl
parent177fd15c9f814babb60e824f89984cdd8acf7c85 (diff)
downloadillumos-joyent-99ebb4ca412cb0a19d77a3899a87c055b9c30fa8.tar.gz
PSARC 2005/074 Solaris Key Management Framework
6224192 Solaris needs unified key management interfaces --HG-- rename : usr/src/cmd/cmd-crypto/pktool/biginteger.h => deleted_files/usr/src/cmd/cmd-crypto/pktool/biginteger.h rename : usr/src/cmd/cmd-crypto/pktool/derparse.c => deleted_files/usr/src/cmd/cmd-crypto/pktool/derparse.c rename : usr/src/cmd/cmd-crypto/pktool/derparse.h => deleted_files/usr/src/cmd/cmd-crypto/pktool/derparse.h rename : usr/src/cmd/cmd-crypto/pktool/osslcommon.c => deleted_files/usr/src/cmd/cmd-crypto/pktool/osslcommon.c rename : usr/src/cmd/cmd-crypto/pktool/osslcommon.h => deleted_files/usr/src/cmd/cmd-crypto/pktool/osslcommon.h rename : usr/src/cmd/cmd-crypto/pktool/p12common.c => deleted_files/usr/src/cmd/cmd-crypto/pktool/p12common.c rename : usr/src/cmd/cmd-crypto/pktool/p12common.h => deleted_files/usr/src/cmd/cmd-crypto/pktool/p12common.h
Diffstat (limited to 'usr/src/lib/libkmf/plugins/kmf_openssl')
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/Makefile46
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com78
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/amd64/Makefile32
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers61
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c4198
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/i386/Makefile29
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/sparc/Makefile29
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/sparcv9/Makefile31
8 files changed, 4504 insertions, 0 deletions
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile
new file mode 100644
index 0000000000..ba73e41d2e
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile
@@ -0,0 +1,46 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include $(SRC)/lib/Makefile.lib
+
+SUBDIRS= $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET= all
+check := TARGET= check
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com b/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com
new file mode 100644
index 0000000000..3ae32a00da
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com
@@ -0,0 +1,78 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Makefile for KMF Plugins
+#
+
+LIBRARY= kmf_openssl.a
+VERS= .1
+
+OBJECTS= openssl_spi.o
+
+include $(SRC)/lib/Makefile.lib
+
+LIBLINKS= $(DYNLIB:.so.1=.so)
+SFWDIR= /usr/sfw
+KMFINC= -I../../../include -I../../../ber_der/inc
+BERLIB= -lkmf -lkmfberder
+BERLIB64= $(BERLIB)
+
+OPENSSLLIBS= $(BERLIB) -R$(SFWDIR)/lib -L$(ROOT)/$(SFWDIR)/lib -lcrypto -lcryptoutil -lc
+OPENSSLLIBS64= $(BERLIB64) -R$(SFWDIR)/lib/$(MACH64) -L$(ROOT)/$(SFWDIR)/lib/$(MACH64) \
+ -lcrypto -lcryptoutil -lc
+
+LINTSSLLIBS = $(BERLIB) -L$(ROOT)/$(SFWDIR)/lib -lcrypto -lcryptoutil -lc
+LINTSSLLIBS64= $(BERLIB64) -L$(ROOT)/$(SFWDIR)/lib/$(MACH64) \
+ -lcrypto -lcryptoutil -lc
+
+SRCDIR= ../common
+INCDIR= ../../include
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -D_REENTRANT $(KMFINC) -I$(ROOT)/$(SFWDIR)/include \
+ -I$(INCDIR) -I/usr/include/libxml2
+
+PICS= $(OBJECTS:%=pics/%)
+SONAME= $(DYNLIB)
+
+lint:= OPENSSLLIBS= $(LINTSSLLIBS)
+lint:= OPENSSLLIBS64= $(LINTSSLLIBS64)
+
+LDLIBS32 += $(OPENSSLLIBS)
+
+ROOTLIBDIR= $(ROOT)/usr/lib/security
+ROOTLIBDIR64= $(ROOT)/usr/lib/security/$(MACH64)
+
+.KEEP_STATE:
+
+LIBS = $(DYNLIB)
+all: $(DYNLIB) $(LINTLIB)
+
+lint: lintcheck
+
+FRC:
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/amd64/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/amd64/Makefile
new file mode 100644
index 0000000000..d73321747a
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/amd64/Makefile
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include $(SRC)/lib/Makefile.lib.64
+
+LDLIBS += $(OPENSSLLIBS64)
+
+install: $(ROOTLIBS64)
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers b/usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers
new file mode 100644
index 0000000000..cd910effa4
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers
@@ -0,0 +1,61 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SUNWprivate_1.1 {
+ global:
+ KMF_Plugin_Initialize;
+ OpenSSL_CertGetPrintable;
+ OpenSSL_CheckCRLDate;
+ OpenSSL_CreateKeypair;
+ OpenSSL_CreateOCSPRequest;
+ OpenSSL_CreateSymKey;
+ OpenSSL_DecryptData;
+ OpenSSL_DeleteCRL;
+ OpenSSL_DeleteCert;
+ OpenSSL_DeleteKey;
+ OpenSSL_EncodePubKeyData;
+ OpenSSL_ExportP12;
+ OpenSSL_FindCert;
+ OpenSSL_FindCertInCRL;
+ OpenSSL_FindKey;
+ OpenSSL_FreeKMFCert;
+ OpenSSL_GetErrorString;
+ OpenSSL_GetOCSPStatusForCert;
+ OpenSSL_GetPrikeyByCert;
+ OpenSSL_GetSymKeyValue;
+ OpenSSL_ImportCRL;
+ OpenSSL_IsCRLFile;
+ OpenSSL_IsCertFile;
+ OpenSSL_ListCRL;
+ OpenSSL_SignData;
+ OpenSSL_StoreCert;
+ OpenSSL_StorePrivateKey;
+ OpenSSL_VerifyCRLFile;
+ openssl_read_pkcs12;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c b/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c
new file mode 100644
index 0000000000..e088341f01
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c
@@ -0,0 +1,4198 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * OpenSSL keystore wrapper
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <kmfapiP.h>
+#include <ber_der.h>
+#include <oidsalg.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <cryptoutil.h>
+#include <synch.h>
+#include <thread.h>
+
+/* OPENSSL related headers */
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/asn1.h>
+#include <openssl/err.h>
+#include <openssl/bn.h>
+#include <openssl/x509.h>
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <openssl/x509v3.h>
+#include <openssl/objects.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs12.h>
+#include <openssl/ocsp.h>
+#include <openssl/des.h>
+#include <openssl/rand.h>
+
+#define PRINT_ANY_EXTENSION (\
+ KMF_X509_EXT_KEY_USAGE |\
+ KMF_X509_EXT_CERT_POLICIES |\
+ KMF_X509_EXT_SUBJALTNAME |\
+ KMF_X509_EXT_BASIC_CONSTRAINTS |\
+ KMF_X509_EXT_NAME_CONSTRAINTS |\
+ KMF_X509_EXT_POLICY_CONSTRAINTS |\
+ KMF_X509_EXT_EXT_KEY_USAGE |\
+ KMF_X509_EXT_INHIBIT_ANY_POLICY |\
+ KMF_X509_EXT_AUTH_KEY_ID |\
+ KMF_X509_EXT_SUBJ_KEY_ID |\
+ KMF_X509_EXT_POLICY_MAPPING)
+
+static BIO *bio_err = NULL;
+static uchar_t P[] = { 0x00, 0x8d, 0xf2, 0xa4, 0x94, 0x49, 0x22, 0x76,
+ 0xaa, 0x3d, 0x25, 0x75, 0x9b, 0xb0, 0x68, 0x69,
+ 0xcb, 0xea, 0xc0, 0xd8, 0x3a, 0xfb, 0x8d, 0x0c,
+ 0xf7, 0xcb, 0xb8, 0x32, 0x4f, 0x0d, 0x78, 0x82,
+ 0xe5, 0xd0, 0x76, 0x2f, 0xc5, 0xb7, 0x21, 0x0e,
+ 0xaf, 0xc2, 0xe9, 0xad, 0xac, 0x32, 0xab, 0x7a,
+ 0xac, 0x49, 0x69, 0x3d, 0xfb, 0xf8, 0x37, 0x24,
+ 0xc2, 0xec, 0x07, 0x36, 0xee, 0x31, 0xc8, 0x02,
+ 0x91 };
+
+static uchar_t Q[] = { 0x00, 0xc7, 0x73, 0x21, 0x8c, 0x73, 0x7e, 0xc8,
+ 0xee, 0x99, 0x3b, 0x4f, 0x2d, 0xed, 0x30, 0xf4,
+ 0x8e, 0xda, 0xce, 0x91, 0x5f };
+
+static uchar_t G[] = { 0x00, 0x62, 0x6d, 0x02, 0x78, 0x39, 0xea, 0x0a,
+ 0x13, 0x41, 0x31, 0x63, 0xa5, 0x5b, 0x4c, 0xb5,
+ 0x00, 0x29, 0x9d, 0x55, 0x22, 0x95, 0x6c, 0xef,
+ 0xcb, 0x3b, 0xff, 0x10, 0xf3, 0x99, 0xce, 0x2c,
+ 0x2e, 0x71, 0xcb, 0x9d, 0xe5, 0xfa, 0x24, 0xba,
+ 0xbf, 0x58, 0xe5, 0xb7, 0x95, 0x21, 0x92, 0x5c,
+ 0x9c, 0xc4, 0x2e, 0x9f, 0x6f, 0x46, 0x4b, 0x08,
+ 0x8c, 0xc5, 0x72, 0xaf, 0x53, 0xe6, 0xd7, 0x88,
+ 0x02 };
+
+#define SET_ERROR(h, c) h->lasterr.kstype = KMF_KEYSTORE_OPENSSL; \
+ h->lasterr.errcode = c;
+
+#define SET_SYS_ERROR(h, c) h->lasterr.kstype = -1; h->lasterr.errcode = c;
+
+mutex_t init_lock = DEFAULTMUTEX;
+static int ssl_initialized = 0;
+
+KMF_RETURN
+OpenSSL_FindCert(KMF_HANDLE_T,
+ KMF_FINDCERT_PARAMS *,
+ KMF_X509_DER_CERT *,
+ uint32_t *);
+
+void
+OpenSSL_FreeKMFCert(KMF_HANDLE_T, KMF_X509_DER_CERT *);
+
+KMF_RETURN
+OpenSSL_StoreCert(KMF_HANDLE_T handle, KMF_STORECERT_PARAMS *, KMF_DATA *);
+
+KMF_RETURN
+OpenSSL_DeleteCert(KMF_HANDLE_T handle, KMF_DELETECERT_PARAMS *);
+
+KMF_RETURN
+OpenSSL_CreateKeypair(KMF_HANDLE_T, KMF_CREATEKEYPAIR_PARAMS *,
+ KMF_KEY_HANDLE *, KMF_KEY_HANDLE *);
+
+KMF_RETURN
+OpenSSL_EncodePubKeyData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_DATA *);
+
+KMF_RETURN
+OpenSSL_SignData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *,
+ KMF_DATA *, KMF_DATA *);
+
+KMF_RETURN
+OpenSSL_DeleteKey(KMF_HANDLE_T, KMF_DELETEKEY_PARAMS *,
+ KMF_KEY_HANDLE *, boolean_t);
+
+KMF_RETURN
+OpenSSL_ImportCRL(KMF_HANDLE_T, KMF_IMPORTCRL_PARAMS *);
+
+KMF_RETURN
+OpenSSL_DeleteCRL(KMF_HANDLE_T, KMF_DELETECRL_PARAMS *);
+
+KMF_RETURN
+OpenSSL_ListCRL(KMF_HANDLE_T, KMF_LISTCRL_PARAMS *, char **);
+
+KMF_RETURN
+OpenSSL_FindCertInCRL(KMF_HANDLE_T, KMF_FINDCERTINCRL_PARAMS *);
+
+KMF_RETURN
+OpenSSL_CertGetPrintable(KMF_HANDLE_T, const KMF_DATA *,
+ KMF_PRINTABLE_ITEM, char *);
+
+KMF_RETURN
+OpenSSL_GetErrorString(KMF_HANDLE_T, char **);
+
+KMF_RETURN
+OpenSSL_GetPrikeyByCert(KMF_HANDLE_T, KMF_CRYPTOWITHCERT_PARAMS *, KMF_DATA *,
+ KMF_KEY_HANDLE *, KMF_KEY_ALG);
+
+KMF_RETURN
+OpenSSL_DecryptData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *,
+ KMF_DATA *, KMF_DATA *);
+
+KMF_RETURN
+OpenSSL_CreateOCSPRequest(KMF_HANDLE_T, KMF_OCSPREQUEST_PARAMS *,
+ char *reqfile);
+
+KMF_RETURN
+OpenSSL_GetOCSPStatusForCert(KMF_HANDLE_T, KMF_OCSPRESPONSE_PARAMS_INPUT *,
+ KMF_OCSPRESPONSE_PARAMS_OUTPUT *);
+
+KMF_RETURN
+OpenSSL_FindKey(KMF_HANDLE_T, KMF_FINDKEY_PARAMS *,
+ KMF_KEY_HANDLE *, uint32_t *);
+
+KMF_RETURN
+OpenSSL_ExportP12(KMF_HANDLE_T,
+ KMF_EXPORTP12_PARAMS *,
+ int, KMF_X509_DER_CERT *,
+ int, KMF_KEY_HANDLE *,
+ char *);
+
+KMF_RETURN
+OpenSSL_StorePrivateKey(KMF_HANDLE_T, KMF_STOREKEY_PARAMS *,
+ KMF_RAW_KEY_DATA *);
+
+KMF_RETURN
+OpenSSL_CreateSymKey(KMF_HANDLE_T, KMF_CREATESYMKEY_PARAMS *,
+ KMF_KEY_HANDLE *);
+
+KMF_RETURN
+OpenSSL_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_SYM_KEY *);
+
+KMF_RETURN
+OpenSSL_VerifyCRLFile(KMF_HANDLE_T, KMF_VERIFYCRL_PARAMS *);
+
+KMF_RETURN
+OpenSSL_CheckCRLDate(KMF_HANDLE_T, KMF_CHECKCRLDATE_PARAMS *);
+
+static
+KMF_PLUGIN_FUNCLIST openssl_plugin_table =
+{
+ 1, /* Version */
+ NULL, /* ConfigureKeystore */
+ OpenSSL_FindCert,
+ OpenSSL_FreeKMFCert,
+ OpenSSL_StoreCert,
+ NULL, /* ImportCert */
+ OpenSSL_ImportCRL,
+ OpenSSL_DeleteCert,
+ OpenSSL_DeleteCRL,
+ OpenSSL_CreateKeypair,
+ OpenSSL_FindKey,
+ OpenSSL_EncodePubKeyData,
+ OpenSSL_SignData,
+ OpenSSL_DeleteKey,
+ OpenSSL_ListCRL,
+ NULL, /* FindCRL */
+ OpenSSL_FindCertInCRL,
+ OpenSSL_GetErrorString,
+ OpenSSL_GetPrikeyByCert,
+ OpenSSL_DecryptData,
+ OpenSSL_ExportP12,
+ OpenSSL_StorePrivateKey,
+ OpenSSL_CreateSymKey,
+ OpenSSL_GetSymKeyValue,
+ NULL, /* SetTokenPin */
+ NULL /* Finalize */
+};
+
+static mutex_t *lock_cs;
+static long *lock_count;
+
+static void
+/*ARGSUSED*/
+locking_cb(int mode, int type, char *file, int line)
+{
+ if (mode & CRYPTO_LOCK) {
+ (void) mutex_lock(&(lock_cs[type]));
+ lock_count[type]++;
+ } else {
+ (void) mutex_unlock(&(lock_cs[type]));
+ }
+}
+
+static unsigned long
+thread_id()
+{
+ return ((unsigned long)thr_self());
+}
+
+KMF_PLUGIN_FUNCLIST *
+KMF_Plugin_Initialize()
+{
+ int i;
+
+ (void) mutex_lock(&init_lock);
+ if (!ssl_initialized) {
+ OpenSSL_add_all_algorithms();
+
+ /* Enable error strings for reporting */
+ ERR_load_crypto_strings();
+
+ /*
+ * Add support for extension OIDs that are not yet in the
+ * openssl default set.
+ */
+ (void) OBJ_create("2.5.29.30", "nameConstraints",
+ "X509v3 Name Constraints");
+ (void) OBJ_create("2.5.29.33", "policyMappings",
+ "X509v3 Policy Mappings");
+ (void) OBJ_create("2.5.29.36", "policyConstraints",
+ "X509v3 Policy Constraints");
+ (void) OBJ_create("2.5.29.46", "freshestCRL",
+ "X509v3 Freshest CRL");
+ (void) OBJ_create("2.5.29.54", "inhibitAnyPolicy",
+ "X509v3 Inhibit Any-Policy");
+ /*
+ * Set up for thread-safe operation.
+ */
+ lock_cs = OPENSSL_malloc(CRYPTO_num_locks() * sizeof (mutex_t));
+ if (lock_cs == NULL) {
+ (void) mutex_unlock(&init_lock);
+ return (NULL);
+ }
+
+ lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof (long));
+ if (lock_count == NULL) {
+ OPENSSL_free(lock_cs);
+ (void) mutex_unlock(&init_lock);
+ return (NULL);
+ }
+
+ for (i = 0; i < CRYPTO_num_locks(); i++) {
+ lock_count[i] = 0;
+ (void) mutex_init(&lock_cs[i], USYNC_THREAD, NULL);
+ }
+
+ CRYPTO_set_id_callback((unsigned long (*)())thread_id);
+ CRYPTO_set_locking_callback((void (*)())locking_cb);
+ ssl_initialized = 1;
+ }
+ (void) mutex_unlock(&init_lock);
+
+ return (&openssl_plugin_table);
+}
+/*
+ * Convert an SSL DN to a KMF DN.
+ */
+static KMF_RETURN
+get_x509_dn(X509_NAME *sslDN, KMF_X509_NAME *kmfDN)
+{
+ KMF_DATA derdata;
+ KMF_RETURN rv = KMF_OK;
+ uchar_t *tmp;
+
+ /* Convert to raw DER format */
+ derdata.Length = i2d_X509_NAME(sslDN, NULL);
+ if ((tmp = derdata.Data = (uchar_t *)OPENSSL_malloc(derdata.Length))
+ == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+ (void) i2d_X509_NAME(sslDN, &tmp);
+
+ /* Decode to KMF format */
+ rv = DerDecodeName(&derdata, kmfDN);
+ if (rv != KMF_OK) {
+ rv = KMF_ERR_BAD_CERT_FORMAT;
+ }
+ OPENSSL_free(derdata.Data);
+
+ return (rv);
+}
+
+static int
+isdir(char *path)
+{
+ struct stat s;
+
+ if (stat(path, &s) == -1)
+ return (0);
+
+ return (s.st_mode & S_IFDIR);
+}
+
+static KMF_RETURN
+ssl_cert2KMFDATA(KMF_HANDLE *kmfh, X509 *x509cert, KMF_DATA *cert)
+{
+ KMF_RETURN rv = KMF_OK;
+ unsigned char *buf = NULL, *p;
+ int len;
+
+ /*
+ * Convert the X509 internal struct to DER encoded data
+ */
+ if ((len = i2d_X509(x509cert, NULL)) < 0) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+ if ((buf = malloc(len)) == NULL) {
+ SET_SYS_ERROR(kmfh, errno);
+ rv = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * i2d_X509 will increment the buf pointer so that we need to
+ * save it.
+ */
+ p = buf;
+ if ((len = i2d_X509(x509cert, &p)) < 0) {
+ SET_ERROR(kmfh, ERR_get_error());
+ free(buf);
+ rv = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ /* caller's responsibility to free it */
+ cert->Data = buf;
+ cert->Length = len;
+
+cleanup:
+ if (rv != KMF_OK) {
+ if (buf)
+ free(buf);
+ cert->Data = NULL;
+ cert->Length = 0;
+ }
+
+ return (rv);
+}
+
+static KMF_RETURN
+check_cert(X509 *xcert, KMF_FINDCERT_PARAMS *params, boolean_t *match)
+{
+ KMF_RETURN rv = KMF_OK;
+ boolean_t findIssuer = FALSE;
+ boolean_t findSubject = FALSE;
+ boolean_t findSerial = FALSE;
+ KMF_X509_NAME issuerDN, subjectDN;
+ KMF_X509_NAME certIssuerDN, certSubjectDN;
+
+ *match = FALSE;
+ if (xcert == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ (void) memset(&issuerDN, 0, sizeof (KMF_X509_NAME));
+ (void) memset(&subjectDN, 0, sizeof (KMF_X509_NAME));
+ (void) memset(&certIssuerDN, 0, sizeof (KMF_X509_NAME));
+ (void) memset(&certSubjectDN, 0, sizeof (KMF_X509_NAME));
+
+ if (params->issuer != NULL && strlen(params->issuer)) {
+ rv = KMF_DNParser(params->issuer, &issuerDN);
+ if (rv != KMF_OK)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = get_x509_dn(xcert->cert_info->issuer, &certIssuerDN);
+ if (rv != KMF_OK) {
+ KMF_FreeDN(&issuerDN);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ findIssuer = TRUE;
+ }
+ if (params->subject != NULL && strlen(params->subject)) {
+ rv = KMF_DNParser(params->subject, &subjectDN);
+ if (rv != KMF_OK) {
+ rv = KMF_ERR_BAD_PARAMETER;
+ goto cleanup;
+ }
+
+ rv = get_x509_dn(xcert->cert_info->subject, &certSubjectDN);
+ if (rv != KMF_OK) {
+ rv = KMF_ERR_BAD_PARAMETER;
+ goto cleanup;
+ }
+ findSubject = TRUE;
+ }
+ if (params->serial != NULL && params->serial->val != NULL)
+ findSerial = TRUE;
+
+ if (findSerial) {
+ BIGNUM *bn;
+
+ /* Comparing BIGNUMs is a pain! */
+ bn = ASN1_INTEGER_to_BN(xcert->cert_info->serialNumber, NULL);
+ if (bn != NULL) {
+ int bnlen = BN_num_bytes(bn);
+
+ if (bnlen == params->serial->len) {
+ uchar_t *a = malloc(bnlen);
+ if (a == NULL) {
+ rv = KMF_ERR_MEMORY;
+ BN_free(bn);
+ goto cleanup;
+ }
+ bnlen = BN_bn2bin(bn, a);
+ *match = !memcmp(a,
+ params->serial->val,
+ params->serial->len);
+ rv = KMF_OK;
+ free(a);
+ }
+ BN_free(bn);
+ if (!(*match))
+ goto cleanup;
+ } else {
+ rv = KMF_OK;
+ goto cleanup;
+ }
+ }
+ if (findIssuer) {
+ *match = !KMF_CompareRDNs(&issuerDN, &certIssuerDN);
+ if (!(*match)) {
+ rv = KMF_OK;
+ goto cleanup;
+ }
+ }
+ if (findSubject) {
+ *match = !KMF_CompareRDNs(&subjectDN, &certSubjectDN);
+ if (!(*match)) {
+ rv = KMF_OK;
+ goto cleanup;
+ }
+ }
+
+ *match = TRUE;
+cleanup:
+ if (findIssuer) {
+ KMF_FreeDN(&issuerDN);
+ KMF_FreeDN(&certIssuerDN);
+ }
+ if (findSubject) {
+ KMF_FreeDN(&subjectDN);
+ KMF_FreeDN(&certSubjectDN);
+ }
+
+ return (rv);
+}
+
+static KMF_RETURN
+load_X509cert(KMF_HANDLE *kmfh,
+ KMF_FINDCERT_PARAMS *params,
+ char *pathname,
+ X509 **outcert)
+{
+ KMF_RETURN rv = KMF_OK;
+ X509 *xcert = NULL;
+ BIO *bcert = NULL;
+ boolean_t match = FALSE;
+ KMF_ENCODE_FORMAT format;
+
+ /*
+ * auto-detect the file format, regardless of what
+ * the 'format' parameters in the params say.
+ */
+ rv = KMF_GetFileFormat(pathname, &format);
+ if (rv != KMF_OK) {
+ if (rv == KMF_ERR_OPEN_FILE)
+ rv = KMF_ERR_CERT_NOT_FOUND;
+ return (rv);
+ }
+
+ /* Not ASN1(DER) format */
+ if ((bcert = BIO_new_file(pathname, "rb")) == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_OPEN_FILE;
+ goto cleanup;
+ }
+
+ if (format == KMF_FORMAT_PEM)
+ xcert = PEM_read_bio_X509_AUX(bcert, NULL, NULL, NULL);
+ else if (format == KMF_FORMAT_ASN1)
+ xcert = d2i_X509_bio(bcert, NULL);
+ else if (format == KMF_FORMAT_PKCS12) {
+ PKCS12 *p12 = d2i_PKCS12_bio(bcert, NULL);
+ if (p12 != NULL) {
+ (void) PKCS12_parse(p12, NULL, NULL, &xcert, NULL);
+ PKCS12_free(p12);
+ p12 = NULL;
+ } else {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_BAD_CERT_FORMAT;
+ }
+ } else {
+ rv = KMF_ERR_BAD_PARAMETER;
+ goto cleanup;
+ }
+
+ if (xcert == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ if (check_cert(xcert, params, &match) != KMF_OK || match == FALSE) {
+ rv = KMF_ERR_CERT_NOT_FOUND;
+ goto cleanup;
+ }
+
+ if (outcert != NULL) {
+ *outcert = xcert;
+ }
+
+cleanup:
+ if (bcert != NULL) (void) BIO_free(bcert);
+ if (rv != KMF_OK && xcert != NULL)
+ X509_free(xcert);
+
+ return (rv);
+}
+
+static KMF_RETURN
+kmf_load_cert(KMF_HANDLE *kmfh,
+ KMF_FINDCERT_PARAMS *params,
+ char *pathname,
+ KMF_DATA *cert)
+{
+ KMF_RETURN rv = KMF_OK;
+ X509 *x509cert = NULL;
+
+ rv = load_X509cert(kmfh, params, pathname, &x509cert);
+ if (rv == KMF_OK && x509cert != NULL && cert != NULL) {
+ rv = ssl_cert2KMFDATA(kmfh, x509cert, cert);
+ if (rv != KMF_OK) {
+ goto cleanup;
+ }
+ if (params->find_cert_validity == KMF_NONEXPIRED_CERTS) {
+ rv = KMF_CheckCertDate(kmfh, cert);
+ } else if (params->find_cert_validity == KMF_EXPIRED_CERTS) {
+ rv = KMF_CheckCertDate(kmfh, cert);
+ if (rv == KMF_OK) {
+ /*
+ * This is a valid cert so skip it.
+ */
+ rv = KMF_ERR_CERT_NOT_FOUND;
+ }
+ if (rv == KMF_ERR_VALIDITY_PERIOD) {
+ /*
+ * We want to return success when we
+ * find an invalid cert.
+ */
+ rv = KMF_OK;
+ goto cleanup;
+ }
+ }
+ }
+cleanup:
+ if (x509cert != NULL)
+ X509_free(x509cert);
+
+ return (rv);
+}
+
+static EVP_PKEY *
+openssl_load_key(KMF_HANDLE_T handle, const char *file)
+{
+ BIO *keyfile = NULL;
+ EVP_PKEY *pkey = NULL;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_ENCODE_FORMAT format;
+
+ if (file == NULL) {
+ return (NULL);
+ }
+
+ if (KMF_GetFileFormat((char *)file, &format) != KMF_OK)
+ return (NULL);
+
+ keyfile = BIO_new_file(file, "rb");
+ if (keyfile == NULL) {
+ goto end;
+ }
+
+ if (format == KMF_FORMAT_ASN1)
+ pkey = d2i_PrivateKey_bio(keyfile, NULL);
+ else if (format == KMF_FORMAT_PEM)
+ pkey = PEM_read_bio_PrivateKey(keyfile, NULL, NULL, NULL);
+
+end:
+ if (pkey == NULL)
+ SET_ERROR(kmfh, ERR_get_error());
+
+ if (keyfile != NULL)
+ (void) BIO_free(keyfile);
+
+ return (pkey);
+}
+
+KMF_RETURN
+OpenSSL_FindCert(KMF_HANDLE_T handle,
+ KMF_FINDCERT_PARAMS *params,
+ KMF_X509_DER_CERT *kmf_cert,
+ uint32_t *num_certs)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_DATA certdata = {NULL, 0};
+ char *fullpath;
+
+ if (num_certs == NULL || params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ *num_certs = 0;
+
+ fullpath = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.certfile);
+
+ if (fullpath == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (isdir(fullpath)) {
+ DIR *dirp;
+ struct dirent *dp;
+ int n = 0;
+
+ /* open all files in the directory and attempt to read them */
+ if ((dirp = opendir(fullpath)) == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+ while ((dp = readdir(dirp)) != NULL) {
+ char *fname;
+ if (strcmp(dp->d_name, ".") == 0 ||
+ strcmp(dp->d_name, "..") == 0)
+ continue;
+
+ fname = get_fullpath(fullpath,
+ (char *)&dp->d_name);
+
+ rv = kmf_load_cert(kmfh, params, fname,
+ &certdata);
+
+ if (rv != KMF_OK) {
+ free(fname);
+ KMF_FreeData(&certdata);
+ continue;
+ }
+
+ /* If load succeeds, add certdata to the list */
+ if (kmf_cert != NULL) {
+ kmf_cert[n].certificate.Data = certdata.Data;
+ kmf_cert[n].certificate.Length =
+ certdata.Length;
+
+ kmf_cert[n].kmf_private.keystore_type =
+ KMF_KEYSTORE_OPENSSL;
+ kmf_cert[n].kmf_private.flags =
+ KMF_FLAG_CERT_VALID;
+ kmf_cert[n].kmf_private.label = fname;
+ } else {
+ free(fname);
+ KMF_FreeData(&certdata);
+ }
+ n++;
+ }
+ (*num_certs) = n;
+ if (*num_certs == 0)
+ rv = KMF_ERR_CERT_NOT_FOUND;
+ if (*num_certs > 0)
+ rv = KMF_OK;
+exit:
+ (void) closedir(dirp);
+ } else {
+ /* Just try to load a single certificate */
+ rv = kmf_load_cert(kmfh, params, fullpath, &certdata);
+ if (rv != KMF_OK) {
+ free(fullpath);
+ KMF_FreeData(&certdata);
+ return (rv);
+ }
+
+ if (kmf_cert != NULL) {
+ kmf_cert->certificate.Data = certdata.Data;
+ kmf_cert->certificate.Length = certdata.Length;
+ kmf_cert->kmf_private.keystore_type =
+ KMF_KEYSTORE_OPENSSL;
+ kmf_cert->kmf_private.flags = KMF_FLAG_CERT_VALID;
+ kmf_cert->kmf_private.label = fullpath;
+ } else {
+ KMF_FreeData(&certdata);
+ }
+
+ *num_certs = 1;
+ }
+
+ if (kmf_cert == NULL || rv != KMF_OK)
+ free(fullpath);
+
+ return (rv);
+
+}
+
+void
+/*ARGSUSED*/
+OpenSSL_FreeKMFCert(KMF_HANDLE_T handle,
+ KMF_X509_DER_CERT *kmf_cert)
+{
+ if (kmf_cert != NULL) {
+ if (kmf_cert->certificate.Data != NULL) {
+ free(kmf_cert->certificate.Data);
+ kmf_cert->certificate.Data = NULL;
+ kmf_cert->certificate.Length = 0;
+ }
+ if (kmf_cert->kmf_private.label)
+ free(kmf_cert->kmf_private.label);
+ }
+}
+
+KMF_RETURN
+OpenSSL_StoreCert(KMF_HANDLE_T handle, KMF_STORECERT_PARAMS *params,
+ KMF_DATA * pcert)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ X509 *xcert = NULL;
+ FILE *fp;
+ unsigned char *outbuf;
+ unsigned char *outbuf_p;
+ char *fullpath;
+ int outbuflen;
+ int len;
+ KMF_ENCODE_FORMAT format;
+
+ if (params == NULL || params->ks_opt_u.openssl_opts.certfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /*
+ * check if the cert output format is supported by OPENSSL.
+ * however, since the keystore for OPENSSL is just a file, we have
+ * no way to store the format along with the file.
+ */
+ format = params->sslparms.format;
+ if (format != KMF_FORMAT_ASN1 && format != KMF_FORMAT_PEM)
+ return (KMF_ERR_BAD_CERT_FORMAT);
+
+
+ fullpath = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.certfile);
+ if (fullpath == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * When storing a certificate, you must specify a filename.
+ */
+ if (isdir(fullpath)) {
+ free(fullpath);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /* copy cert data to outbuf */
+ outbuflen = pcert->Length;
+ outbuf = malloc(outbuflen);
+ if (outbuf == NULL) {
+ free(fullpath);
+ return (KMF_ERR_MEMORY);
+ }
+ (void) memcpy(outbuf, pcert->Data, pcert->Length);
+
+ if ((fp = fopen(fullpath, "w")) ==
+ NULL) {
+ SET_SYS_ERROR(kmfh, errno);
+ ret = KMF_ERR_INTERNAL;
+ goto out;
+ }
+
+ if (format == KMF_FORMAT_ASN1) {
+ len = fwrite(outbuf, 1, outbuflen, fp);
+ if (len != outbuflen) {
+ SET_SYS_ERROR(kmfh, errno);
+ ret = KMF_ERR_WRITE_FILE;
+ } else {
+ ret = KMF_OK;
+ }
+ goto out;
+ }
+
+ /*
+ * The output format is not KMF_FORMAT_ASN1, so we will
+ * Convert the cert data to OpenSSL internal X509 first.
+ */
+ outbuf_p = outbuf; /* use a temp pointer; required by openssl */
+ xcert = d2i_X509(NULL, (const uchar_t **)&outbuf_p, outbuflen);
+ if (xcert == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+
+ if (format == KMF_FORMAT_PEM) {
+ /* Convert to the PEM format and write it out */
+ if (!PEM_write_X509(fp, xcert)) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_ENCODING;
+ } else {
+ ret = KMF_OK;
+ }
+ goto out;
+ }
+
+out:
+ if (fullpath != NULL)
+ free(fullpath);
+
+ if (outbuf != NULL) {
+ free(outbuf);
+ }
+ if (fp != NULL) {
+ (void) fclose(fp);
+ }
+
+ if (xcert != NULL) {
+ X509_free(xcert);
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+OpenSSL_DeleteCert(KMF_HANDLE_T handle, KMF_DELETECERT_PARAMS *params)
+{
+ KMF_RETURN rv;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ char *fullpath = NULL;
+ KMF_DATA certdata = {NULL, 0};
+
+ if (params == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ fullpath = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.certfile);
+
+ if (fullpath == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (isdir(fullpath)) {
+ DIR *dirp;
+ struct dirent *dp;
+
+ /* open all files in the directory and attempt to read them */
+ if ((dirp = opendir(fullpath)) == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ while ((dp = readdir(dirp)) != NULL) {
+ if (strcmp(dp->d_name, ".") != 0 &&
+ strcmp(dp->d_name, "..") != 0) {
+ char *fname;
+
+ fname = get_fullpath(fullpath,
+ (char *)&dp->d_name);
+
+ if (fname == NULL) {
+ rv = KMF_ERR_MEMORY;
+ break;
+ }
+
+ rv = kmf_load_cert(kmfh, params, fname,
+ &certdata);
+
+ if (rv == KMF_ERR_CERT_NOT_FOUND) {
+ free(fname);
+ if (certdata.Data)
+ free(certdata.Data);
+ rv = KMF_OK;
+ continue;
+ } else if (rv != KMF_OK) {
+ free(fname);
+ break;
+ }
+
+ if (unlink(fname) != 0) {
+ SET_SYS_ERROR(kmfh, errno);
+ rv = KMF_ERR_INTERNAL;
+ free(fname);
+ break;
+ }
+ free(fname);
+ if (certdata.Data)
+ free(certdata.Data);
+ }
+ }
+ (void) closedir(dirp);
+ } else {
+ /* Just try to load a single certificate */
+ rv = kmf_load_cert(kmfh, params, fullpath, &certdata);
+ if (rv == KMF_OK) {
+ if (unlink(fullpath) != 0) {
+ SET_SYS_ERROR(kmfh, errno);
+ rv = KMF_ERR_INTERNAL;
+ }
+ }
+ }
+
+out:
+ if (fullpath != NULL)
+ free(fullpath);
+
+ if (certdata.Data)
+ free(certdata.Data);
+
+ return (rv);
+}
+
+KMF_RETURN
+OpenSSL_EncodePubKeyData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key,
+ KMF_DATA *keydata)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ int n;
+
+ if (key == NULL || keydata == NULL ||
+ key->keyp == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (key->keyalg == KMF_RSA) {
+ RSA *pubkey = EVP_PKEY_get1_RSA(key->keyp);
+
+ if (!(n = i2d_RSA_PUBKEY(pubkey, &keydata->Data))) {
+ SET_ERROR(kmfh, ERR_get_error());
+ return (KMF_ERR_ENCODING);
+ }
+ RSA_free(pubkey);
+ } else if (key->keyalg == KMF_DSA) {
+ DSA *pubkey = EVP_PKEY_get1_DSA(key->keyp);
+
+ if (!(n = i2d_DSA_PUBKEY(pubkey, &keydata->Data))) {
+ SET_ERROR(kmfh, ERR_get_error());
+ return (KMF_ERR_ENCODING);
+ }
+ DSA_free(pubkey);
+ } else {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+ keydata->Length = n;
+
+cleanup:
+ if (rv != KMF_OK) {
+ if (keydata->Data)
+ free(keydata->Data);
+ keydata->Data = NULL;
+ keydata->Length = 0;
+ }
+
+ return (rv);
+}
+
+static KMF_RETURN
+ssl_write_private_key(KMF_HANDLE *kmfh, KMF_ENCODE_FORMAT format, BIO *out,
+ KMF_CREDENTIAL *cred, EVP_PKEY *pkey)
+{
+ int rv = 0;
+ RSA *rsa;
+ DSA *dsa;
+
+ switch (format) {
+ case KMF_FORMAT_ASN1:
+ if (pkey->type == EVP_PKEY_RSA) {
+ rsa = EVP_PKEY_get1_RSA(pkey);
+ rv = i2d_RSAPrivateKey_bio(out, rsa);
+ RSA_free(rsa);
+ } else if (pkey->type == EVP_PKEY_DSA) {
+ dsa = EVP_PKEY_get1_DSA(pkey);
+ rv = i2d_DSAPrivateKey_bio(out, dsa);
+ DSA_free(dsa);
+ }
+ if (rv == 1) {
+ rv = KMF_OK;
+ } else {
+ SET_ERROR(kmfh, rv);
+ }
+ break;
+ case KMF_FORMAT_PEM:
+ if (pkey->type == EVP_PKEY_RSA) {
+ rsa = EVP_PKEY_get1_RSA(pkey);
+ rv = PEM_write_bio_RSAPrivateKey(out,
+ rsa,
+ NULL /* encryption type */,
+ NULL, 0, NULL,
+ cred->cred);
+ RSA_free(rsa);
+ } else if (pkey->type == EVP_PKEY_DSA) {
+ dsa = EVP_PKEY_get1_DSA(pkey);
+ rv = PEM_write_bio_DSAPrivateKey(out,
+ dsa,
+ NULL /* encryption type */,
+ NULL, 0, NULL,
+ cred->cred);
+ DSA_free(dsa);
+ }
+
+ if (rv == 1) {
+ rv = KMF_OK;
+ } else {
+ SET_ERROR(kmfh, rv);
+ }
+ break;
+
+ default:
+ rv = KMF_ERR_BAD_PARAMETER;
+ }
+
+ return (rv);
+}
+
+KMF_RETURN
+OpenSSL_CreateKeypair(KMF_HANDLE_T handle, KMF_CREATEKEYPAIR_PARAMS *params,
+ KMF_KEY_HANDLE *privkey, KMF_KEY_HANDLE *pubkey)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ int format;
+ uint32_t eValue = 0x010001;
+ RSA *sslPrivKey = NULL;
+ DSA *sslDSAKey = NULL;
+ EVP_PKEY *eprikey = NULL;
+ EVP_PKEY *epubkey = NULL;
+ BIO *out = NULL;
+ char *fullpath = NULL;
+
+ if (params == NULL || params->sslparms.keyfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ fullpath = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.keyfile);
+
+ if (fullpath == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* If the requested file exists, return an error */
+ if (access(fullpath, F_OK) == 0) {
+ free(fullpath);
+ return (KMF_ERR_DUPLICATE_KEYFILE);
+ }
+
+ eprikey = EVP_PKEY_new();
+ if (eprikey == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto cleanup;
+ }
+ epubkey = EVP_PKEY_new();
+ if (epubkey == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto cleanup;
+ }
+ if (params->keytype == KMF_RSA) {
+ if (params->rsa_exponent.len > 0 &&
+ params->rsa_exponent.len <= sizeof (eValue) &&
+ params->rsa_exponent.val != NULL)
+ /*LINTED*/
+ eValue = *(uint32_t *)params->rsa_exponent.val;
+
+ sslPrivKey = RSA_generate_key(params->keylength, eValue,
+ NULL, NULL);
+ if (sslPrivKey == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ } else {
+ if (privkey != NULL &&
+ EVP_PKEY_set1_RSA(eprikey, sslPrivKey)) {
+ privkey->kstype = KMF_KEYSTORE_OPENSSL;
+ privkey->keyalg = KMF_RSA;
+ privkey->keyclass = KMF_ASYM_PRI;
+ privkey->israw = FALSE;
+ privkey->keylabel = (char *)strdup(fullpath);
+ privkey->keyp = (void *)eprikey;
+ }
+ /* OpenSSL derives the public key from the private */
+ if (pubkey != NULL &&
+ EVP_PKEY_set1_RSA(epubkey, sslPrivKey)) {
+ pubkey->kstype = KMF_KEYSTORE_OPENSSL;
+ pubkey->keyalg = KMF_RSA;
+ pubkey->israw = FALSE;
+ pubkey->keyclass = KMF_ASYM_PUB;
+ pubkey->keylabel = (char *)strdup(fullpath);
+ pubkey->keyp = (void *)epubkey;
+ }
+ }
+ } else if (params->keytype == KMF_DSA) {
+ sslDSAKey = DSA_new();
+ if (sslDSAKey == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ return (KMF_ERR_MEMORY);
+ }
+
+ if ((sslDSAKey->p = BN_bin2bn(P, sizeof (P), sslDSAKey->p)) ==
+ NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto cleanup;
+ }
+ if ((sslDSAKey->q = BN_bin2bn(Q, sizeof (Q), sslDSAKey->q)) ==
+ NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto cleanup;
+ }
+ if ((sslDSAKey->g = BN_bin2bn(G, sizeof (G), sslDSAKey->g)) ==
+ NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto cleanup;
+ }
+
+ if (!DSA_generate_key(sslDSAKey)) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto cleanup;
+ }
+
+ if (privkey != NULL) {
+ privkey->kstype = KMF_KEYSTORE_OPENSSL;
+ privkey->keyalg = KMF_DSA;
+ privkey->keyclass = KMF_ASYM_PRI;
+ privkey->israw = FALSE;
+ privkey->keylabel = (char *)strdup(fullpath);
+ if (EVP_PKEY_set1_DSA(eprikey, sslDSAKey)) {
+ privkey->keyp = (void *)eprikey;
+ } else {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto cleanup;
+ }
+ }
+ if (pubkey != NULL) {
+ DSA *dp = DSA_new();
+ /* Make a copy for the public key */
+ if (dp != NULL) {
+ if ((dp->p = BN_new()) == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_MEMORY;
+ DSA_free(dp);
+ goto cleanup;
+ }
+ if ((dp->q = BN_new()) == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_MEMORY;
+ BN_free(dp->p);
+ DSA_free(dp);
+ goto cleanup;
+ }
+ if ((dp->g = BN_new()) == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_MEMORY;
+ BN_free(dp->q);
+ BN_free(dp->p);
+ DSA_free(dp);
+ goto cleanup;
+ }
+ if ((dp->pub_key = BN_new()) == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_MEMORY;
+ BN_free(dp->q);
+ BN_free(dp->p);
+ BN_free(dp->g);
+ DSA_free(dp);
+ goto cleanup;
+ }
+ (void) BN_copy(dp->p, sslDSAKey->p);
+ (void) BN_copy(dp->q, sslDSAKey->q);
+ (void) BN_copy(dp->g, sslDSAKey->g);
+ (void) BN_copy(dp->pub_key, sslDSAKey->pub_key);
+
+ pubkey->kstype = KMF_KEYSTORE_OPENSSL;
+ pubkey->keyalg = KMF_DSA;
+ pubkey->keyclass = KMF_ASYM_PUB;
+ pubkey->israw = FALSE;
+ pubkey->keylabel = (char *)strdup(fullpath);
+
+ if (EVP_PKEY_set1_DSA(epubkey, sslDSAKey)) {
+ pubkey->keyp = (void *)epubkey;
+ } else {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto cleanup;
+ }
+ }
+ }
+ }
+
+ if (rv != KMF_OK) {
+ goto cleanup;
+ }
+
+ /* Store the private key to the keyfile */
+ format = params->sslparms.format;
+ out = BIO_new_file(fullpath, "wb");
+ if (out == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_OPEN_FILE;
+ goto cleanup;
+ }
+ rv = ssl_write_private_key(kmfh, format, out, &params->cred, eprikey);
+
+cleanup:
+ if (rv != KMF_OK) {
+ if (eprikey != NULL)
+ EVP_PKEY_free(eprikey);
+
+ if (epubkey != NULL)
+ EVP_PKEY_free(epubkey);
+
+ if (pubkey->keylabel) {
+ free(pubkey->keylabel);
+ pubkey->keylabel = NULL;
+ }
+
+ if (privkey->keylabel) {
+ free(privkey->keylabel);
+ privkey->keylabel = NULL;
+ }
+
+ pubkey->keyp = NULL;
+ privkey->keyp = NULL;
+ }
+
+ if (sslPrivKey)
+ RSA_free(sslPrivKey);
+
+ if (sslDSAKey)
+ DSA_free(sslDSAKey);
+
+
+ if (out != NULL)
+ (void) BIO_free(out);
+
+ if (fullpath)
+ free(fullpath);
+
+ /* Protect the file by making it read-only */
+ if (rv == KMF_OK) {
+ (void) chmod(fullpath, 0400);
+ }
+ return (rv);
+}
+
+KMF_RETURN
+OpenSSL_SignData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key,
+ KMF_OID *AlgOID, KMF_DATA *tobesigned, KMF_DATA *output)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_ALGORITHM_INDEX AlgId;
+ EVP_MD_CTX ctx;
+ const EVP_MD *md;
+ if (key == NULL || AlgOID == NULL ||
+ tobesigned == NULL || output == NULL ||
+ tobesigned->Data == NULL ||
+ output->Data == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* Map the OID to an OpenSSL algorithm */
+ AlgId = X509_AlgorithmOidToAlgId(AlgOID);
+ if (AlgId == KMF_ALGID_NONE)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (key->keyalg == KMF_RSA) {
+ EVP_PKEY *pkey = (EVP_PKEY *)key->keyp;
+ uchar_t *p;
+ uint32_t len;
+ if (AlgId == KMF_ALGID_MD5WithRSA)
+ md = EVP_md5();
+ else if (AlgId == KMF_ALGID_MD2WithRSA)
+ md = EVP_md2();
+ else if (AlgId == KMF_ALGID_SHA1WithRSA)
+ md = EVP_sha1();
+ else
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (md == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ return (KMF_ERR_MEMORY);
+ }
+
+ (void) EVP_MD_CTX_init(&ctx);
+ (void) EVP_SignInit_ex(&ctx, md, NULL);
+ (void) EVP_SignUpdate(&ctx, tobesigned->Data,
+ (uint32_t)tobesigned->Length);
+ len = (uint32_t)output->Length;
+ p = output->Data;
+ if (!EVP_SignFinal(&ctx, p, &len, pkey)) {
+ SET_ERROR(kmfh, ERR_get_error());
+ output->Length = 0;
+ }
+ output->Length = len;
+ (void) EVP_MD_CTX_cleanup(&ctx);
+ } else if (key->keyalg == KMF_DSA) {
+ DSA *dsa = EVP_PKEY_get1_DSA(key->keyp);
+
+ uchar_t hash[EVP_MAX_MD_SIZE];
+ uint32_t hashlen;
+ DSA_SIG *dsasig;
+
+ /*
+ * OpenSSL EVP_Sign operation automatically converts to
+ * ASN.1 output so we do the operations separately so we
+ * are assured of NOT getting ASN.1 output returned.
+ * KMF does not want ASN.1 encoded results because
+ * not all mechanisms return ASN.1 encodings (PKCS#11
+ * and NSS return raw signature data).
+ */
+ md = EVP_sha1();
+ EVP_MD_CTX_init(&ctx);
+ (void) EVP_DigestInit_ex(&ctx, md, NULL);
+ (void) EVP_DigestUpdate(&ctx, tobesigned->Data,
+ tobesigned->Length);
+ (void) EVP_DigestFinal_ex(&ctx, hash, &hashlen);
+ (void) EVP_MD_CTX_cleanup(&ctx);
+
+ dsasig = DSA_do_sign(hash, hashlen, dsa);
+ if (dsasig != NULL) {
+ int i;
+ output->Length = i = BN_bn2bin(dsasig->r, output->Data);
+ output->Length += BN_bn2bin(dsasig->s,
+ &output->Data[i]);
+ DSA_SIG_free(dsasig);
+ } else {
+ SET_ERROR(kmfh, ERR_get_error());
+ }
+ } else {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+cleanup:
+ return (ret);
+}
+
+KMF_RETURN
+/*ARGSUSED*/
+OpenSSL_DeleteKey(KMF_HANDLE_T handle, KMF_DELETEKEY_PARAMS *params,
+ KMF_KEY_HANDLE *key, boolean_t destroy)
+{
+ KMF_RETURN rv = KMF_OK;
+ if (key == NULL || key->keyp == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (key->keyclass != KMF_ASYM_PUB &&
+ key->keyclass != KMF_ASYM_PRI &&
+ key->keyclass != KMF_SYMMETRIC)
+ return (KMF_ERR_BAD_KEY_CLASS);
+
+ if (key->keyclass == KMF_SYMMETRIC) {
+ KMF_FreeRawSymKey((KMF_RAW_SYM_KEY *)key->keyp);
+ key->keyp = NULL;
+ } else {
+ if (key->keyp != NULL) {
+ EVP_PKEY_free(key->keyp);
+ key->keyp = NULL;
+ }
+ }
+
+ if (key->keylabel != NULL) {
+ EVP_PKEY *pkey = NULL;
+ /* If the file exists, make sure it is a proper key. */
+ pkey = openssl_load_key(handle, key->keylabel);
+ if (pkey == NULL) {
+ free(key->keylabel);
+ key->keylabel = NULL;
+ return (KMF_ERR_KEY_NOT_FOUND);
+ }
+ EVP_PKEY_free(pkey);
+
+ if (destroy) {
+ if (unlink(key->keylabel) != 0) {
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ SET_SYS_ERROR(kmfh, errno);
+ rv = KMF_ERR_INTERNAL;
+ }
+ }
+ if (key->keylabel != NULL) {
+ free(key->keylabel);
+ key->keylabel = NULL;
+ }
+ }
+ return (rv);
+}
+
+KMF_RETURN
+OpenSSL_ImportCRL(KMF_HANDLE_T handle, KMF_IMPORTCRL_PARAMS *params)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ X509_CRL *xcrl = NULL;
+ X509 *xcert = NULL;
+ EVP_PKEY *pkey;
+ KMF_ENCODE_FORMAT format;
+ BIO *in = NULL, *out = NULL;
+ int openssl_ret = 0;
+ char *outcrlfile = NULL;
+ KMF_ENCODE_FORMAT outformat;
+
+ if (params == NULL || params->sslparms.crlfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ if (params->sslparms.crl_check == B_TRUE &&
+ params->sslparms.certfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ outcrlfile = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.outcrlfile);
+
+ if (outcrlfile == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (isdir(outcrlfile)) {
+ free(outcrlfile);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ ret = KMF_IsCRLFile(handle, params->sslparms.crlfile, &format);
+ if (ret != KMF_OK) {
+ free(outcrlfile);
+ return (ret);
+ }
+
+ in = BIO_new_file(params->sslparms.crlfile, "rb");
+ if (in == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ if (format == KMF_FORMAT_ASN1) {
+ xcrl = d2i_X509_CRL_bio(in, NULL);
+ } else if (format == KMF_FORMAT_PEM) {
+ xcrl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL);
+ }
+
+ if (xcrl == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_BAD_CRLFILE;
+ goto end;
+ }
+
+ /* If bypasscheck is specified, no need to verify. */
+ if (params->sslparms.crl_check == B_FALSE) {
+ goto output;
+ }
+
+ ret = KMF_IsCertFile(handle, params->sslparms.certfile, &format);
+ if (ret != KMF_OK)
+ goto end;
+
+ /* Read in the CA cert file and convert to X509 */
+ if (BIO_read_filename(in, params->sslparms.certfile) <= 0) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ if (format == KMF_FORMAT_ASN1) {
+ xcert = d2i_X509_bio(in, NULL);
+ } else if (format == KMF_FORMAT_PEM) {
+ xcert = PEM_read_bio_X509(in, NULL, NULL, NULL);
+ } else {
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+
+ if (xcert == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto end;
+ }
+ /* Now get the public key from the CA cert */
+ pkey = X509_get_pubkey(xcert);
+ if (!pkey) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_BAD_CERTFILE;
+ goto end;
+ }
+
+ /* Verify the CRL with the CA's public key */
+ openssl_ret = X509_CRL_verify(xcrl, pkey);
+ EVP_PKEY_free(pkey);
+ if (openssl_ret > 0) {
+ ret = KMF_OK; /* verify succeed */
+ } else {
+ SET_ERROR(kmfh, openssl_ret);
+ ret = KMF_ERR_BAD_CRLFILE;
+ }
+
+output:
+ outformat = params->sslparms.format;
+
+ out = BIO_new_file(outcrlfile, "wb");
+ if (out == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ if (outformat == KMF_FORMAT_ASN1) {
+ openssl_ret = (int)i2d_X509_CRL_bio(out, xcrl);
+ } else if (outformat == KMF_FORMAT_PEM) {
+ openssl_ret = PEM_write_bio_X509_CRL(out, xcrl);
+ } else {
+ ret = KMF_ERR_BAD_PARAMETER;
+ goto end;
+ }
+
+ if (openssl_ret <= 0) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_WRITE_FILE;
+ } else {
+ ret = KMF_OK;
+ }
+
+end:
+ if (xcrl != NULL)
+ X509_CRL_free(xcrl);
+
+ if (xcert != NULL)
+ X509_free(xcert);
+
+ if (in != NULL)
+ (void) BIO_free(in);
+
+ if (out != NULL)
+ (void) BIO_free(out);
+
+ if (outcrlfile != NULL)
+ free(outcrlfile);
+
+ return (ret);
+}
+
+KMF_RETURN
+OpenSSL_ListCRL(KMF_HANDLE_T handle, KMF_LISTCRL_PARAMS *params,
+ char **crldata)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ X509_CRL *x = NULL;
+ KMF_ENCODE_FORMAT format;
+ char *crlfile = NULL;
+ BIO *in = NULL;
+ BIO *mem = NULL;
+ long len;
+ char *memptr;
+ char *data = NULL;
+
+ if (params == NULL || params->sslparms.crlfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ crlfile = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.crlfile);
+
+ if (crlfile == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (isdir(crlfile)) {
+ free(crlfile);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ ret = KMF_IsCRLFile(handle, crlfile, &format);
+ if (ret != KMF_OK) {
+ free(crlfile);
+ return (ret);
+ }
+
+ if (bio_err == NULL)
+ bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
+
+ in = BIO_new_file(crlfile, "rb");
+ if (in == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ if (format == KMF_FORMAT_ASN1) {
+ x = d2i_X509_CRL_bio(in, NULL);
+ } else if (format == KMF_FORMAT_PEM) {
+ x = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL);
+ }
+
+ if (x == NULL) { /* should not happen */
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ mem = BIO_new(BIO_s_mem());
+ if (mem == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+
+ (void) X509_CRL_print(mem, x);
+ len = BIO_get_mem_data(mem, &memptr);
+ if (len <= 0) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+
+ data = malloc(len + 1);
+ if (data == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto end;
+ }
+
+ (void) memcpy(data, memptr, len);
+ data[len] = '\0';
+ *crldata = data;
+
+end:
+ if (x != NULL)
+ X509_CRL_free(x);
+
+ if (crlfile != NULL)
+ free(crlfile);
+
+ if (in != NULL)
+ (void) BIO_free(in);
+
+ if (mem != NULL)
+ (void) BIO_free(mem);
+
+ return (ret);
+}
+
+KMF_RETURN
+OpenSSL_DeleteCRL(KMF_HANDLE_T handle, KMF_DELETECRL_PARAMS *params)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_ENCODE_FORMAT format;
+ char *crlfile = NULL;
+ BIO *in = NULL;
+
+ if (params == NULL || params->sslparms.crlfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ crlfile = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.crlfile);
+
+ if (crlfile == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (isdir(crlfile)) {
+ ret = KMF_ERR_BAD_PARAMETER;
+ goto end;
+ }
+
+ ret = KMF_IsCRLFile(handle, crlfile, &format);
+ if (ret != KMF_OK)
+ goto end;
+
+ if (unlink(crlfile) != 0) {
+ SET_SYS_ERROR(kmfh, errno);
+ ret = KMF_ERR_INTERNAL;
+ goto end;
+ }
+
+end:
+ if (in != NULL)
+ (void) BIO_free(in);
+ if (crlfile != NULL)
+ free(crlfile);
+
+ return (ret);
+}
+
+
+KMF_RETURN
+OpenSSL_FindCertInCRL(KMF_HANDLE_T handle, KMF_FINDCERTINCRL_PARAMS *params)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_ENCODE_FORMAT format;
+ BIO *in = NULL;
+ X509 *xcert = NULL;
+ X509_CRL *xcrl = NULL;
+ STACK_OF(X509_REVOKED) *revoke_stack = NULL;
+ X509_REVOKED *revoke;
+ int i;
+
+ if (params == NULL || params->sslparms.crlfile == NULL ||
+ params->sslparms.certfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ ret = KMF_IsCRLFile(handle, params->sslparms.crlfile, &format);
+ if (ret != KMF_OK)
+ return (ret);
+
+ /* Read the CRL file and load it into a X509_CRL structure */
+ in = BIO_new_file(params->sslparms.crlfile, "rb");
+ if (in == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ if (format == KMF_FORMAT_ASN1) {
+ xcrl = d2i_X509_CRL_bio(in, NULL);
+ } else if (format == KMF_FORMAT_PEM) {
+ xcrl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL);
+ }
+
+ if (xcrl == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_BAD_CRLFILE;
+ goto end;
+ }
+ (void) BIO_free(in);
+
+ /* Read the Certificate file and load it into a X509 structure */
+ ret = KMF_IsCertFile(handle, params->sslparms.certfile, &format);
+ if (ret != KMF_OK)
+ goto end;
+
+ in = BIO_new_file(params->sslparms.certfile, "rb");
+ if (in == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ if (format == KMF_FORMAT_ASN1) {
+ xcert = d2i_X509_bio(in, NULL);
+ } else if (format == KMF_FORMAT_PEM) {
+ xcert = PEM_read_bio_X509(in, NULL, NULL, NULL);
+ }
+
+ if (xcert == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_BAD_CERTFILE;
+ goto end;
+ }
+
+ /* Check if the certificate and the CRL have same issuer */
+ if (X509_NAME_cmp(xcert->cert_info->issuer, xcrl->crl->issuer) != 0) {
+ ret = KMF_ERR_ISSUER;
+ goto end;
+ }
+
+ /* Check to see if the certificate serial number is revoked */
+ revoke_stack = X509_CRL_get_REVOKED(xcrl);
+ if (sk_X509_REVOKED_num(revoke_stack) <= 0) {
+ /* No revoked certificates in the CRL file */
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_EMPTY_CRL;
+ goto end;
+ }
+
+ for (i = 0; i < sk_X509_REVOKED_num(revoke_stack); i++) {
+ /*LINTED*/
+ revoke = sk_X509_REVOKED_value(revoke_stack, i);
+ if (ASN1_INTEGER_cmp(xcert->cert_info->serialNumber,
+ revoke->serialNumber) == 0) {
+ break;
+ }
+ }
+
+ if (i < sk_X509_REVOKED_num(revoke_stack)) {
+ ret = KMF_OK;
+ } else {
+ ret = KMF_ERR_NOT_REVOKED;
+ }
+
+end:
+ if (in != NULL)
+ (void) BIO_free(in);
+ if (xcrl != NULL)
+ X509_CRL_free(xcrl);
+ if (xcert != NULL)
+ X509_free(xcert);
+
+ return (ret);
+}
+
+KMF_RETURN
+OpenSSL_GetErrorString(KMF_HANDLE_T handle, char **msgstr)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ char str[256]; /* OpenSSL needs at least 120 byte buffer */
+
+ ERR_error_string_n(kmfh->lasterr.errcode, str, sizeof (str));
+ if (strlen(str)) {
+ *msgstr = (char *)strdup(str);
+ if ((*msgstr) == NULL)
+ ret = KMF_ERR_MEMORY;
+ } else {
+ *msgstr = NULL;
+ }
+
+ return (ret);
+}
+
+static int
+ext2NID(int kmfext)
+{
+ switch (kmfext) {
+ case KMF_X509_EXT_KEY_USAGE:
+ return (NID_key_usage);
+ case KMF_X509_EXT_PRIV_KEY_USAGE_PERIOD:
+ return (NID_private_key_usage_period);
+ case KMF_X509_EXT_CERT_POLICIES:
+ return (NID_certificate_policies);
+ case KMF_X509_EXT_SUBJ_ALTNAME:
+ return (NID_subject_alt_name);
+ case KMF_X509_EXT_ISSUER_ALTNAME:
+ return (NID_issuer_alt_name);
+ case KMF_X509_EXT_BASIC_CONSTRAINTS:
+ return (NID_basic_constraints);
+ case KMF_X509_EXT_EXT_KEY_USAGE:
+ return (NID_ext_key_usage);
+ case KMF_X509_EXT_AUTH_KEY_ID:
+ return (NID_authority_key_identifier);
+ case KMF_X509_EXT_CRL_DIST_POINTS:
+ return (NID_crl_distribution_points);
+ case KMF_X509_EXT_SUBJ_KEY_ID:
+ return (NID_subject_key_identifier);
+ case KMF_X509_EXT_POLICY_MAPPINGS:
+ return (OBJ_sn2nid("policyMappings"));
+ case KMF_X509_EXT_NAME_CONSTRAINTS:
+ return (OBJ_sn2nid("nameConstraints"));
+ case KMF_X509_EXT_POLICY_CONSTRAINTS:
+ return (OBJ_sn2nid("policyConstraints"));
+ case KMF_X509_EXT_INHIBIT_ANY_POLICY:
+ return (OBJ_sn2nid("inhibitAnyPolicy"));
+ case KMF_X509_EXT_FRESHEST_CRL:
+ return (OBJ_sn2nid("freshestCRL"));
+ default:
+ return (NID_undef);
+ }
+}
+
+KMF_RETURN
+OpenSSL_CertGetPrintable(KMF_HANDLE_T handle, const KMF_DATA *pcert,
+ KMF_PRINTABLE_ITEM flag, char *resultStr)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ X509 *xcert = NULL;
+ unsigned char *outbuf = NULL;
+ unsigned char *outbuf_p;
+ char *tmpstr = NULL;
+ int j;
+ int ext_index, nid, len;
+ BIO *mem = NULL;
+ STACK *emlst = NULL;
+ X509_EXTENSION *ex;
+ X509_CINF *ci;
+
+ if (pcert == NULL || pcert->Data == NULL || pcert->Length == 0) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /* copy cert data to outbuf */
+ outbuf = malloc(pcert->Length);
+ if (outbuf == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+ (void) memcpy(outbuf, pcert->Data, pcert->Length);
+
+ outbuf_p = outbuf; /* use a temp pointer; required by openssl */
+ xcert = d2i_X509(NULL, (const uchar_t **)&outbuf_p, pcert->Length);
+ if (xcert == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+
+ mem = BIO_new(BIO_s_mem());
+ if (mem == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+
+ switch (flag) {
+ case KMF_CERT_ISSUER:
+ (void) X509_NAME_print_ex(mem, X509_get_issuer_name(xcert), 0,
+ XN_FLAG_SEP_CPLUS_SPC);
+ len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN);
+ break;
+
+ case KMF_CERT_SUBJECT:
+ (void) X509_NAME_print_ex(mem, X509_get_subject_name(xcert), 0,
+ XN_FLAG_SEP_CPLUS_SPC);
+ len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN);
+ break;
+
+ case KMF_CERT_VERSION:
+ tmpstr = i2s_ASN1_INTEGER(NULL, xcert->cert_info->version);
+ (void) strncpy(resultStr, tmpstr, KMF_CERT_PRINTABLE_LEN);
+ OPENSSL_free(tmpstr);
+ len = strlen(resultStr);
+ break;
+
+ case KMF_CERT_SERIALNUM:
+ if (i2a_ASN1_INTEGER(mem, X509_get_serialNumber(xcert)) > 0) {
+ (void) strcpy(resultStr, "0x");
+ len = BIO_gets(mem, &resultStr[2],
+ KMF_CERT_PRINTABLE_LEN - 2);
+ }
+ break;
+
+ case KMF_CERT_NOTBEFORE:
+ (void) ASN1_TIME_print(mem, X509_get_notBefore(xcert));
+ len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN);
+ break;
+
+ case KMF_CERT_NOTAFTER:
+ (void) ASN1_TIME_print(mem, X509_get_notAfter(xcert));
+ len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN);
+ break;
+
+ case KMF_CERT_PUBKEY_DATA:
+ {
+ EVP_PKEY *pkey = X509_get_pubkey(xcert);
+ if (pkey == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+
+ if (pkey->type == EVP_PKEY_RSA) {
+ (void) BIO_printf(mem,
+ "RSA Public Key: (%d bit)\n",
+ BN_num_bits(pkey->pkey.rsa->n));
+ (void) RSA_print(mem, pkey->pkey.rsa, 0);
+ } else if (pkey->type == EVP_PKEY_DSA) {
+ (void) BIO_printf(mem,
+ "%12sDSA Public Key:\n", "");
+ (void) DSA_print(mem, pkey->pkey.dsa, 0);
+ } else {
+ (void) BIO_printf(mem,
+ "%12sUnknown Public Key:\n", "");
+ }
+ (void) BIO_printf(mem, "\n");
+ EVP_PKEY_free(pkey);
+ }
+ len = BIO_read(mem, resultStr, KMF_CERT_PRINTABLE_LEN);
+ break;
+ case KMF_CERT_SIGNATURE_ALG:
+ case KMF_CERT_PUBKEY_ALG:
+ if (flag == KMF_CERT_SIGNATURE_ALG) {
+ len = i2a_ASN1_OBJECT(mem,
+ xcert->sig_alg->algorithm);
+ } else {
+ len = i2a_ASN1_OBJECT(mem,
+ xcert->cert_info->key->algor->algorithm);
+ }
+
+ if (len > 0) {
+ len = BIO_read(mem, resultStr,
+ KMF_CERT_PRINTABLE_LEN);
+ }
+ break;
+
+ case KMF_CERT_EMAIL:
+ emlst = X509_get1_email(xcert);
+ for (j = 0; j < sk_num(emlst); j++)
+ (void) BIO_printf(mem, "%s\n", sk_value(emlst, j));
+
+ len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN);
+ X509_email_free(emlst);
+ break;
+ case KMF_X509_EXT_ISSUER_ALTNAME:
+ case KMF_X509_EXT_SUBJ_ALTNAME:
+ case KMF_X509_EXT_KEY_USAGE:
+ case KMF_X509_EXT_PRIV_KEY_USAGE_PERIOD:
+ case KMF_X509_EXT_CERT_POLICIES:
+ case KMF_X509_EXT_BASIC_CONSTRAINTS:
+ case KMF_X509_EXT_NAME_CONSTRAINTS:
+ case KMF_X509_EXT_POLICY_CONSTRAINTS:
+ case KMF_X509_EXT_EXT_KEY_USAGE:
+ case KMF_X509_EXT_INHIBIT_ANY_POLICY:
+ case KMF_X509_EXT_AUTH_KEY_ID:
+ case KMF_X509_EXT_SUBJ_KEY_ID:
+ case KMF_X509_EXT_POLICY_MAPPINGS:
+ case KMF_X509_EXT_CRL_DIST_POINTS:
+ case KMF_X509_EXT_FRESHEST_CRL:
+ nid = ext2NID(flag);
+ if (nid == NID_undef) {
+ ret = KMF_ERR_EXTENSION_NOT_FOUND;
+ goto out;
+ }
+ ci = xcert->cert_info;
+
+ ext_index = X509v3_get_ext_by_NID(ci->extensions, nid, -1);
+ if (ext_index == -1) {
+ SET_ERROR(kmfh, ERR_get_error());
+
+ ret = KMF_ERR_EXTENSION_NOT_FOUND;
+ goto out;
+ }
+ ex = X509v3_get_ext(ci->extensions, ext_index);
+
+ (void) i2a_ASN1_OBJECT(mem, X509_EXTENSION_get_object(ex));
+
+ if (BIO_printf(mem, ": %s\n",
+ X509_EXTENSION_get_critical(ex) ? "critical" : "") <=
+ 0) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+ if (!X509V3_EXT_print(mem, ex, X509V3_EXT_DUMP_UNKNOWN, 4)) {
+ (void) BIO_printf(mem, "%*s", 4, "");
+ (void) M_ASN1_OCTET_STRING_print(mem, ex->value);
+ }
+ if (BIO_write(mem, "\n", 1) <= 0) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_ENCODING;
+ goto out;
+ }
+ len = BIO_read(mem, resultStr, KMF_CERT_PRINTABLE_LEN);
+ }
+ if (len <= 0) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_ENCODING;
+ }
+
+out:
+ if (outbuf != NULL) {
+ free(outbuf);
+ }
+
+ if (xcert != NULL) {
+ X509_free(xcert);
+ }
+
+ if (mem != NULL) {
+ (void) BIO_free(mem);
+ }
+
+ return (ret);
+}
+KMF_RETURN
+/*ARGSUSED*/
+OpenSSL_GetPrikeyByCert(KMF_HANDLE_T handle,
+ KMF_CRYPTOWITHCERT_PARAMS *params,
+ KMF_DATA *SignerCertData, KMF_KEY_HANDLE *key,
+ KMF_KEY_ALG keytype)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_FINDKEY_PARAMS fkparms;
+ uint32_t numkeys = 0;
+
+ if (params == NULL && params->sslparms.keyfile == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * This is really just a FindKey operation, reuse the
+ * FindKey function.
+ */
+ (void *)memset(&fkparms, 0, sizeof (fkparms));
+ fkparms.kstype = KMF_KEYSTORE_OPENSSL;
+ fkparms.keyclass = KMF_ASYM_PRI;
+ fkparms.keytype = keytype;
+ fkparms.format = params->format;
+ fkparms.sslparms = params->sslparms;
+
+ rv = OpenSSL_FindKey(handle, &fkparms, key, &numkeys);
+
+ return (rv);
+}
+
+KMF_RETURN
+/*ARGSUSED*/
+OpenSSL_DecryptData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key,
+ KMF_OID *AlgOID, KMF_DATA *ciphertext,
+ KMF_DATA *output)
+{
+ KMF_RETURN ret = KMF_OK;
+ RSA *rsa = NULL;
+ unsigned int in_len = 0, out_len = 0;
+ unsigned int total_decrypted = 0, modulus_len = 0;
+ uint8_t *in_data, *out_data;
+ int i, blocks;
+
+ if (key == NULL || AlgOID == NULL ||
+ ciphertext == NULL || output == NULL ||
+ ciphertext->Data == NULL ||
+ output->Data == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (key->keyalg == KMF_RSA) {
+ rsa = EVP_PKEY_get1_RSA((EVP_PKEY *)key->keyp);
+ modulus_len = RSA_size(rsa);
+ } else {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ blocks = ciphertext->Length/modulus_len;
+ out_data = output->Data;
+ in_data = ciphertext->Data;
+ out_len = modulus_len - 11;
+ in_len = modulus_len;
+
+ for (i = 0; i < blocks; i++) {
+ out_len = RSA_private_decrypt(in_len,
+ in_data, out_data, rsa, RSA_PKCS1_PADDING);
+
+ if (out_len == 0) {
+ ret = KMF_ERR_INTERNAL;
+ goto cleanup;
+ }
+
+ out_data += out_len;
+ total_decrypted += out_len;
+ in_data += in_len;
+ }
+
+ output->Length = total_decrypted;
+
+cleanup:
+ RSA_free(rsa);
+ if (ret != KMF_OK)
+ output->Length = 0;
+
+ return (ret);
+
+}
+
+/*
+ * This function will create a certid from issuer_cert and user_cert.
+ * The caller should use OCSP_CERTID_free(OCSP_CERTID *) to deallocate
+ * certid memory after use.
+ */
+static KMF_RETURN
+create_certid(KMF_HANDLE_T handle, const KMF_DATA *issuer_cert,
+ const KMF_DATA *user_cert, OCSP_CERTID **certid)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ X509 *issuer = NULL;
+ X509 *cert = NULL;
+ unsigned char *ptmp;
+
+ if (issuer_cert == NULL || user_cert == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /* convert the DER-encoded issuer cert to an internal X509 */
+ ptmp = issuer_cert->Data;
+ issuer = d2i_X509(NULL, (const uchar_t **)&ptmp,
+ issuer_cert->Length);
+ if (issuer == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OCSP_BAD_ISSUER;
+ goto end;
+ }
+
+ /* convert the DER-encoded user cert to an internal X509 */
+ ptmp = user_cert->Data;
+ cert = d2i_X509(NULL, (const uchar_t **)&ptmp,
+ user_cert->Length);
+ if (cert == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+
+ ret = KMF_ERR_OCSP_BAD_CERT;
+ goto end;
+ }
+
+ /* create a CERTID */
+ *certid = OCSP_cert_to_id(NULL, cert, issuer);
+ if (*certid == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OCSP_CERTID;
+ goto end;
+ }
+
+end:
+ if (issuer != NULL) {
+ X509_free(issuer);
+ }
+
+ if (cert != NULL) {
+ X509_free(cert);
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+OpenSSL_CreateOCSPRequest(KMF_HANDLE_T handle, KMF_OCSPREQUEST_PARAMS *params,
+ char *reqfile)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ OCSP_CERTID *id = NULL;
+ OCSP_REQUEST *req = NULL;
+ BIO *derbio = NULL;
+
+ if (params->user_cert == NULL || params->issuer_cert == NULL ||
+ reqfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ ret = create_certid(handle, params->issuer_cert, params->user_cert,
+ &id);
+ if (ret != KMF_OK) {
+ return (ret);
+ }
+
+ /* Create an OCSP request */
+ req = OCSP_REQUEST_new();
+ if (req == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OCSP_CREATE_REQUEST;
+ goto end;
+ }
+
+ if (!OCSP_request_add0_id(req, id)) {
+ ret = KMF_ERR_OCSP_CREATE_REQUEST;
+ goto end;
+ }
+
+ /* Write the request to the output file with DER encoding */
+ derbio = BIO_new_file(reqfile, "wb");
+ if (!derbio) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+ if (i2d_OCSP_REQUEST_bio(derbio, req) <= 0) {
+ ret = KMF_ERR_ENCODING;
+ }
+
+end:
+ /*
+ * We don't need to free "id" explicitely, because OCSP_REQUEST_free()
+ * will deallocate certid's space also.
+ */
+ if (req != NULL) {
+ OCSP_REQUEST_free(req);
+ }
+
+ if (derbio != NULL) {
+ (void) BIO_free(derbio);
+ }
+
+ return (ret);
+}
+
+/* ocsp_find_signer_sk() is copied from openssl source */
+static X509 *ocsp_find_signer_sk(STACK_OF(X509) *certs, OCSP_RESPID *id)
+{
+ int i;
+ unsigned char tmphash[SHA_DIGEST_LENGTH], *keyhash;
+
+ /* Easy if lookup by name */
+ if (id->type == V_OCSP_RESPID_NAME)
+ return (X509_find_by_subject(certs, id->value.byName));
+
+ /* Lookup by key hash */
+
+ /* If key hash isn't SHA1 length then forget it */
+ if (id->value.byKey->length != SHA_DIGEST_LENGTH)
+ return (NULL);
+
+ keyhash = id->value.byKey->data;
+ /* Calculate hash of each key and compare */
+ for (i = 0; i < sk_X509_num(certs); i++) {
+ /*LINTED*/
+ X509 *x = sk_X509_value(certs, i);
+ (void) X509_pubkey_digest(x, EVP_sha1(), tmphash, NULL);
+ if (!memcmp(keyhash, tmphash, SHA_DIGEST_LENGTH))
+ return (x);
+ }
+ return (NULL);
+}
+
+/* ocsp_find_signer() is copied from openssl source */
+/*ARGSUSED*/
+static int
+ocsp_find_signer(X509 **psigner, OCSP_BASICRESP *bs, STACK_OF(X509) *certs,
+ X509_STORE *st, unsigned long flags)
+{
+ X509 *signer;
+ OCSP_RESPID *rid = bs->tbsResponseData->responderId;
+ if ((signer = ocsp_find_signer_sk(certs, rid))) {
+ *psigner = signer;
+ return (2);
+ }
+ if (!(flags & OCSP_NOINTERN) &&
+ (signer = ocsp_find_signer_sk(bs->certs, rid))) {
+ *psigner = signer;
+ return (1);
+ }
+ /* Maybe lookup from store if by subject name */
+
+ *psigner = NULL;
+ return (0);
+}
+
+/*
+ * This function will verify the signature of a basic response, using
+ * the public key from the OCSP responder certificate.
+ */
+static KMF_RETURN
+check_response_signature(KMF_HANDLE_T handle, OCSP_BASICRESP *bs,
+ KMF_DATA *signer_cert, KMF_DATA *issuer_cert)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ STACK_OF(X509) *cert_stack = NULL;
+ X509 *signer = NULL;
+ X509 *issuer = NULL;
+ EVP_PKEY *skey = NULL;
+ unsigned char *ptmp;
+
+
+ if (bs == NULL || issuer_cert == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * Find the certificate that signed the basic response.
+ *
+ * If signer_cert is not NULL, we will use that as the signer cert.
+ * Otherwise, we will check if the issuer cert is actually the signer.
+ * If we still do not find a signer, we will look for it from the
+ * certificate list came with the response file.
+ */
+ if (signer_cert != NULL) {
+ ptmp = signer_cert->Data;
+ signer = d2i_X509(NULL, (const uchar_t **)&ptmp,
+ signer_cert->Length);
+ if (signer == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OCSP_BAD_SIGNER;
+ goto end;
+ }
+ } else {
+ /*
+ * Convert the issuer cert into X509 and push it into a
+ * stack to be used by ocsp_find_signer().
+ */
+ ptmp = issuer_cert->Data;
+ issuer = d2i_X509(NULL, (const uchar_t **)&ptmp,
+ issuer_cert->Length);
+ if (issuer == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OCSP_BAD_ISSUER;
+ goto end;
+ }
+
+ if ((cert_stack = sk_X509_new_null()) == NULL) {
+ ret = KMF_ERR_INTERNAL;
+ goto end;
+ }
+
+ if (sk_X509_push(cert_stack, issuer) == NULL) {
+ ret = KMF_ERR_INTERNAL;
+ goto end;
+ }
+
+ ret = ocsp_find_signer(&signer, bs, cert_stack, NULL, 0);
+ if (!ret) {
+ /* can not find the signer */
+ ret = KMF_ERR_OCSP_BAD_SIGNER;
+ goto end;
+ }
+ }
+
+ /* Verify the signature of the response */
+ skey = X509_get_pubkey(signer);
+ if (skey == NULL) {
+ ret = KMF_ERR_OCSP_BAD_SIGNER;
+ goto end;
+ }
+
+ ret = OCSP_BASICRESP_verify(bs, skey, 0);
+ if (ret == 0) {
+ ret = KMF_ERR_OCSP_RESPONSE_SIGNATURE;
+ goto end;
+ }
+
+end:
+ if (issuer != NULL) {
+ X509_free(issuer);
+ }
+
+ if (signer != NULL) {
+ X509_free(signer);
+ }
+
+ if (skey != NULL) {
+ EVP_PKEY_free(skey);
+ }
+
+ if (cert_stack != NULL) {
+ sk_X509_free(cert_stack);
+ }
+
+ return (ret);
+}
+
+
+
+KMF_RETURN
+OpenSSL_GetOCSPStatusForCert(KMF_HANDLE_T handle,
+ KMF_OCSPRESPONSE_PARAMS_INPUT *params_in,
+ KMF_OCSPRESPONSE_PARAMS_OUTPUT *params_out)
+{
+ KMF_RETURN ret = KMF_OK;
+ BIO *derbio = NULL;
+ OCSP_RESPONSE *resp = NULL;
+ OCSP_BASICRESP *bs = NULL;
+ OCSP_CERTID *id = NULL;
+ OCSP_SINGLERESP *single = NULL;
+ ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
+ int index, status, reason;
+
+ if (params_in == NULL || params_in->issuer_cert == NULL ||
+ params_in->user_cert == NULL || params_in->response == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ if (params_out == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /* Read in the response */
+ derbio = BIO_new_mem_buf(params_in->response->Data,
+ params_in->response->Length);
+ if (!derbio) {
+ ret = KMF_ERR_MEMORY;
+ return (ret);
+ }
+
+ resp = d2i_OCSP_RESPONSE_bio(derbio, NULL);
+ if (resp == NULL) {
+ ret = KMF_ERR_OCSP_MALFORMED_RESPONSE;
+ goto end;
+ }
+
+ /* Check the response status */
+ status = OCSP_response_status(resp);
+ params_out->response_status = status;
+ if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+ ret = KMF_ERR_OCSP_RESPONSE_STATUS;
+ goto end;
+ }
+
+#ifdef DEBUG
+ printf("Successfully checked the response file status.\n");
+#endif /* DEBUG */
+
+ /* Extract basic response */
+ bs = OCSP_response_get1_basic(resp);
+ if (bs == NULL) {
+ ret = KMF_ERR_OCSP_NO_BASIC_RESPONSE;
+ goto end;
+ }
+
+#ifdef DEBUG
+ printf("Successfully retrieved the basic response.\n");
+#endif /* DEBUG */
+
+ /* Check the basic response signature if required */
+ if (params_in->ignore_response_sign == B_FALSE) {
+ ret = check_response_signature(handle, bs,
+ params_in->signer_cert, params_in->issuer_cert);
+ if (ret != KMF_OK)
+ goto end;
+ }
+
+#ifdef DEBUG
+ printf("Successfully verified the response signature.\n");
+#endif /* DEBUG */
+
+ /* Create a certid for the certificate in question */
+ ret = create_certid(handle, params_in->issuer_cert,
+ params_in->user_cert, &id);
+ if (ret != KMF_OK) {
+ ret = KMF_ERR_OCSP_CERTID;
+ goto end;
+ }
+
+#ifdef DEBUG
+ printf("successfully created a certid for the cert.\n");
+#endif /* DEBUG */
+
+ /* Find the index of the single response for the certid */
+ index = OCSP_resp_find(bs, id, -1);
+ if (index < 0) {
+ /* cound not find this certificate in the response */
+ ret = KMF_ERR_OCSP_UNKNOWN_CERT;
+ goto end;
+ }
+
+#ifdef DEBUG
+ printf("Successfully found the single response index for the cert.\n");
+#endif /* DEBUG */
+
+ /* Retrieve the single response and get the cert status */
+ single = OCSP_resp_get0(bs, index);
+ status = OCSP_single_get0_status(single, &reason, &rev, &thisupd,
+ &nextupd);
+ if (status == V_OCSP_CERTSTATUS_GOOD) {
+ params_out->cert_status = OCSP_GOOD;
+ } else if (status == V_OCSP_CERTSTATUS_UNKNOWN) {
+ params_out->cert_status = OCSP_UNKNOWN;
+ } else { /* revoked */
+ params_out->cert_status = OCSP_REVOKED;
+ params_out->reason = reason;
+ }
+ ret = KMF_OK;
+
+ /* Verify the time */
+ if (!OCSP_check_validity(thisupd, nextupd, 300,
+ params_in->response_lifetime)) {
+ ret = KMF_ERR_OCSP_STATUS_TIME_INVALID;
+ goto end;
+ }
+
+#ifdef DEBUG
+ printf("Successfully verify the time.\n");
+#endif /* DEBUG */
+
+end:
+ if (derbio != NULL)
+ (void) BIO_free(derbio);
+
+ if (resp != NULL)
+ OCSP_RESPONSE_free(resp);
+
+ if (bs != NULL)
+ OCSP_BASICRESP_free(bs);
+
+ if (id != NULL)
+ OCSP_CERTID_free(id);
+
+ return (ret);
+}
+
+static KMF_RETURN
+fetch_key(KMF_HANDLE_T handle, char *path,
+ KMF_KEY_CLASS keyclass, KMF_KEY_HANDLE *key)
+{
+ KMF_RETURN rv = KMF_OK;
+ EVP_PKEY *pkey;
+ KMF_RAW_SYM_KEY *rkey = NULL;
+
+ /* Make sure the requested file actually exists. */
+ if (access(path, F_OK) != 0) {
+ return (KMF_ERR_KEY_NOT_FOUND);
+ }
+
+ if (keyclass == KMF_ASYM_PRI ||
+ keyclass == KMF_ASYM_PUB) {
+ pkey = openssl_load_key(handle, path);
+ if (pkey == NULL) {
+ return (KMF_ERR_KEY_NOT_FOUND);
+ }
+ if (key != NULL) {
+ if (pkey->type == EVP_PKEY_RSA)
+ key->keyalg = KMF_RSA;
+ else if (pkey->type == EVP_PKEY_DSA)
+ key->keyalg = KMF_DSA;
+
+ key->kstype = KMF_KEYSTORE_OPENSSL;
+ key->keyclass = keyclass;
+ key->keyp = (void *)pkey;
+ key->israw = FALSE;
+ key->keylabel = path;
+ } else {
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ }
+ } else if (keyclass == KMF_SYMMETRIC) {
+ KMF_ENCODE_FORMAT fmt;
+ /*
+ * If the file is a recognized format,
+ * then it is NOT a symmetric key.
+ */
+ rv = KMF_GetFileFormat(path, &fmt);
+ if (rv == KMF_OK || fmt != 0) {
+ return (KMF_ERR_KEY_NOT_FOUND);
+ } else if (rv == KMF_ERR_ENCODING) {
+ /*
+ * If we don't know the encoding,
+ * it is probably a symmetric key.
+ */
+ rv = KMF_OK;
+ }
+
+ if (key != NULL) {
+ KMF_DATA keyvalue;
+ rkey = malloc(sizeof (KMF_RAW_SYM_KEY));
+ if (rkey == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto out;
+ }
+
+ (void) memset(rkey, 0, sizeof (KMF_RAW_SYM_KEY));
+ rv = KMF_ReadInputFile(handle, path, &keyvalue);
+ if (rv != KMF_OK)
+ goto out;
+
+ rkey->keydata.len = keyvalue.Length;
+ rkey->keydata.val = keyvalue.Data;
+
+ key->kstype = KMF_KEYSTORE_OPENSSL;
+ key->keyclass = keyclass;
+ key->israw = TRUE;
+ key->keylabel = path;
+ key->keyp = (void *)rkey;
+ }
+ }
+out:
+ if (rv != KMF_OK) {
+ if (rkey != NULL) {
+ KMF_FreeRawSymKey(rkey);
+ }
+ if (pkey != NULL)
+ EVP_PKEY_free(pkey);
+
+ if (key != NULL) {
+ key->keyalg = KMF_KEYALG_NONE;
+ key->keyclass = KMF_KEYCLASS_NONE;
+ key->keyp = NULL;
+ }
+ }
+
+ return (rv);
+}
+
+KMF_RETURN
+OpenSSL_FindKey(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS *params,
+ KMF_KEY_HANDLE *key, uint32_t *numkeys)
+{
+ KMF_RETURN rv = KMF_OK;
+ char *fullpath = NULL;
+
+ if (handle == NULL || params == NULL || numkeys == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (params->keyclass != KMF_ASYM_PUB &&
+ params->keyclass != KMF_ASYM_PRI &&
+ params->keyclass != KMF_SYMMETRIC)
+ return (KMF_ERR_BAD_KEY_CLASS);
+
+ fullpath = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.keyfile);
+
+ if (fullpath == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ *numkeys = 0;
+
+ if (isdir(fullpath)) {
+ DIR *dirp;
+ struct dirent *dp;
+ int n = 0;
+
+ /* open all files in the directory and attempt to read them */
+ if ((dirp = opendir(fullpath)) == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+ rewinddir(dirp);
+ while ((dp = readdir(dirp)) != NULL) {
+ if (strcmp(dp->d_name, ".") &&
+ strcmp(dp->d_name, "..")) {
+ char *fname;
+
+ fname = get_fullpath(fullpath,
+ (char *)&dp->d_name);
+
+ rv = fetch_key(handle, fname,
+ params->keyclass,
+ key ? &key[n] : NULL);
+
+ if (rv == KMF_OK)
+ n++;
+
+ if (rv != KMF_OK || key == NULL)
+ free(fname);
+ }
+ }
+ (void) closedir(dirp);
+ free(fullpath);
+ (*numkeys) = n;
+ } else {
+ rv = fetch_key(handle, fullpath, params->keyclass, key);
+ if (rv == KMF_OK)
+ (*numkeys) = 1;
+
+ if (rv != KMF_OK || key == NULL)
+ free(fullpath);
+ }
+
+ if ((*numkeys) == 0)
+ rv = KMF_ERR_KEY_NOT_FOUND;
+
+ return (rv);
+}
+
+#define HANDLE_PK12_ERROR { \
+ SET_ERROR(kmfh, ERR_get_error()); \
+ rv = KMF_ERR_ENCODING; \
+ goto out; \
+}
+
+static KMF_RETURN
+write_pkcs12(KMF_HANDLE *kmfh,
+ BIO *bio,
+ KMF_CREDENTIAL *cred,
+ EVP_PKEY *pkey,
+ X509 *sslcert)
+{
+ KMF_RETURN rv = KMF_OK;
+ STACK_OF(PKCS12_SAFEBAG) *bag_stack = NULL;
+ PKCS12_SAFEBAG *bag = NULL;
+ PKCS7 *cert_authsafe = NULL;
+ PKCS8_PRIV_KEY_INFO *p8 = NULL;
+ PKCS7 *key_authsafe = NULL;
+ STACK_OF(PKCS7) *authsafe_stack = NULL;
+ PKCS12 *p12_elem = NULL;
+ char *lab = NULL;
+ int lab_len = 0;
+ unsigned char keyid[EVP_MAX_MD_SIZE];
+ unsigned int keyidlen = 0;
+
+ /* Must have at least a cert OR a key */
+ if (sslcert == NULL && pkey == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(keyid, 0, sizeof (keyid));
+ /*
+ * Section 1:
+ *
+ * The first PKCS#12 container (safebag) will hold the certificates
+ * associated with this key. The result of this section is a
+ * PIN-encrypted PKCS#7 container (authsafe). If there are no
+ * certificates, there is no point in creating the "safebag" or the
+ * "authsafe" so we go to the next section.
+ */
+ if (sslcert != NULL && pkey != NULL) {
+ if (X509_check_private_key(sslcert, pkey)) {
+ (void) X509_digest(sslcert, EVP_sha1(), keyid,
+ &keyidlen);
+ } else {
+ /* The key doesn't match the cert */
+ HANDLE_PK12_ERROR
+ }
+ }
+
+ bag_stack = sk_PKCS12_SAFEBAG_new_null();
+ if (bag_stack == NULL)
+ return (KMF_ERR_MEMORY);
+
+ if (sslcert != NULL) {
+ /* Convert cert from X509 struct to PKCS#12 bag */
+ bag = PKCS12_x5092certbag(sslcert);
+ if (bag == NULL) {
+ HANDLE_PK12_ERROR
+ }
+
+ /* Add the key id to the certificate bag. */
+ if (keyidlen > 0 &&
+ !PKCS12_add_localkeyid(bag, keyid, keyidlen)) {
+ HANDLE_PK12_ERROR
+ }
+
+ /* Pile it on the bag_stack. */
+ if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag)) {
+ HANDLE_PK12_ERROR
+ }
+#if 0
+ /* No support for CA certs yet */
+ if (cacerts != NULL && ncacerts > 0) {
+ int i;
+ for (i = 0; i < ncacerts; i++) {
+ KMF_X509_DER_CERT *c = &cacerts[i];
+ X509 *ca = NULL;
+
+ uchar_t *p = (uchar_t *)c->certificate.Data;
+ ca = d2i_X509(NULL, &p,
+ c->certificate.Length);
+ if (ca == NULL) {
+ HANDLE_PK12_ERROR
+ }
+ /* Convert CA cert to PKCS#12 bag. */
+ bag = PKCS12_x5092certbag(ca);
+ if (bag == NULL) {
+ sk_PKCS12_SAFEBAG_pop_free(bag_stack,
+ PKCS12_SAFEBAG_free);
+ HANDLE_PK12_ERROR
+ }
+ /* Pile it onto the bag_stack. */
+ if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag)) {
+ HANDLE_PK12_ERROR
+ }
+ }
+ }
+#endif
+ /* Turn bag_stack of certs into encrypted authsafe. */
+ cert_authsafe = PKCS12_pack_p7encdata(
+ NID_pbe_WithSHA1And40BitRC2_CBC,
+ cred->cred,
+ cred->credlen, NULL, 0,
+ PKCS12_DEFAULT_ITER,
+ bag_stack);
+
+ /* Clear away this bag_stack, we're done with it. */
+ sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free);
+ bag_stack = NULL;
+
+ if (cert_authsafe == NULL) {
+ HANDLE_PK12_ERROR
+ }
+ }
+ /*
+ * Section 2:
+ *
+ * The second PKCS#12 container (safebag) will hold the private key
+ * that goes with the certificates above. The results of this section
+ * is an unencrypted PKCS#7 container (authsafe). If there is no
+ * private key, there is no point in creating the "safebag" or the
+ * "authsafe" so we go to the next section.
+ */
+ if (pkey != NULL) {
+ p8 = EVP_PKEY2PKCS8(pkey);
+ if (p8 == NULL) {
+ HANDLE_PK12_ERROR
+ }
+ /* Put the shrouded key into a PKCS#12 bag. */
+ bag = PKCS12_MAKE_SHKEYBAG(
+ NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
+ cred->cred, cred->credlen,
+ NULL, 0, PKCS12_DEFAULT_ITER, p8);
+
+ /* Clean up the PKCS#8 shrouded key, don't need it now. */
+ PKCS8_PRIV_KEY_INFO_free(p8);
+ p8 = NULL;
+
+ if (bag == NULL) {
+ HANDLE_PK12_ERROR
+ }
+ if (keyidlen &&
+ !PKCS12_add_localkeyid(bag, keyid, keyidlen)) {
+ HANDLE_PK12_ERROR
+ }
+ if (lab != NULL) {
+ if (!PKCS12_add_friendlyname(bag,
+ (char *)lab, lab_len)) {
+ HANDLE_PK12_ERROR
+ }
+ }
+ /* Start a PKCS#12 safebag container for the private key. */
+ bag_stack = sk_PKCS12_SAFEBAG_new_null();
+ if (bag_stack == NULL) {
+ HANDLE_PK12_ERROR
+ }
+
+ /* Pile on the private key on the bag_stack. */
+ if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag)) {
+ HANDLE_PK12_ERROR
+ }
+ key_authsafe = PKCS12_pack_p7data(bag_stack);
+
+ /* Clear away this bag_stack, we're done with it. */
+ sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free);
+ bag_stack = NULL;
+
+ if (key_authsafe == NULL) {
+ HANDLE_PK12_ERROR
+ }
+ }
+ /*
+ * Section 3:
+ *
+ * This is where the two PKCS#7 containers, one for the certificates
+ * and one for the private key, are put together into a PKCS#12
+ * element. This final PKCS#12 element is written to the export file.
+ */
+
+ /* Start a PKCS#7 stack. */
+ authsafe_stack = sk_PKCS7_new_null();
+ if (authsafe_stack == NULL) {
+ HANDLE_PK12_ERROR
+ }
+ if (key_authsafe != NULL) {
+ if (!sk_PKCS7_push(authsafe_stack, key_authsafe)) {
+ HANDLE_PK12_ERROR
+ }
+ }
+ if (cert_authsafe != NULL) {
+ if (!sk_PKCS7_push(authsafe_stack, cert_authsafe)) {
+ HANDLE_PK12_ERROR
+ }
+ }
+ p12_elem = PKCS12_init(NID_pkcs7_data);
+ if (p12_elem == NULL) {
+ sk_PKCS7_pop_free(authsafe_stack, PKCS7_free);
+ HANDLE_PK12_ERROR
+ }
+
+ /* Put the PKCS#7 stack into the PKCS#12 element. */
+ if (!PKCS12_pack_authsafes(p12_elem, authsafe_stack)) {
+ HANDLE_PK12_ERROR
+ }
+ /* Clear away the PKCS#7 stack, we're done with it. */
+ sk_PKCS7_pop_free(authsafe_stack, PKCS7_free);
+ authsafe_stack = NULL;
+
+ /* Set the integrity MAC on the PKCS#12 element. */
+ if (!PKCS12_set_mac(p12_elem, cred->cred, cred->credlen,
+ NULL, 0, PKCS12_DEFAULT_ITER, NULL)) {
+ HANDLE_PK12_ERROR
+ }
+
+ /* Write the PKCS#12 element to the export file. */
+ if (!i2d_PKCS12_bio(bio, p12_elem)) {
+ HANDLE_PK12_ERROR
+ }
+
+ PKCS12_free(p12_elem);
+out:
+ if (rv != KMF_OK) {
+ /* Clear away this bag_stack, we're done with it. */
+ sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free);
+ sk_PKCS7_pop_free(authsafe_stack, PKCS7_free);
+ }
+ return (rv);
+}
+
+static EVP_PKEY *
+ImportRawRSAKey(KMF_RAW_RSA_KEY *key)
+{
+ RSA *rsa = NULL;
+ EVP_PKEY *newkey = NULL;
+
+ if ((rsa = RSA_new()) == NULL)
+ return (NULL);
+
+ if ((rsa->n = BN_bin2bn(key->mod.val, key->mod.len, rsa->n)) == NULL)
+ return (NULL);
+
+ if ((rsa->e = BN_bin2bn(key->pubexp.val, key->pubexp.len, rsa->e)) ==
+ NULL)
+ return (NULL);
+
+ if (key->priexp.val != NULL)
+ if ((rsa->d = BN_bin2bn(key->priexp.val, key->priexp.len,
+ rsa->d)) == NULL)
+ return (NULL);
+
+ if (key->prime1.val != NULL)
+ if ((rsa->p = BN_bin2bn(key->prime1.val, key->prime1.len,
+ rsa->p)) == NULL)
+ return (NULL);
+
+ if (key->prime2.val != NULL)
+ if ((rsa->q = BN_bin2bn(key->prime2.val, key->prime2.len,
+ rsa->q)) == NULL)
+ return (NULL);
+
+ if (key->exp1.val != NULL)
+ if ((rsa->dmp1 = BN_bin2bn(key->exp1.val, key->exp1.len,
+ rsa->dmp1)) == NULL)
+ return (NULL);
+
+ if (key->exp2.val != NULL)
+ if ((rsa->dmq1 = BN_bin2bn(key->exp2.val, key->exp2.len,
+ rsa->dmq1)) == NULL)
+ return (NULL);
+
+ if (key->coef.val != NULL)
+ if ((rsa->iqmp = BN_bin2bn(key->coef.val, key->coef.len,
+ rsa->iqmp)) == NULL)
+ return (NULL);
+
+ if ((newkey = EVP_PKEY_new()) == NULL)
+ return (NULL);
+
+ (void) EVP_PKEY_set1_RSA(newkey, rsa);
+
+ /* The original key must be freed once here or it leaks memory */
+ RSA_free(rsa);
+
+ return (newkey);
+}
+
+static EVP_PKEY *
+ImportRawDSAKey(KMF_RAW_DSA_KEY *key)
+{
+ DSA *dsa = NULL;
+ EVP_PKEY *newkey = NULL;
+
+ if ((dsa = DSA_new()) == NULL)
+ return (NULL);
+
+ if ((dsa->p = BN_bin2bn(key->prime.val, key->prime.len,
+ dsa->p)) == NULL)
+ return (NULL);
+
+ if ((dsa->q = BN_bin2bn(key->subprime.val, key->subprime.len,
+ dsa->q)) == NULL)
+ return (NULL);
+
+ if ((dsa->g = BN_bin2bn(key->base.val, key->base.len,
+ dsa->g)) == NULL)
+ return (NULL);
+
+ if ((dsa->priv_key = BN_bin2bn(key->value.val, key->value.len,
+ dsa->priv_key)) == NULL)
+ return (NULL);
+
+ if ((newkey = EVP_PKEY_new()) == NULL)
+ return (NULL);
+
+ (void) EVP_PKEY_set1_DSA(newkey, dsa);
+
+ /* The original key must be freed once here or it leaks memory */
+ DSA_free(dsa);
+ return (newkey);
+}
+
+static KMF_RETURN
+ExportPK12FromRawData(KMF_HANDLE_T handle,
+ KMF_CREDENTIAL *cred,
+ int numcerts, KMF_X509_DER_CERT *certlist,
+ int numkeys, KMF_KEY_HANDLE *keylist,
+ char *filename)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ BIO *bio = NULL;
+ X509 *xcert = NULL;
+ EVP_PKEY *pkey = NULL;
+ int i;
+
+ /*
+ * Open the output file.
+ */
+ if ((bio = BIO_new_file(filename, "wb")) == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_OPEN_FILE;
+ goto cleanup;
+ }
+
+ if (numcerts > 0 && numkeys > 0) {
+ for (i = 0; rv == KMF_OK && i < numcerts; i++) {
+ KMF_RAW_KEY_DATA *key = NULL;
+ const uchar_t *p = certlist[i].certificate.Data;
+ long len = certlist[i].certificate.Length;
+
+ if (i < numkeys) {
+ key = (KMF_RAW_KEY_DATA *)keylist[i].keyp;
+
+ if (key->keytype == KMF_RSA) {
+ pkey = ImportRawRSAKey(
+ &key->rawdata.rsa);
+ } else if (key->keytype == KMF_DSA) {
+ pkey = ImportRawDSAKey(
+ &key->rawdata.dsa);
+ } else {
+ rv = KMF_ERR_BAD_PARAMETER;
+ }
+ }
+
+ xcert = d2i_X509(NULL, &p, len);
+ if (xcert == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_ENCODING;
+ }
+ /* Stick the key and the cert into a PKCS#12 file */
+ rv = write_pkcs12(kmfh, bio, cred, pkey, xcert);
+ if (xcert)
+ X509_free(xcert);
+ if (pkey)
+ EVP_PKEY_free(pkey);
+ }
+ }
+
+cleanup:
+
+ if (bio != NULL)
+ (void) BIO_free_all(bio);
+
+ return (rv);
+}
+
+KMF_RETURN
+OpenSSL_ExportP12(KMF_HANDLE_T handle,
+ KMF_EXPORTP12_PARAMS *params,
+ int numcerts, KMF_X509_DER_CERT *certlist,
+ int numkeys, KMF_KEY_HANDLE *keylist,
+ char *filename)
+{
+ KMF_RETURN rv;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_FINDCERT_PARAMS fcargs;
+ BIO *bio = NULL;
+ X509 *xcert = NULL;
+ char *fullpath = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ /*
+ * First, find the certificate.
+ */
+ if (params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * If the caller already sent the raw keys and certs,
+ * shortcut the search and just export that
+ * data.
+ *
+ * One *may* export a key OR a cert by itself.
+ */
+ if (certlist != NULL || keylist != NULL) {
+ rv = ExportPK12FromRawData(handle,
+ &params->p12cred,
+ numcerts, certlist,
+ numkeys, keylist,
+ filename);
+ return (rv);
+ }
+
+ if (params->sslparms.certfile != NULL) {
+ fullpath = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.certfile);
+
+ if (fullpath == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (isdir(fullpath)) {
+ free(fullpath);
+ return (KMF_ERR_AMBIGUOUS_PATHNAME);
+ }
+
+ (void *)memset(&fcargs, 0, sizeof (fcargs));
+ fcargs.kstype = params->kstype;
+ fcargs.certLabel = params->certLabel;
+ fcargs.issuer = params->issuer;
+ fcargs.subject = params->subject;
+ fcargs.serial = params->serial;
+ fcargs.idstr = params->idstr;
+ fcargs.sslparms.dirpath = NULL;
+ fcargs.sslparms.certfile = fullpath;
+ fcargs.sslparms.format = params->sslparms.format;
+
+ rv = load_X509cert(kmfh, &fcargs, fullpath, &xcert);
+ if (rv != KMF_OK)
+ goto end;
+ }
+
+ /*
+ * Now find the private key.
+ */
+ if (params->sslparms.keyfile != NULL) {
+ fullpath = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.keyfile);
+
+ if (fullpath == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (isdir(fullpath)) {
+ free(fullpath);
+ return (KMF_ERR_AMBIGUOUS_PATHNAME);
+ }
+
+ pkey = openssl_load_key(handle, fullpath);
+ if (pkey == NULL) {
+ rv = KMF_ERR_KEY_NOT_FOUND;
+ goto end;
+ }
+ }
+
+ /*
+ * Open the output file.
+ */
+ if ((bio = BIO_new_file(filename, "wb")) == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ /* Stick the key and the cert into a PKCS#12 file */
+ rv = write_pkcs12(kmfh, bio, &params->p12cred,
+ pkey, xcert);
+
+end:
+ if (fullpath)
+ free(fullpath);
+ if (xcert)
+ X509_free(xcert);
+ if (pkey)
+ EVP_PKEY_free(pkey);
+ if (bio)
+ (void) BIO_free(bio);
+
+ return (rv);
+}
+
+/*
+ * Helper function to decrypt and parse PKCS#12 import file.
+ */
+static KMF_RETURN
+extract_pkcs12(BIO *fbio, CK_UTF8CHAR *pin, CK_ULONG pinlen,
+ EVP_PKEY **priv_key, X509 **cert, STACK_OF(X509) **ca)
+/* ARGSUSED */
+{
+ PKCS12 *pk12, *pk12_tmp;
+ EVP_PKEY *temp_pkey = NULL;
+ X509 *temp_cert = NULL;
+ STACK_OF(X509) *temp_ca = NULL;
+
+ if ((pk12 = PKCS12_new()) == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+
+ if ((pk12_tmp = d2i_PKCS12_bio(fbio, &pk12)) == NULL) {
+ /* This is ok; it seems to mean there is no more to read. */
+ if (ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_ASN1 &&
+ ERR_GET_REASON(ERR_peek_error()) == ASN1_R_HEADER_TOO_LONG)
+ goto end_extract_pkcs12;
+
+ PKCS12_free(pk12);
+ return (KMF_ERR_PKCS12_FORMAT);
+ }
+ pk12 = pk12_tmp;
+
+ if (PKCS12_parse(pk12, (char *)pin, &temp_pkey, &temp_cert,
+ &temp_ca) <= 0) {
+ PKCS12_free(pk12);
+ return (KMF_ERR_PKCS12_FORMAT);
+ }
+
+end_extract_pkcs12:
+
+ *priv_key = temp_pkey;
+ *cert = temp_cert;
+ *ca = temp_ca;
+
+ PKCS12_free(pk12);
+ return (KMF_OK);
+}
+
+static KMF_RETURN
+sslBN2KMFBN(BIGNUM *from, KMF_BIGINT *to)
+{
+ KMF_RETURN rv = KMF_OK;
+ uint32_t sz;
+
+ sz = BN_num_bytes(from);
+ to->val = (uchar_t *)malloc(sz);
+ if (to->val == NULL)
+ return (KMF_ERR_MEMORY);
+
+ if ((to->len = BN_bn2bin(from, to->val)) != sz) {
+ free(to->val);
+ to->val = NULL;
+ to->len = 0;
+ rv = KMF_ERR_MEMORY;
+ }
+
+ return (rv);
+}
+
+static KMF_RETURN
+exportRawRSAKey(RSA *rsa, KMF_RAW_KEY_DATA *key)
+{
+ KMF_RETURN rv;
+ KMF_RAW_RSA_KEY *kmfkey = &key->rawdata.rsa;
+
+ (void) memset(kmfkey, 0, sizeof (KMF_RAW_RSA_KEY));
+ if ((rv = sslBN2KMFBN(rsa->n, &kmfkey->mod)) != KMF_OK)
+ goto cleanup;
+
+ if ((rv = sslBN2KMFBN(rsa->e, &kmfkey->pubexp)) != KMF_OK)
+ goto cleanup;
+
+ if (rsa->d != NULL)
+ if ((rv = sslBN2KMFBN(rsa->d, &kmfkey->priexp)) != KMF_OK)
+ goto cleanup;
+
+ if (rsa->p != NULL)
+ if ((rv = sslBN2KMFBN(rsa->p, &kmfkey->prime1)) != KMF_OK)
+ goto cleanup;
+
+ if (rsa->q != NULL)
+ if ((rv = sslBN2KMFBN(rsa->q, &kmfkey->prime2)) != KMF_OK)
+ goto cleanup;
+
+ if (rsa->dmp1 != NULL)
+ if ((rv = sslBN2KMFBN(rsa->dmp1, &kmfkey->exp1)) != KMF_OK)
+ goto cleanup;
+
+ if (rsa->dmq1 != NULL)
+ if ((rv = sslBN2KMFBN(rsa->dmq1, &kmfkey->exp2)) != KMF_OK)
+ goto cleanup;
+
+ if (rsa->iqmp != NULL)
+ if ((rv = sslBN2KMFBN(rsa->iqmp, &kmfkey->coef)) != KMF_OK)
+ goto cleanup;
+cleanup:
+ if (rv != KMF_OK)
+ KMF_FreeRawKey(key);
+ else
+ key->keytype = KMF_RSA;
+
+ /*
+ * Free the reference to this key, SSL will not actually free
+ * the memory until the refcount == 0, so this is safe.
+ */
+ RSA_free(rsa);
+
+ return (rv);
+}
+
+static KMF_RETURN
+exportRawDSAKey(DSA *dsa, KMF_RAW_KEY_DATA *key)
+{
+ KMF_RETURN rv;
+ KMF_RAW_DSA_KEY *kmfkey = &key->rawdata.dsa;
+
+ (void) memset(kmfkey, 0, sizeof (KMF_RAW_DSA_KEY));
+ if ((rv = sslBN2KMFBN(dsa->p, &kmfkey->prime)) != KMF_OK)
+ goto cleanup;
+
+ if ((rv = sslBN2KMFBN(dsa->q, &kmfkey->subprime)) != KMF_OK)
+ goto cleanup;
+
+ if ((rv = sslBN2KMFBN(dsa->g, &kmfkey->base)) != KMF_OK)
+ goto cleanup;
+
+ if ((rv = sslBN2KMFBN(dsa->priv_key, &kmfkey->value)) != KMF_OK)
+ goto cleanup;
+
+cleanup:
+ if (rv != KMF_OK)
+ KMF_FreeRawKey(key);
+ else
+ key->keytype = KMF_DSA;
+
+ /*
+ * Free the reference to this key, SSL will not actually free
+ * the memory until the refcount == 0, so this is safe.
+ */
+ DSA_free(dsa);
+
+ return (rv);
+}
+
+static KMF_RETURN
+add_cert_to_list(KMF_HANDLE *kmfh, X509 *sslcert,
+ KMF_DATA **certlist, int *ncerts)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_DATA *list = (*certlist);
+ KMF_DATA cert;
+ int n = (*ncerts);
+
+ if (list == NULL) {
+ list = (KMF_DATA *)malloc(sizeof (KMF_DATA));
+ } else {
+ list = (KMF_DATA *)realloc(list, sizeof (KMF_DATA) * (n + 1));
+ }
+
+ if (list == NULL)
+ return (KMF_ERR_MEMORY);
+
+ rv = ssl_cert2KMFDATA(kmfh, sslcert, &cert);
+ if (rv == KMF_OK) {
+ list[n] = cert;
+ (*ncerts) = n + 1;
+
+ *certlist = list;
+ } else {
+ free(list);
+ }
+
+ return (rv);
+}
+
+static KMF_RETURN
+add_key_to_list(KMF_RAW_KEY_DATA **keylist,
+ KMF_RAW_KEY_DATA *newkey, int *nkeys)
+{
+ KMF_RAW_KEY_DATA *list = (*keylist);
+ int n = (*nkeys);
+
+ if (list == NULL) {
+ list = (KMF_RAW_KEY_DATA *)malloc(sizeof (KMF_RAW_KEY_DATA));
+ } else {
+ list = (KMF_RAW_KEY_DATA *)realloc(list,
+ sizeof (KMF_RAW_KEY_DATA) * (n + 1));
+ }
+
+ if (list == NULL)
+ return (KMF_ERR_MEMORY);
+
+ list[n] = *newkey;
+ (*nkeys) = n + 1;
+
+ *keylist = list;
+
+ return (KMF_OK);
+}
+
+
+static KMF_RETURN
+convertPK12Objects(
+ KMF_HANDLE *kmfh,
+ EVP_PKEY *sslkey, X509 *sslcert, STACK_OF(X509) *sslcacerts,
+ KMF_RAW_KEY_DATA **keylist, int *nkeys,
+ KMF_DATA **certlist, int *ncerts)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_RAW_KEY_DATA key;
+ int i;
+
+ if (sslkey != NULL) {
+ /* Convert SSL key to raw key */
+ switch (sslkey->type) {
+ case EVP_PKEY_RSA:
+ rv = exportRawRSAKey(EVP_PKEY_get1_RSA(sslkey),
+ &key);
+ if (rv != KMF_OK)
+ return (rv);
+
+ break;
+ case EVP_PKEY_DSA:
+ rv = exportRawDSAKey(EVP_PKEY_get1_DSA(sslkey),
+ &key);
+ if (rv != KMF_OK)
+ return (rv);
+
+ break;
+ default:
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ rv = add_key_to_list(keylist, &key, nkeys);
+ if (rv != KMF_OK)
+ return (rv);
+ }
+
+ /* Now add the certificate to the certlist */
+ if (sslcert != NULL) {
+ rv = add_cert_to_list(kmfh, sslcert, certlist, ncerts);
+ if (rv != KMF_OK)
+ return (rv);
+ }
+
+ /* Also add any included CA certs to the list */
+ for (i = 0; i != sk_X509_num(sslcacerts); i++) {
+ X509 *c;
+ /*
+ * sk_X509_value() is macro that embeds a cast to (X509 *).
+ * Here it translates into ((X509 *)sk_value((ca), (i))).
+ * Lint is complaining about the embedded casting, and
+ * to fix it, you need to fix openssl header files.
+ */
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ c = sk_X509_value(sslcacerts, i);
+
+ /* Now add the ca cert to the certlist */
+ rv = add_cert_to_list(kmfh, c, certlist, ncerts);
+ if (rv != KMF_OK)
+ return (rv);
+ }
+ return (rv);
+}
+
+KMF_RETURN
+openssl_read_pkcs12(KMF_HANDLE *kmfh,
+ char *filename, KMF_CREDENTIAL *cred,
+ KMF_DATA **certlist, int *ncerts,
+ KMF_RAW_KEY_DATA **keylist, int *nkeys)
+{
+ KMF_RETURN rv = KMF_OK;
+ BIO *bio = NULL;
+ EVP_PKEY *privkey = NULL;
+ X509 *cert = NULL;
+ STACK_OF(X509) *cacerts = NULL;
+
+ bio = BIO_new_file(filename, "rb");
+ if (bio == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_OPEN_FILE;
+ goto end;
+ }
+
+ *certlist = NULL;
+ *keylist = NULL;
+ *ncerts = 0;
+ *nkeys = 0;
+ while (rv == KMF_OK) {
+ rv = extract_pkcs12(bio,
+ (uchar_t *)cred->cred,
+ (uint32_t)cred->credlen,
+ &privkey, &cert, &cacerts);
+
+ /* Reached end of import file? */
+ if (rv == KMF_OK && privkey == NULL &&
+ cert == NULL && cacerts == NULL)
+ break;
+
+ if (rv == KMF_OK)
+ /* Convert keys and certs to exportable format */
+ rv = convertPK12Objects(kmfh, privkey, cert, cacerts,
+ keylist, nkeys, certlist, ncerts);
+
+ if (privkey)
+ EVP_PKEY_free(privkey);
+
+ if (cert)
+ X509_free(cert);
+
+ if (cacerts)
+ sk_X509_free(cacerts);
+ }
+end:
+ if (bio != NULL)
+ (void) BIO_free(bio);
+
+ if (privkey)
+ EVP_PKEY_free(privkey);
+
+ if (cert)
+ X509_free(cert);
+
+ if (cacerts)
+ sk_X509_free(cacerts);
+
+ return (rv);
+}
+
+KMF_RETURN
+OpenSSL_StorePrivateKey(KMF_HANDLE_T handle, KMF_STOREKEY_PARAMS *params,
+ KMF_RAW_KEY_DATA *key)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ char *fullpath;
+ EVP_PKEY *pkey = NULL;
+ BIO *bio = NULL;
+
+ if (key != NULL) {
+ if (key->keytype == KMF_RSA) {
+ pkey = ImportRawRSAKey(&key->rawdata.rsa);
+ } else if (key->keytype == KMF_DSA) {
+ pkey = ImportRawDSAKey(&key->rawdata.dsa);
+ } else {
+ rv = KMF_ERR_BAD_PARAMETER;
+ }
+ } else {
+ rv = KMF_ERR_BAD_PARAMETER;
+ }
+ if (rv != KMF_OK || pkey == NULL)
+ return (rv);
+
+ fullpath = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.keyfile);
+
+ if (fullpath == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* If the requested file exists, return an error */
+ if (access(fullpath, F_OK) == 0) {
+ free(fullpath);
+ return (KMF_ERR_DUPLICATE_KEYFILE);
+ }
+
+ bio = BIO_new_file(fullpath, "wb");
+ if (bio == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ rv = KMF_ERR_OPEN_FILE;
+ goto cleanup;
+ }
+
+ rv = ssl_write_private_key(kmfh,
+ params->sslparms.format,
+ bio, &params->cred, pkey);
+
+cleanup:
+ if (fullpath)
+ free(fullpath);
+
+ if (pkey)
+ EVP_PKEY_free(pkey);
+
+ if (bio)
+ (void) BIO_free(bio);
+
+ /* Protect the file by making it read-only */
+ if (rv == KMF_OK) {
+ (void) chmod(fullpath, 0400);
+ }
+ return (rv);
+}
+
+static KMF_RETURN
+create_deskey(DES_cblock **deskey)
+{
+ DES_cblock *key;
+
+ key = (DES_cblock *) malloc(sizeof (DES_cblock));
+ if (key == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+
+ if (DES_random_key(key) == 0) {
+ free(key);
+ return (KMF_ERR_KEYGEN_FAILED);
+ }
+
+ *deskey = key;
+ return (KMF_OK);
+}
+
+#define KEYGEN_RETRY 3
+#define DES3_KEY_SIZE 24
+
+static KMF_RETURN
+create_des3key(unsigned char **des3key)
+{
+ KMF_RETURN ret = KMF_OK;
+ DES_cblock *deskey1 = NULL;
+ DES_cblock *deskey2 = NULL;
+ DES_cblock *deskey3 = NULL;
+ unsigned char *newkey = NULL;
+ int retry;
+
+ if ((newkey = malloc(DES3_KEY_SIZE)) == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+
+ /* create the 1st DES key */
+ if ((ret = create_deskey(&deskey1)) != KMF_OK) {
+ goto out;
+ }
+
+ /*
+ * Create the 2nd DES key and make sure its value is different
+ * from the 1st DES key.
+ */
+ retry = 0;
+ do {
+ if (deskey2 != NULL) {
+ free(deskey2);
+ deskey2 = NULL;
+ }
+
+ if ((ret = create_deskey(&deskey2)) != KMF_OK) {
+ goto out;
+ }
+
+ if (memcmp((const void *) deskey1, (const void *) deskey2, 8)
+ == 0) {
+ ret = KMF_ERR_KEYGEN_FAILED;
+ retry++;
+ }
+ } while (ret == KMF_ERR_KEYGEN_FAILED && retry < KEYGEN_RETRY);
+
+ if (ret != KMF_OK) {
+ goto out;
+ }
+
+ /*
+ * Create the 3rd DES key and make sure its value is different
+ * from the 2nd DES key.
+ */
+ retry = 0;
+ do {
+ if (deskey3 != NULL) {
+ free(deskey3);
+ deskey3 = NULL;
+ }
+
+ if ((ret = create_deskey(&deskey3)) != KMF_OK) {
+ goto out;
+ }
+
+ if (memcmp((const void *)deskey2, (const void *)deskey3, 8)
+ == 0) {
+ ret = KMF_ERR_KEYGEN_FAILED;
+ retry++;
+ }
+ } while (ret == KMF_ERR_KEYGEN_FAILED && retry < KEYGEN_RETRY);
+
+ if (ret != KMF_OK) {
+ goto out;
+ }
+
+ /* Concatenate 3 DES keys into a DES3 key */
+ (void) memcpy((void *)newkey, (const void *)deskey1, 8);
+ (void) memcpy((void *)(newkey + 8), (const void *)deskey2, 8);
+ (void) memcpy((void *)(newkey + 16), (const void *)deskey3, 8);
+ *des3key = newkey;
+
+out:
+ if (deskey1 != NULL)
+ free(deskey1);
+
+ if (deskey2 != NULL)
+ free(deskey2);
+
+ if (deskey3 != NULL)
+ free(deskey3);
+
+ if (ret != KMF_OK && newkey != NULL)
+ free(newkey);
+
+ return (ret);
+}
+
+KMF_RETURN
+OpenSSL_CreateSymKey(KMF_HANDLE_T handle, KMF_CREATESYMKEY_PARAMS *params,
+ KMF_KEY_HANDLE *symkey)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ char *fullpath = NULL;
+ KMF_RAW_SYM_KEY *rkey = NULL;
+ DES_cblock *deskey = NULL;
+ unsigned char *des3key = NULL;
+ unsigned char *random = NULL;
+ int fd = -1;
+
+ if (kmfh == NULL)
+ return (KMF_ERR_UNINITIALIZED);
+
+ if (params == NULL || params->sslparms.keyfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ fullpath = get_fullpath(params->sslparms.dirpath,
+ params->sslparms.keyfile);
+ if (fullpath == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* If the requested file exists, return an error */
+ if (access(fullpath, F_OK) == 0) {
+ free(fullpath);
+ return (KMF_ERR_DUPLICATE_KEYFILE);
+ }
+
+ fd = open(fullpath, O_CREAT|O_TRUNC|O_RDWR, 0400);
+ if (fd == -1) {
+ ret = KMF_ERR_OPEN_FILE;
+ goto out;
+ }
+
+ rkey = malloc(sizeof (KMF_RAW_SYM_KEY));
+ if (rkey == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+ (void) memset(rkey, 0, sizeof (KMF_RAW_SYM_KEY));
+
+ if (params->keytype == KMF_DES) {
+ if ((ret = create_deskey(&deskey)) != KMF_OK) {
+ goto out;
+ }
+ rkey->keydata.val = (uchar_t *)deskey;
+ rkey->keydata.len = 8;
+
+ symkey->keyalg = KMF_DES;
+
+ } else if (params->keytype == KMF_DES3) {
+ if ((ret = create_des3key(&des3key)) != KMF_OK) {
+ goto out;
+ }
+ rkey->keydata.val = (uchar_t *)des3key;
+ rkey->keydata.len = DES3_KEY_SIZE;
+ symkey->keyalg = KMF_DES3;
+
+ } else if (params->keytype == KMF_AES || params->keytype == KMF_RC4) {
+ int bytes;
+
+ if (params->keylength % 8 != 0) {
+ ret = KMF_ERR_BAD_KEY_SIZE;
+ goto out;
+ }
+
+ if (params->keytype == KMF_AES) {
+ if (params->keylength != 128 &&
+ params->keylength != 192 &&
+ params->keylength != 256) {
+ ret = KMF_ERR_BAD_KEY_SIZE;
+ goto out;
+ }
+ }
+
+ bytes = params->keylength/8;
+ random = malloc(bytes);
+ if (random == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+ if (RAND_bytes(random, bytes) != 1) {
+ ret = KMF_ERR_KEYGEN_FAILED;
+ goto out;
+ }
+
+ rkey->keydata.val = (uchar_t *)random;
+ rkey->keydata.len = bytes;
+ symkey->keyalg = params->keytype;
+
+ } else {
+ ret = KMF_ERR_BAD_KEY_TYPE;
+ goto out;
+ }
+
+ (void) write(fd, (const void *) rkey->keydata.val, rkey->keydata.len);
+
+ symkey->kstype = KMF_KEYSTORE_OPENSSL;
+ symkey->keyclass = KMF_SYMMETRIC;
+ symkey->keylabel = (char *)fullpath;
+ symkey->israw = TRUE;
+ symkey->keyp = rkey;
+
+out:
+ if (fd != -1)
+ (void) close(fd);
+
+ if (ret != KMF_OK && fullpath != NULL) {
+ free(fullpath);
+ }
+ if (ret != KMF_OK) {
+ KMF_FreeRawSymKey(rkey);
+ symkey->keyp = NULL;
+ symkey->keyalg = KMF_KEYALG_NONE;
+ }
+
+ return (ret);
+}
+
+
+KMF_RETURN
+OpenSSL_VerifyCRLFile(KMF_HANDLE_T handle, KMF_VERIFYCRL_PARAMS *params)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ BIO *bcrl = NULL;
+ X509_CRL *xcrl = NULL;
+ X509 *xcert = NULL;
+ EVP_PKEY *pkey;
+ int sslret;
+ KMF_ENCODE_FORMAT crl_format;
+ unsigned char *p;
+ long len;
+
+ if (params->crl_name == NULL || params->tacert == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ ret = KMF_GetFileFormat(params->crl_name, &crl_format);
+ if (ret != KMF_OK)
+ return (ret);
+
+ bcrl = BIO_new_file(params->crl_name, "rb");
+ if (bcrl == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto cleanup;
+ }
+
+ if (crl_format == KMF_FORMAT_ASN1) {
+ xcrl = d2i_X509_CRL_bio(bcrl, NULL);
+ } else if (crl_format == KMF_FORMAT_PEM) {
+ xcrl = PEM_read_bio_X509_CRL(bcrl, NULL, NULL, NULL);
+ } else {
+ ret = KMF_ERR_BAD_PARAMETER;
+ goto cleanup;
+ }
+
+ if (xcrl == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_BAD_CRLFILE;
+ goto cleanup;
+ }
+
+ p = params->tacert->Data;
+ len = params->tacert->Length;
+ xcert = d2i_X509(NULL, (const uchar_t **)&p, len);
+
+ if (xcert == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_BAD_CERTFILE;
+ goto cleanup;
+ }
+
+ /* Get issuer certificate public key */
+ pkey = X509_get_pubkey(xcert);
+ if (!pkey) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ /* Verify CRL signature */
+ sslret = X509_CRL_verify(xcrl, pkey);
+ EVP_PKEY_free(pkey);
+ if (sslret > 0) {
+ ret = KMF_OK;
+ } else {
+ SET_ERROR(kmfh, sslret);
+ ret = KMF_ERR_BAD_CRLFILE;
+ }
+
+cleanup:
+ if (bcrl != NULL)
+ (void) BIO_free(bcrl);
+
+ if (xcrl != NULL)
+ X509_CRL_free(xcrl);
+
+ if (xcert != NULL)
+ X509_free(xcert);
+
+ return (ret);
+
+}
+
+KMF_RETURN
+OpenSSL_CheckCRLDate(KMF_HANDLE_T handle,
+ KMF_CHECKCRLDATE_PARAMS *params)
+{
+
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_ENCODE_FORMAT crl_format;
+ BIO *bcrl = NULL;
+ X509_CRL *xcrl = NULL;
+ int i;
+
+ if (params == NULL || params->crl_name == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ ret = KMF_IsCRLFile(handle, params->crl_name, &crl_format);
+ if (ret != KMF_OK)
+ return (ret);
+
+ bcrl = BIO_new_file(params->crl_name, "rb");
+ if (bcrl == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto cleanup;
+ }
+
+ if (crl_format == KMF_FORMAT_ASN1) {
+ xcrl = d2i_X509_CRL_bio(bcrl, NULL);
+ } else if (crl_format == KMF_FORMAT_PEM) {
+ xcrl = PEM_read_bio_X509_CRL(bcrl, NULL, NULL, NULL);
+ }
+
+ if (xcrl == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_BAD_CRLFILE;
+ goto cleanup;
+ }
+
+ i = X509_cmp_time(X509_CRL_get_lastUpdate(xcrl), NULL);
+ if (i >= 0) {
+ ret = KMF_ERR_VALIDITY_PERIOD;
+ goto cleanup;
+ }
+
+ if (X509_CRL_get_nextUpdate(xcrl)) {
+ i = X509_cmp_time(X509_CRL_get_nextUpdate(xcrl), NULL);
+
+ if (i <= 0) {
+ ret = KMF_ERR_VALIDITY_PERIOD;
+ goto cleanup;
+ }
+ }
+
+ ret = KMF_OK;
+
+cleanup:
+ if (bcrl != NULL)
+ (void) BIO_free(bcrl);
+
+ if (xcrl != NULL)
+ X509_CRL_free(xcrl);
+
+ return (ret);
+}
+
+/*
+ * Check a file to see if it is a CRL file with PEM or DER format.
+ * If success, return its format in the "pformat" argument.
+ */
+KMF_RETURN
+OpenSSL_IsCRLFile(KMF_HANDLE_T handle, char *filename, int *pformat)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ BIO *bio = NULL;
+ X509_CRL *xcrl = NULL;
+
+ if (filename == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ bio = BIO_new_file(filename, "rb");
+ if (bio == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto out;
+ }
+
+ if ((xcrl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL)) != NULL) {
+ *pformat = KMF_FORMAT_PEM;
+ goto out;
+ }
+ (void) BIO_free(bio);
+
+ /*
+ * Now try to read it as raw DER data.
+ */
+ bio = BIO_new_file(filename, "rb");
+ if (bio == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto out;
+ }
+
+ if ((xcrl = d2i_X509_CRL_bio(bio, NULL)) != NULL) {
+ *pformat = KMF_FORMAT_ASN1;
+ } else {
+ ret = KMF_ERR_BAD_CRLFILE;
+ }
+
+out:
+ if (bio != NULL)
+ (void) BIO_free(bio);
+
+ if (xcrl != NULL)
+ X509_CRL_free(xcrl);
+
+ return (ret);
+}
+
+/*
+ * Check a file to see if it is a certficate file with PEM or DER format.
+ * If success, return its format in the pformat argument.
+ */
+KMF_RETURN
+OpenSSL_IsCertFile(KMF_HANDLE_T handle, char *filename,
+ KMF_ENCODE_FORMAT *pformat)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ BIO *bio = NULL;
+ X509 *xcert = NULL;
+
+ if (filename == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ ret = KMF_GetFileFormat(filename, pformat);
+ if (ret != KMF_OK)
+ return (ret);
+
+ bio = BIO_new_file(filename, "rb");
+ if (bio == NULL) {
+ SET_ERROR(kmfh, ERR_get_error());
+ ret = KMF_ERR_OPEN_FILE;
+ goto out;
+ }
+
+ if ((*pformat) == KMF_FORMAT_PEM) {
+ if ((xcert = PEM_read_bio_X509(bio, NULL,
+ NULL, NULL)) == NULL) {
+ ret = KMF_ERR_BAD_CERTFILE;
+ }
+ } else if ((*pformat) == KMF_FORMAT_ASN1) {
+ if ((xcert = d2i_X509_bio(bio, NULL)) == NULL) {
+ ret = KMF_ERR_BAD_CERTFILE;
+ }
+ } else {
+ ret = KMF_ERR_BAD_CERTFILE;
+ }
+
+out:
+ if (bio != NULL)
+ (void) BIO_free(bio);
+
+ if (xcert != NULL)
+ X509_free(xcert);
+
+ return (ret);
+}
+
+KMF_RETURN
+OpenSSL_GetSymKeyValue(KMF_HANDLE_T handle, KMF_KEY_HANDLE *symkey,
+ KMF_RAW_SYM_KEY *rkey)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_DATA keyvalue;
+
+ if (kmfh == NULL)
+ return (KMF_ERR_UNINITIALIZED);
+
+ if (symkey == NULL || rkey == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+ else if (symkey->keyclass != KMF_SYMMETRIC)
+ return (KMF_ERR_BAD_KEY_CLASS);
+
+ if (symkey->israw) {
+ KMF_RAW_SYM_KEY *rawkey = (KMF_RAW_SYM_KEY *)symkey->keyp;
+
+ if (rawkey == NULL ||
+ rawkey->keydata.val == NULL ||
+ rawkey->keydata.len == 0)
+ return (KMF_ERR_BAD_KEYHANDLE);
+
+ rkey->keydata.len = rawkey->keydata.len;
+ if ((rkey->keydata.val = malloc(rkey->keydata.len)) == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memcpy(rkey->keydata.val, rawkey->keydata.val,
+ rkey->keydata.len);
+ } else {
+ rv = KMF_ReadInputFile(handle, symkey->keylabel, &keyvalue);
+ if (rv != KMF_OK)
+ return (rv);
+ rkey->keydata.len = keyvalue.Length;
+ rkey->keydata.val = keyvalue.Data;
+ }
+
+ return (rv);
+}
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/i386/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/i386/Makefile
new file mode 100644
index 0000000000..443f78537a
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/i386/Makefile
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: $(ROOTLIBS)
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/sparc/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/sparc/Makefile
new file mode 100644
index 0000000000..472ac90a9a
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/sparc/Makefile
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: $(ROOTLIBS)
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/sparcv9/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/sparcv9/Makefile
new file mode 100644
index 0000000000..e80bb3751a
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/sparcv9/Makefile
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../../Makefile.lib.64
+
+LDLIBS += $(OPENSSLLIBS64)
+install: $(ROOTLIBS64)