summaryrefslogtreecommitdiff
path: root/usr/src/lib/libkmf/plugins
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
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')
-rw-r--r--usr/src/lib/libkmf/plugins/Makefile48
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_nss/Makefile47
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_nss/Makefile.com74
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_nss/amd64/Makefile32
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_nss/common/mapfile-vers56
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c2508
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_nss/i386/Makefile29
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_nss/sparc/Makefile29
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_nss/sparcv9/Makefile32
-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
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile46
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile.com65
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_pkcs11/amd64/Makefile30
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_pkcs11/common/mapfile-vers50
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c2945
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_pkcs11/i386/Makefile29
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_pkcs11/sparc/Makefile29
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_pkcs11/sparcv9/Makefile30
25 files changed, 10583 insertions, 0 deletions
diff --git a/usr/src/lib/libkmf/plugins/Makefile b/usr/src/lib/libkmf/plugins/Makefile
new file mode 100644
index 0000000000..5b27f7e6da
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/Makefile
@@ -0,0 +1,48 @@
+#
+# 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"
+#
+# KMF Prototype Makefile
+#
+include ../../Makefile.lib
+
+SUBDIRS = kmf_nss kmf_openssl kmf_pkcs11
+
+HDRS=
+HDRDIR= include
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+all clean clobber install lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/Makefile
new file mode 100644
index 0000000000..5c60729ece
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_nss/Makefile
@@ -0,0 +1,47 @@
+#
+# 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_nss/Makefile.com b/usr/src/lib/libkmf/plugins/kmf_nss/Makefile.com
new file mode 100644
index 0000000000..30209c69f9
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_nss/Makefile.com
@@ -0,0 +1,74 @@
+#
+# 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_nss.a
+VERS= .1
+
+OBJECTS= nss_spi.o
+
+include $(SRC)/lib/Makefile.lib
+
+MPSDIR= /usr/lib/mps
+KMFINC= -I../../../include -I../../../ber_der/inc
+NSSINC= -I/usr/include/mps
+BERLIB= -lkmf -lkmfberder
+BERLIB64= $(BERLIB)
+
+NSSLIBS= $(BERLIB) -L$(MPSDIR) -R$(MPSDIR) -lnss3 -lnspr4 -lsmime3 -lc
+NSSLIBS64= $(BERLIB64) -L$(MPSDIR)/$(MACH64) -R$(MPSDIR)/$(MACH64) -lnss3 -lnspr4 -lsmime3 -lc
+
+SRCDIR= ../common
+INCDIR= ../../include
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -D_REENTRANT $(KMFINC) $(NSSINC) \
+ -I$(SFWDIR)/include -I$(INCDIR) -I/usr/include/libxml2
+
+PICS= $(OBJECTS:%=pics/%)
+
+lint:= NSSLIBS = $(BERLIB)
+lint:= NSSLIBS64 = $(BERLIB64)
+
+LDLIBS32 += $(NSSLIBS)
+
+LIBS = $(DYNLIB)
+
+ROOTLIBDIR= $(ROOT)/usr/lib/security
+ROOTLIBDIR64= $(ROOT)/usr/lib/security/$(MACH64)
+
+
+.KEEP_STATE:
+
+all: $(LIBS) $(LINTLIB)
+
+lint: lintcheck
+
+FRC:
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/amd64/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/amd64/Makefile
new file mode 100644
index 0000000000..aa52c4aefb
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_nss/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
+
+LDLIBS64 += $(NSSLIBS64)
+
+install: $(ROOTLIBS64)
diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/common/mapfile-vers b/usr/src/lib/libkmf/plugins/kmf_nss/common/mapfile-vers
new file mode 100644
index 0000000000..ed84774842
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_nss/common/mapfile-vers
@@ -0,0 +1,56 @@
+#
+# 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;
+ NSS_FindCert;
+ NSS_FreeKMFCert;
+ NSS_StoreCert;
+ NSS_ImportCert;
+ NSS_ImportCRL;
+ NSS_DeleteCert;
+ NSS_DeleteCRL;
+ NSS_CreateKeypair;
+ NSS_FindKey;
+ NSS_EncodePubKeyData;
+ NSS_SignData;
+ NSS_DeleteKey;
+ NSS_FindCRL;
+ NSS_FindCertInCRL;
+ NSS_GetErrorString;
+ NSS_GetPrikeyByCert;
+ NSS_DecryptData;
+ NSS_ExportP12;
+ NSS_StorePrivateKey;
+ NSS_CreateSymKey;
+ NSS_GetSymKeyValue;
+ NSS_SetTokenPin;
+
+ local:
+ *;
+};
diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c b/usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c
new file mode 100644
index 0000000000..b23886aaae
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c
@@ -0,0 +1,2508 @@
+/*
+ * 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
+ */
+/*
+ * NSS keystore wrapper
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <synch.h>
+
+#include <kmfapiP.h>
+#include <ber_der.h>
+#include <oidsalg.h>
+/* NSS related headers */
+
+#include <mps/nss.h>
+#include <mps/cert.h>
+#include <mps/certdb.h>
+#include <mps/secoid.h>
+#include <mps/secder.h>
+#include <mps/secerr.h>
+#include <mps/cryptohi.h>
+#include <mps/keyhi.h>
+#include <mps/keythi.h>
+#include <mps/pk11func.h>
+#include <mps/pk11pqg.h>
+#include <mps/pkcs12.h>
+#include <mps/p12plcy.h>
+#include <mps/prerror.h>
+
+#define NSS_OK 0
+
+mutex_t init_lock = DEFAULTMUTEX;
+static int nss_initialized = 0;
+
+KMF_RETURN
+NSS_ConfigureKeystore(KMF_HANDLE_T, KMF_CONFIG_PARAMS *);
+
+KMF_RETURN
+NSS_FindCert(KMF_HANDLE_T,
+ KMF_FINDCERT_PARAMS *params,
+ KMF_X509_DER_CERT *kmf_cert,
+ uint32_t *num_certs);
+
+void
+NSS_FreeKMFCert(KMF_HANDLE_T, KMF_X509_DER_CERT *);
+
+KMF_RETURN
+NSS_StoreCert(KMF_HANDLE_T, KMF_STORECERT_PARAMS *params,
+ KMF_DATA * pcert);
+
+KMF_RETURN
+NSS_ImportCert(KMF_HANDLE_T, KMF_IMPORTCERT_PARAMS *params);
+
+KMF_RETURN
+NSS_DeleteCert(KMF_HANDLE_T, KMF_DELETECERT_PARAMS *params);
+
+KMF_RETURN
+NSS_CreateKeypair(KMF_HANDLE_T, KMF_CREATEKEYPAIR_PARAMS *,
+ KMF_KEY_HANDLE *, KMF_KEY_HANDLE *);
+
+KMF_RETURN
+NSS_EncodePubKeyData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_DATA *);
+
+KMF_RETURN
+NSS_SignData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *,
+ KMF_DATA *, KMF_DATA *);
+
+KMF_RETURN
+NSS_ImportCRL(KMF_HANDLE_T, KMF_IMPORTCRL_PARAMS *params);
+
+KMF_RETURN
+NSS_DeleteCRL(KMF_HANDLE_T, KMF_DELETECRL_PARAMS *params);
+
+KMF_RETURN
+NSS_FindCRL(KMF_HANDLE_T, KMF_FINDCRL_PARAMS *params,
+ char **CRLNameList, int *CRLCount);
+
+KMF_RETURN
+NSS_FindKey(KMF_HANDLE_T, KMF_FINDKEY_PARAMS *,
+ KMF_KEY_HANDLE *, uint32_t *);
+
+KMF_RETURN
+NSS_FindCertInCRL(KMF_HANDLE_T, KMF_FINDCERTINCRL_PARAMS *params);
+
+KMF_RETURN
+NSS_GetErrorString(KMF_HANDLE_T, char **);
+
+KMF_RETURN
+NSS_DeleteKey(KMF_HANDLE_T, KMF_DELETEKEY_PARAMS *,
+ KMF_KEY_HANDLE *, boolean_t);
+
+KMF_RETURN
+NSS_GetPrikeyByCert(KMF_HANDLE_T, KMF_CRYPTOWITHCERT_PARAMS *, KMF_DATA *,
+ KMF_KEY_HANDLE *, KMF_KEY_ALG);
+
+KMF_RETURN
+NSS_DecryptData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *,
+ KMF_DATA *, KMF_DATA *);
+
+KMF_RETURN
+NSS_ExportP12(KMF_HANDLE_T,
+ KMF_EXPORTP12_PARAMS *,
+ int, KMF_X509_DER_CERT *,
+ int, KMF_KEY_HANDLE *,
+ char *);
+
+KMF_RETURN
+NSS_StorePrivateKey(KMF_HANDLE_T, KMF_STOREKEY_PARAMS *, KMF_RAW_KEY_DATA *);
+
+KMF_RETURN
+NSS_CreateSymKey(KMF_HANDLE_T, KMF_CREATESYMKEY_PARAMS *, KMF_KEY_HANDLE *);
+
+KMF_RETURN
+NSS_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_SYM_KEY *);
+
+KMF_RETURN
+NSS_SetTokenPin(KMF_HANDLE_T, KMF_SETPIN_PARAMS *, KMF_CREDENTIAL *);
+
+static
+KMF_PLUGIN_FUNCLIST nss_plugin_table =
+{
+ 1, /* Version */
+ NSS_ConfigureKeystore,
+ NSS_FindCert,
+ NSS_FreeKMFCert,
+ NSS_StoreCert,
+ NSS_ImportCert,
+ NSS_ImportCRL,
+ NSS_DeleteCert,
+ NSS_DeleteCRL,
+ NSS_CreateKeypair,
+ NSS_FindKey,
+ NSS_EncodePubKeyData,
+ NSS_SignData,
+ NSS_DeleteKey,
+ NULL /* ListCRL */,
+ NSS_FindCRL,
+ NSS_FindCertInCRL,
+ NSS_GetErrorString,
+ NSS_GetPrikeyByCert,
+ NSS_DecryptData,
+ NSS_ExportP12,
+ NSS_StorePrivateKey,
+ NSS_CreateSymKey,
+ NSS_GetSymKeyValue,
+ NSS_SetTokenPin,
+ NULL /* Finalize */
+};
+
+/* additions for importing and exporting PKCS 12 files */
+typedef struct p12uContextStr {
+ char *filename; /* name of file */
+ PRFileDesc *file; /* pointer to file */
+ PRBool error; /* error occurred? */
+ int errorValue; /* which error occurred? */
+} p12uContext;
+
+#define SET_ERROR(h, c) h->lasterr.kstype = KMF_KEYSTORE_NSS; \
+ h->lasterr.errcode = c;
+
+KMF_PLUGIN_FUNCLIST *
+KMF_Plugin_Initialize()
+{
+ SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1);
+ SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1);
+ SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
+ SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1);
+ SEC_PKCS12EnableCipher(PKCS12_DES_56, 1);
+ SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1);
+ SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1);
+
+ return (&nss_plugin_table);
+}
+
+static char *
+/*ARGSUSED*/
+nss_getpassword(PK11SlotInfo *slot, PRBool retry, void *arg)
+{
+ if (retry)
+ return (NULL);
+ if (arg != NULL)
+ return ((char *)strdup(arg));
+ else
+ return (NULL);
+}
+
+static KMF_RETURN
+nss_authenticate(KMF_HANDLE_T handle,
+ PK11SlotInfo *nss_slot, KMF_CREDENTIAL *cred)
+{
+
+ SECStatus nssrv = SECSuccess;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ /* If a password was given, try to login to the slot */
+ if (cred == NULL || cred->cred == NULL || cred->credlen == 0 ||
+ nss_slot == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ if (PK11_IsLoggedIn(nss_slot, NULL)) {
+ return (KMF_OK);
+ }
+
+ PK11_SetPasswordFunc(nss_getpassword);
+ nssrv = PK11_Authenticate(nss_slot, PR_TRUE,
+ (void *)cred->cred);
+
+ if (nssrv != SECSuccess) {
+ SET_ERROR(kmfh, nssrv);
+ PK11_FreeSlot(nss_slot);
+ return (KMF_ERR_AUTH_FAILED);
+ }
+
+ return (KMF_OK);
+}
+
+static SECStatus
+Init_NSS_DBs(const char *configdir,
+ const char *certPrefix,
+ const char *keyPrefix,
+ const char *secmodName)
+{
+ SECStatus rv = NSS_OK;
+
+ (void) mutex_lock(&init_lock);
+
+ /* If another thread already did it, return OK. */
+ if (nss_initialized) {
+ (void) mutex_unlock(&init_lock);
+ return (SECSuccess);
+ }
+
+ rv = NSS_Initialize((configdir && strlen(configdir)) ?
+ configdir : "./", certPrefix,
+ keyPrefix, secmodName ? secmodName : "secmod.db",
+ NSS_INIT_COOPERATE);
+ if (rv != SECSuccess) {
+ goto end;
+ }
+
+ nss_initialized++;
+end:
+ (void) mutex_unlock(&init_lock);
+ return (rv);
+}
+
+/*
+ * When it is called the first time, it will intialize NSS. Once the NSS
+ * is initialized, this function returns KMF_KEYSTORE_ALREADY_INITIALIZED
+ * if it is called again.
+ */
+KMF_RETURN
+NSS_ConfigureKeystore(KMF_HANDLE_T handle, KMF_CONFIG_PARAMS *params)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ if (params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) mutex_lock(&init_lock);
+ if (nss_initialized == 0) {
+ SECStatus err;
+
+ (void) mutex_unlock(&init_lock);
+ err = Init_NSS_DBs(params->nssconfig.configdir,
+ params->nssconfig.certPrefix,
+ params->nssconfig.keyPrefix,
+ params->nssconfig.secModName);
+ if (err != SECSuccess) {
+ SET_ERROR(kmfh, err);
+ return (KMF_ERR_INTERNAL);
+ }
+ } else {
+ rv = KMF_KEYSTORE_ALREADY_INITIALIZED;
+ (void) mutex_unlock(&init_lock);
+ }
+
+ return (rv);
+}
+
+
+/*
+ * This function sets up the slot to be used for other operations.
+ * This function is basically called by every NSS SPI function.
+ * For those functions that can only be performed in the internal slot, the
+ * boolean "internal_slot_only" argument needs to be TRUE.
+ * A slot pointer will be returned when this function is executed successfully.
+ */
+static KMF_RETURN
+Do_NSS_Init(
+ void *handle,
+ KMF_NSS_PARAMS nss_opts,
+ boolean_t internal_slot_only,
+ PK11SlotInfo **nss_slot)
+{
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ if (!nss_initialized)
+ return (KMF_ERR_PLUGIN_INIT);
+
+ /*
+ * NSS Is already initialized, but we need to find
+ * the right slot.
+ */
+ if (nss_opts.slotlabel == NULL ||
+ strcmp(nss_opts.slotlabel, "internal") == 0) {
+ *nss_slot = PK11_GetInternalKeySlot();
+ } else if (internal_slot_only == TRUE) {
+ return (KMF_ERR_SLOTNAME);
+ } else {
+ *nss_slot = PK11_FindSlotByName(nss_opts.slotlabel);
+ }
+
+ if (*nss_slot == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ return (KMF_ERR_SLOTNAME);
+ }
+
+ /*
+ * If the token was not yet initialized, return an error.
+ */
+ if (PK11_NeedUserInit(*nss_slot)) {
+ return (KMF_ERR_UNINITIALIZED_TOKEN);
+ }
+
+ return (KMF_OK);
+}
+
+static KMF_RETURN
+nss2kmf_cert(CERTCertificate *nss_cert, KMF_X509_DER_CERT *kmf_cert)
+{
+ kmf_cert->kmf_private.keystore_type = KMF_KEYSTORE_NSS;
+ kmf_cert->kmf_private.flags = KMF_FLAG_CERT_VALID;
+
+ kmf_cert->certificate.Length = nss_cert->derCert.len;
+
+ if ((kmf_cert->certificate.Data = malloc(nss_cert->derCert.len)) ==
+ NULL) {
+ kmf_cert->certificate.Length = 0;
+ return (KMF_ERR_MEMORY);
+ }
+ (void) memcpy(kmf_cert->certificate.Data, nss_cert->derCert.data,
+ nss_cert->derCert.len);
+ if (nss_cert->nickname != NULL)
+ kmf_cert->kmf_private.label =
+ (char *)strdup(nss_cert->nickname);
+ return (KMF_OK);
+}
+
+static KMF_RETURN
+nss_getcert_by_label(KMF_HANDLE *kmfh,
+ char *name, KMF_X509_DER_CERT *kmf_cert,
+ uint32_t *num_certs, KMF_CERT_VALIDITY find_criteria)
+{
+ KMF_RETURN rv = KMF_OK;
+ CERTCertificate *nss_cert;
+ SECCertTimeValidity validity;
+
+ nss_cert = PK11_FindCertFromNickname(name, NULL);
+ if (nss_cert == NULL) {
+ *num_certs = 0;
+ SET_ERROR(kmfh, PORT_GetError());
+ *num_certs = 0;
+ return (KMF_ERR_CERT_NOT_FOUND);
+ } else {
+ *num_certs = 1;
+ }
+
+ switch (find_criteria) {
+ case KMF_ALL_CERTS:
+ break;
+ case KMF_NONEXPIRED_CERTS:
+ validity = CERT_CheckCertValidTimes(nss_cert, PR_Now(),
+ PR_FALSE);
+ if (validity != secCertTimeValid) {
+ /* this is an invalid cert, reject it */
+ *num_certs = 0;
+ CERT_DestroyCertificate(nss_cert);
+ return (KMF_OK);
+ }
+ break;
+ case KMF_EXPIRED_CERTS:
+ validity = CERT_CheckCertValidTimes(nss_cert, PR_Now(),
+ PR_FALSE);
+ if (validity == secCertTimeValid) {
+ /* this is a valid cert, reject it in this case. */
+ *num_certs = 0;
+ CERT_DestroyCertificate(nss_cert);
+ return (KMF_OK);
+ }
+ break;
+ default:
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ if (kmf_cert != NULL)
+ rv = nss2kmf_cert(nss_cert, kmf_cert);
+
+ /* We copied the data we need, so cleanup the internal record */
+ CERT_DestroyCertificate(nss_cert);
+
+ if (rv != KMF_OK)
+ *num_certs = 0;
+
+ return (rv);
+}
+
+static KMF_RETURN
+nss_find_matching_certs(PK11SlotInfo *slot,
+ char *issuer, char *subject, KMF_BIGINT *serial,
+ CERTCertList **certlist, KMF_CERT_VALIDITY find_criteria)
+{
+ KMF_RETURN rv = KMF_OK;
+ SECStatus ret;
+ CERTCertList *list;
+ CERTCertListNode *node;
+ KMF_X509_NAME issuerDN, subjectDN;
+ boolean_t findIssuer = FALSE;
+ boolean_t findSubject = FALSE;
+ boolean_t findSerial = FALSE;
+
+ if (issuer != NULL && strlen(issuer)) {
+ rv = KMF_DNParser(issuer, &issuerDN);
+ if (rv != KMF_OK)
+ return (rv);
+ findIssuer = TRUE;
+ }
+ if (subject != NULL && strlen(subject)) {
+ rv = KMF_DNParser(subject, &subjectDN);
+ if (rv != KMF_OK)
+ return (rv);
+ findSubject = TRUE;
+ }
+ if (serial != 0 && serial->val != NULL && serial->len > 0)
+ findSerial = TRUE;
+
+ list = PK11_ListCertsInSlot(slot);
+ if (list) {
+ node = CERT_LIST_HEAD(list);
+ while (!CERT_LIST_END(node, list)) {
+ KMF_X509_NAME cmpDN;
+ KMF_DATA der;
+ boolean_t match;
+ CERTCertListNode *freenode;
+
+ if (findIssuer) {
+ der.Data = node->cert->derIssuer.data;
+ der.Length = node->cert->derIssuer.len;
+ rv = DerDecodeName(&der, &cmpDN);
+ if (rv == KMF_OK) {
+ match = !KMF_CompareRDNs(&issuerDN,
+ &cmpDN);
+ KMF_FreeDN(&cmpDN);
+ if (!match)
+ goto delete_and_cont;
+ } else {
+ goto delete_and_cont;
+ }
+ }
+ if (findSubject) {
+ der.Data = node->cert->derSubject.data;
+ der.Length = node->cert->derSubject.len;
+ rv = DerDecodeName(&der, &cmpDN);
+ if (rv == KMF_OK) {
+ match = !KMF_CompareRDNs(&subjectDN,
+ &cmpDN);
+ KMF_FreeDN(&cmpDN);
+ if (!match)
+ goto delete_and_cont;
+ } else {
+ goto delete_and_cont;
+ }
+ }
+ if (findSerial) {
+ SECItem *sernum;
+
+ sernum = &node->cert->serialNumber;
+
+ if (serial->len != sernum->len)
+ goto delete_and_cont;
+
+ if (memcmp(sernum->data, serial->val,
+ serial->len))
+ goto delete_and_cont;
+ }
+
+ /* select the certs using find criteria */
+ switch (find_criteria) {
+ case KMF_ALL_CERTS:
+ break;
+ case KMF_NONEXPIRED_CERTS:
+ ret = CERT_CertTimesValid(node->cert);
+ if (ret == SECFailure) {
+ /* this is an invalid cert */
+ goto skip;
+ }
+ break;
+
+ case KMF_EXPIRED_CERTS:
+ ret = CERT_CertTimesValid(node->cert);
+ if (ret != SECFailure) {
+ /* this is a valid cert */
+ goto skip;
+ }
+ break;
+ }
+skip:
+ node = CERT_LIST_NEXT(node);
+ continue;
+delete_and_cont:
+ freenode = node;
+ node = CERT_LIST_NEXT(node);
+ CERT_RemoveCertListNode(freenode);
+ }
+ }
+
+ if (rv == KMF_OK && certlist != NULL) {
+ *certlist = list;
+ } else {
+ CERT_DestroyCertList(list);
+ }
+ return (rv);
+}
+
+static KMF_RETURN
+convertCertList(void *kmfhandle,
+ CERTCertList *nsscerts, KMF_X509_DER_CERT *kmfcerts,
+ uint32_t *numcerts)
+{
+ KMF_RETURN rv = KMF_OK;
+ CERTCertListNode *node;
+
+ *numcerts = 0;
+
+ for (node = CERT_LIST_HEAD(nsscerts);
+ !CERT_LIST_END(node, nsscerts) && rv == KMF_OK;
+ node = CERT_LIST_NEXT(node), (*numcerts)++) {
+ if (kmfcerts != NULL)
+ rv = nss2kmf_cert(node->cert, &kmfcerts[*numcerts]);
+ }
+
+ /*
+ * If we failed, delete any certs allocated so far.
+ */
+ if (rv != KMF_OK) {
+ int i;
+ for (i = 0; i < *numcerts; i++)
+ KMF_FreeKMFCert(kmfhandle, &kmfcerts[i]);
+ }
+ return (rv);
+}
+
+KMF_RETURN
+NSS_FindCert(KMF_HANDLE_T handle, KMF_FINDCERT_PARAMS *params,
+ KMF_X509_DER_CERT *kmfcerts,
+ uint32_t *num_certs)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ PK11SlotInfo *nss_slot = NULL;
+ CERTCertList *certlist = NULL;
+
+ rv = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts, FALSE, &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ *num_certs = 0;
+ if (params->certLabel) {
+ rv = nss_getcert_by_label(kmfh,
+ params->certLabel,
+ kmfcerts, num_certs, params->find_cert_validity);
+ } else {
+ rv = nss_find_matching_certs(nss_slot,
+ params->issuer, params->subject, params->serial,
+ &certlist, params->find_cert_validity);
+
+ if (rv == KMF_OK && certlist != NULL) {
+ rv = convertCertList(handle,
+ certlist, kmfcerts, num_certs);
+ CERT_DestroyCertList(certlist);
+ }
+ }
+
+ if (nss_slot != NULL) {
+ PK11_FreeSlot(nss_slot);
+ }
+
+ if (rv == KMF_OK && *num_certs == 0)
+ rv = KMF_ERR_CERT_NOT_FOUND;
+
+ return (rv);
+}
+
+void
+/*ARGSUSED*/
+NSS_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 != NULL) {
+ free(kmf_cert->kmf_private.label);
+ kmf_cert->kmf_private.label = NULL;
+ }
+ }
+}
+
+KMF_RETURN
+NSS_StoreCert(KMF_HANDLE_T handle, KMF_STORECERT_PARAMS *params,
+ KMF_DATA *pcert)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ SECStatus nss_rv;
+ CERTCertificate *nss_cert = NULL;
+ CERTCertTrust *nss_trust = NULL;
+ PK11SlotInfo *nss_slot = NULL;
+ CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
+
+ if (pcert == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /* NSS only support DER format */
+ if (params == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ ret = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts, FALSE, &nss_slot);
+ if (ret != KMF_OK) {
+ return (ret);
+ }
+
+ nss_cert = CERT_DecodeCertFromPackage((char *)pcert->Data,
+ pcert->Length);
+ if (nss_cert == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto out;
+ }
+
+ nss_rv = PK11_ImportCert(nss_slot, nss_cert, CK_INVALID_HANDLE,
+ params->certLabel, 0);
+ if (nss_rv) {
+ SET_ERROR(kmfh, nss_rv);
+ ret = KMF_ERR_BAD_CERT_FORMAT;
+ goto out;
+ }
+
+ if (params->ks_opt_u.nss_opts.trustflag != NULL &&
+ strlen(params->ks_opt_u.nss_opts.trustflag)) {
+ nss_trust = (CERTCertTrust *) malloc(sizeof (CERTCertTrust));
+ if (nss_trust == NULL) {
+ ret = KMF_ERR_MEMORY;
+ goto out;
+ }
+ nss_rv = CERT_DecodeTrustString(nss_trust,
+ params->ks_opt_u.nss_opts.trustflag);
+ if (nss_rv) {
+ SET_ERROR(kmfh, nss_rv);
+ ret = KMF_ERR_BAD_PARAMETER;
+ goto out;
+ }
+
+ nss_rv = CERT_ChangeCertTrust(certHandle, nss_cert, nss_trust);
+ if (nss_rv) {
+ SET_ERROR(kmfh, nss_rv);
+ ret = KMF_ERR_BAD_PARAMETER;
+ }
+ }
+
+out:
+ if (nss_trust != NULL) {
+ free(nss_trust);
+ }
+
+ if (nss_cert != NULL) {
+ CERT_DestroyCertificate(nss_cert);
+ }
+
+ if (nss_slot != NULL) {
+ PK11_FreeSlot(nss_slot);
+ }
+
+ return (ret);
+}
+
+
+KMF_RETURN
+NSS_ImportCert(KMF_HANDLE_T handle, KMF_IMPORTCERT_PARAMS *params)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_STORECERT_PARAMS scparams;
+ KMF_DATA cert = {NULL, 0};
+ KMF_DATA cert_der = {NULL, 0};
+ KMF_DATA *cptr = NULL;
+ KMF_ENCODE_FORMAT format;
+
+ if (params == NULL || params->certfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /*
+ * Check if the input cert file is a valid certificate and
+ * auto-detect the file format of it.
+ */
+ ret = KMF_IsCertFile(handle, params->certfile, &format);
+ if (ret != KMF_OK)
+ return (ret);
+
+ ret = KMF_ReadInputFile(handle, params->certfile, &cert);
+ if (ret != KMF_OK) {
+ return (ret);
+ }
+
+ /*
+ * If the imported cert is in PEM format, convert it to
+ * DER format in order to store it in NSS token.
+ */
+ if (format == KMF_FORMAT_PEM) {
+ int derlen;
+ ret = KMF_Pem2Der(cert.Data, cert.Length,
+ &cert_der.Data, &derlen);
+ if (ret != KMF_OK) {
+ goto cleanup;
+ }
+ cert_der.Length = (size_t)derlen;
+ cptr = &cert_der;
+ } else {
+ cptr = &cert;
+ }
+
+ (void) memset(&scparams, 0, sizeof (scparams));
+ scparams.kstype = params->kstype;
+ scparams.certLabel = params->certLabel;
+ scparams.nssparms = params->nssparms;
+
+ ret = NSS_StoreCert(handle, &scparams, cptr);
+
+ if (format == KMF_FORMAT_PEM) {
+ KMF_FreeData(&cert_der);
+ }
+
+cleanup:
+ KMF_FreeData(&cert);
+
+ return (ret);
+}
+
+KMF_RETURN
+NSS_DeleteCert(KMF_HANDLE_T handle, KMF_DELETECERT_PARAMS *params)
+{
+ KMF_RETURN rv = KMF_OK;
+ int nssrv;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ CERTCertificate *cert = NULL;
+ PK11SlotInfo *nss_slot = NULL;
+
+ /* check params */
+ if (params == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ rv = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts,
+ FALSE, &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ if (params->certLabel) {
+ cert = PK11_FindCertFromNickname(params->certLabel, NULL);
+ if (cert == NULL) {
+ return (KMF_ERR_CERT_NOT_FOUND);
+ }
+
+ switch (params->find_cert_validity) {
+ case KMF_ALL_CERTS:
+ break;
+ case KMF_NONEXPIRED_CERTS:
+ nssrv = CERT_CertTimesValid(cert);
+ if (nssrv == SECFailure) {
+ /* this is an invalid cert - skip it */
+ goto out;
+ }
+ break;
+ case KMF_EXPIRED_CERTS:
+ nssrv = CERT_CertTimesValid(cert);
+ if (nssrv != SECFailure) {
+ /* this is a valid cert - skip it */
+ goto out;
+ }
+ break;
+ }
+ /* delete it from database */
+ nssrv = SEC_DeletePermCertificate(cert);
+ if (nssrv) {
+ SET_ERROR(kmfh, nssrv);
+ rv = KMF_ERR_INTERNAL;
+ }
+ } else {
+ CERTCertListNode *node;
+ CERTCertList *certlist = NULL;
+
+ rv = nss_find_matching_certs(nss_slot,
+ params->issuer, params->subject, params->serial,
+ &certlist, params->find_cert_validity);
+
+ for (node = CERT_LIST_HEAD(certlist);
+ !CERT_LIST_END(node, certlist) && rv == KMF_OK;
+ node = CERT_LIST_NEXT(node)) {
+
+ nssrv = SEC_DeletePermCertificate(node->cert);
+ if (nssrv) {
+ SET_ERROR(kmfh, nssrv);
+ rv = KMF_ERR_INTERNAL;
+ }
+ }
+
+ if (rv == KMF_OK && certlist != NULL) {
+ CERT_DestroyCertList(certlist);
+ } else if (rv == KMF_OK && certlist == NULL) {
+ rv = KMF_ERR_CERT_NOT_FOUND;
+ }
+ }
+out:
+ if (nss_slot != NULL) {
+ PK11_FreeSlot(nss_slot);
+ }
+
+ if (cert != NULL) {
+ CERT_DestroyCertificate(cert);
+ }
+
+ return (rv);
+}
+
+static void
+InitRandom(char *filename)
+{
+ char buf[2048];
+ int fd;
+ PRInt32 count;
+
+ fd = open(filename, O_RDONLY);
+ if (!fd)
+ return;
+
+ count = read(fd, buf, sizeof (buf));
+ if (count > 0) {
+ PK11_RandomUpdate(buf, count);
+ }
+
+ (void) close(fd);
+}
+
+KMF_RETURN
+NSS_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;
+ PK11RSAGenParams rsaparams;
+ void *nssparams;
+ CK_MECHANISM_TYPE mechanism;
+ ulong_t publicExponent = 0x010001;
+ PK11SlotInfo *nss_slot = NULL;
+ SECKEYPrivateKey *NSSprivkey = NULL;
+ SECKEYPublicKey *NSSpubkey = NULL;
+ PQGParams *pqgParams = NULL;
+
+
+ if (params == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ rv = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts, FALSE, &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ rv = nss_authenticate(handle, nss_slot, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ /* Get some random bits */
+ InitRandom("/dev/urandom");
+ if (params->keytype == KMF_RSA) {
+ rsaparams.keySizeInBits = params->keylength;
+ /*
+ * NSS only allows for a 4 byte exponent.
+ * Ignore the exponent parameter if it is too big.
+ */
+ if (params->rsa_exponent.len > 0 &&
+ params->rsa_exponent.len <= sizeof (publicExponent) &&
+ params->rsa_exponent.val != NULL) {
+ (void) memcpy(&publicExponent,
+ params->rsa_exponent.val,
+ params->rsa_exponent.len);
+ }
+ rsaparams.pe = publicExponent;
+ mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
+ nssparams = &rsaparams;
+ } else if (params->keytype == KMF_DSA) {
+ PQGVerify *pqgVerify = NULL;
+ int ks;
+ SECStatus nssrv, passed;
+
+ mechanism = CKM_DSA_KEY_PAIR_GEN;
+
+ ks = PQG_PBITS_TO_INDEX(params->keylength);
+ nssrv = PK11_PQG_ParamGen(ks, &pqgParams, &pqgVerify);
+ if (nssrv != SECSuccess) {
+ SET_ERROR(kmfh, rv);
+ PK11_PQG_DestroyVerify(pqgVerify);
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto cleanup;
+ }
+
+ nssrv = PK11_PQG_VerifyParams(pqgParams, pqgVerify, &passed);
+ if (nssrv != SECSuccess || passed != SECSuccess) {
+ SET_ERROR(kmfh, rv);
+ rv = KMF_ERR_KEYGEN_FAILED;
+ }
+
+ PK11_PQG_DestroyVerify(pqgVerify);
+
+ if (rv != KMF_OK) {
+ SET_ERROR(kmfh, PORT_GetError());
+ goto cleanup;
+ }
+
+ nssparams = pqgParams;
+ } else {
+ rv = KMF_ERR_BAD_PARAMETER;
+ goto cleanup;
+ }
+
+ NSSprivkey = PK11_GenerateKeyPair(nss_slot,
+ mechanism, nssparams, &NSSpubkey,
+ PR_TRUE, /* isPermanent */
+ PR_TRUE, /* isSensitive */
+ (void *)params->cred.cred);
+
+ if (NSSprivkey == NULL || NSSpubkey == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ } else {
+ if (params->keylabel != NULL &&
+ strlen(params->keylabel)) {
+ (void) PK11_SetPrivateKeyNickname(NSSprivkey,
+ params->keylabel);
+ (void) PK11_SetPublicKeyNickname(NSSpubkey,
+ params->keylabel);
+ }
+ /* Now, convert it to a KMF_KEY object for the framework */
+ if (privkey != NULL) {
+ privkey->kstype = KMF_KEYSTORE_NSS;
+ privkey->keyalg = params->keytype;
+ privkey->keyclass = KMF_ASYM_PRI;
+ privkey->keylabel =
+ PK11_GetPrivateKeyNickname(NSSprivkey);
+ privkey->keyp = (void *)NSSprivkey;
+ }
+ if (pubkey != NULL) {
+ pubkey->kstype = KMF_KEYSTORE_NSS;
+ pubkey->keyalg = params->keytype;
+ pubkey->keyp = (void *)NSSpubkey;
+ pubkey->keyclass = KMF_ASYM_PUB;
+ pubkey->keylabel =
+ PK11_GetPublicKeyNickname(NSSpubkey);
+ }
+ rv = KMF_OK;
+ }
+cleanup:
+ if (rv != KMF_OK) {
+ if (NSSpubkey)
+ PK11_DeleteTokenPublicKey(NSSpubkey);
+ if (NSSprivkey)
+ PK11_DeleteTokenPrivateKey(NSSprivkey, PR_TRUE);
+
+ privkey->keyp = NULL;
+ pubkey->keyp = NULL;
+ }
+
+ if (pqgParams != NULL)
+ PK11_PQG_DestroyParams(pqgParams);
+
+
+ if (nss_slot != NULL)
+ PK11_FreeSlot(nss_slot);
+
+ return (rv);
+}
+
+KMF_RETURN
+NSS_SignData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key,
+ KMF_OID *AlgOID, KMF_DATA *tobesigned,
+ KMF_DATA *output)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_ALGORITHM_INDEX AlgId;
+ SECOidTag signAlgTag;
+ SECKEYPrivateKey *NSSprivkey = NULL;
+ SECStatus rv;
+ SECItem signed_data;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ signed_data.data = 0;
+ if (key == NULL || AlgOID == NULL ||
+ tobesigned == NULL || output == NULL ||
+ tobesigned->Data == NULL ||
+ output->Data == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* Map the OID to a NSS algorithm */
+ AlgId = X509_AlgorithmOidToAlgId(AlgOID);
+ if (AlgId == KMF_ALGID_NONE)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ NSSprivkey = (SECKEYPrivateKey *)key->keyp;
+
+ if (AlgId == KMF_ALGID_MD5WithRSA)
+ signAlgTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
+ else if (AlgId == KMF_ALGID_MD2WithRSA)
+ signAlgTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
+ else if (AlgId == KMF_ALGID_SHA1WithRSA)
+ signAlgTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
+ else if (AlgId == KMF_ALGID_SHA1WithDSA)
+ signAlgTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
+ else
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = SEC_SignData(&signed_data, tobesigned->Data,
+ tobesigned->Length, NSSprivkey, signAlgTag);
+
+ if (rv != 0) {
+ SET_ERROR(kmfh, rv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ if (signed_data.len <= output->Length) {
+ (void) memcpy(output->Data, signed_data.data, signed_data.len);
+ output->Length = signed_data.len;
+ } else {
+ output->Length = 0;
+ ret = KMF_ERR_BAD_PARAMETER;
+ }
+ free(signed_data.data);
+
+ return (ret);
+}
+
+KMF_RETURN
+NSS_EncodePubKeyData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *keyp,
+ KMF_DATA *encoded)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ SECItem *rvitem;
+ CERTSubjectPublicKeyInfo *spki = NULL;
+
+ if (keyp == NULL || encoded == NULL || keyp->keyp == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ spki = SECKEY_CreateSubjectPublicKeyInfo(keyp->keyp);
+ if (spki == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ return (KMF_ERR_MEMORY);
+ }
+
+ rvitem = SEC_ASN1EncodeItem(NULL, NULL, spki,
+ CERT_SubjectPublicKeyInfoTemplate);
+
+ if (rvitem != NULL) {
+ encoded->Data = malloc(rvitem->len);
+ if (encoded->Data == NULL) {
+ ret = KMF_ERR_MEMORY;
+ } else {
+ (void) memcpy(encoded->Data, rvitem->data, rvitem->len);
+ encoded->Length = rvitem->len;
+ }
+ SECITEM_FreeItem(rvitem, TRUE);
+ } else {
+ SET_ERROR(kmfh, PORT_GetError());
+ encoded->Data = NULL;
+ encoded->Length = 0;
+ ret = KMF_ERR_ENCODING;
+ }
+ SECKEY_DestroySubjectPublicKeyInfo(spki);
+
+ return (ret);
+}
+
+KMF_RETURN
+NSS_DeleteKey(KMF_HANDLE_T handle, KMF_DELETEKEY_PARAMS *params,
+ KMF_KEY_HANDLE *key, boolean_t delete_token)
+{
+ KMF_RETURN rv = KMF_OK;
+ PK11SlotInfo *nss_slot = NULL;
+
+ /*
+ * "delete_token" means to clear it from the token storage as well
+ * as from memory.
+ */
+ if (key == NULL || key->keyp == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (delete_token) {
+ SECStatus nssrv = SECSuccess;
+ if (key->keyclass != KMF_ASYM_PUB &&
+ key->keyclass != KMF_ASYM_PRI &&
+ key->keyclass != KMF_SYMMETRIC)
+ return (KMF_ERR_BAD_KEY_CLASS);
+
+ if (params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+ rv = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts, FALSE, &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+ rv = nss_authenticate(handle, nss_slot, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ if (key->keyclass == KMF_ASYM_PUB) {
+ nssrv = PK11_DeleteTokenPublicKey(
+ (SECKEYPublicKey *)key->keyp);
+ } else if (key->keyclass == KMF_ASYM_PRI) {
+ nssrv = PK11_DeleteTokenPrivateKey(
+ (SECKEYPrivateKey *)key->keyp, PR_TRUE);
+ } else if (key->keyclass == KMF_SYMMETRIC) {
+ nssrv = PK11_DeleteTokenSymKey(
+ (PK11SymKey *) key->keyp);
+ if (nssrv == SECSuccess)
+ PK11_FreeSymKey(
+ (PK11SymKey *) key->keyp);
+ }
+ if (nssrv != SECSuccess) {
+ SET_ERROR(handle, PORT_GetError());
+ rv = KMF_ERR_INTERNAL;
+ }
+ } else {
+ if (key->keyclass == KMF_ASYM_PUB) {
+ SECKEY_DestroyPublicKey((SECKEYPublicKey *)key->keyp);
+ } else if (key->keyclass == KMF_ASYM_PRI) {
+ SECKEY_DestroyPrivateKey((SECKEYPrivateKey *)key->keyp);
+ } else if (key->keyclass == KMF_SYMMETRIC) {
+ PK11_FreeSymKey((PK11SymKey *) key->keyp);
+ } else {
+ return (KMF_ERR_BAD_KEY_CLASS);
+ }
+ }
+ key->keyp = NULL;
+
+ return (rv);
+}
+
+KMF_RETURN
+NSS_ImportCRL(KMF_HANDLE_T handle, KMF_IMPORTCRL_PARAMS *params)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ PK11SlotInfo *nss_slot = NULL;
+ CERTSignedCrl *nss_crl = NULL;
+ KMF_ENCODE_FORMAT format;
+ int importOptions;
+ SECItem crlDER;
+ KMF_DATA crl1;
+ KMF_DATA crl2;
+
+ if (params == NULL || params->ks_opt_u.nss_opts.crlfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /*
+ * Check if the input CRL file is a valid CRL file and auto-detect
+ * the encoded format of the file.
+ */
+ ret = KMF_IsCRLFile(handle, params->ks_opt_u.nss_opts.crlfile,
+ &format);
+ if (ret != KMF_OK)
+ return (ret);
+
+ ret = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts, TRUE, &nss_slot);
+ if (ret != KMF_OK) {
+ return (ret);
+ }
+
+ /* set importOptions */
+ if (params->ks_opt_u.nss_opts.crl_check == B_FALSE) {
+ importOptions = CRL_IMPORT_DEFAULT_OPTIONS |
+ CRL_IMPORT_BYPASS_CHECKS;
+ } else {
+ importOptions = CRL_IMPORT_DEFAULT_OPTIONS;
+ }
+
+
+ /* Read in the CRL file */
+ crl1.Data = NULL;
+ crl2.Data = NULL;
+ ret = KMF_ReadInputFile(handle, params->ks_opt_u.nss_opts.crlfile,
+ &crl1);
+ if (ret != KMF_OK) {
+ return (ret);
+ }
+
+ /* If the input CRL is in PEM format, convert it to DER first. */
+ if (format == KMF_FORMAT_PEM) {
+ int len;
+ ret = KMF_Pem2Der(crl1.Data, crl1.Length,
+ &crl2.Data, &len);
+ if (ret != KMF_OK) {
+ goto out;
+ }
+ crl2.Length = (size_t)len;
+ }
+
+ crlDER.data = format == KMF_FORMAT_ASN1 ? crl1.Data : crl2.Data;
+ crlDER.len = format == KMF_FORMAT_ASN1 ? crl1.Length : crl2.Length;
+
+ nss_crl = PK11_ImportCRL(nss_slot, &crlDER, NULL, SEC_CRL_TYPE,
+ NULL, importOptions, NULL, CRL_DECODE_DEFAULT_OPTIONS);
+
+ if (nss_crl == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ ret = KMF_ERR_BAD_CRLFILE;
+ goto out;
+ }
+
+out:
+ if (nss_slot != NULL) {
+ PK11_FreeSlot(nss_slot);
+ }
+
+ if (crl1.Data != NULL) {
+ free(crl1.Data);
+ }
+
+ if (crl2.Data != NULL) {
+ free(crl2.Data);
+ }
+
+ if (nss_crl != NULL) {
+ SEC_DestroyCrl(nss_crl);
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+NSS_DeleteCRL(KMF_HANDLE_T handle, KMF_DELETECRL_PARAMS *params)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ CERTSignedCrl *crl = NULL;
+ CERTCertificate *cert = NULL;
+ PK11SlotInfo *nss_slot = NULL;
+ CERTCrlHeadNode *crlList = NULL;
+ CERTCrlNode *crlNode = NULL;
+ PRArenaPool *arena = NULL;
+ CERTName *name = NULL;
+ CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
+
+ /* check params */
+ if (params == NULL ||
+ (params->ks_opt_u.nss_opts.crl_issuerName == NULL &&
+ params->ks_opt_u.nss_opts.crl_subjName == NULL) ||
+ (params->ks_opt_u.nss_opts.crl_issuerName != NULL &&
+ params->ks_opt_u.nss_opts.crl_subjName != NULL)) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ rv = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts, TRUE,
+ &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ /* Find the CRL based on the deletion criteria. */
+ if (params->ks_opt_u.nss_opts.crl_issuerName != NULL) {
+ /*
+ * If the deletion is based on the issuer's certificate
+ * nickname, we will get the issuer's cert first, then
+ * get the CRL from the cert.
+ */
+ cert = CERT_FindCertByNicknameOrEmailAddr(certHandle,
+ params->ks_opt_u.nss_opts.crl_issuerName);
+ if (!cert) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CERT_NOT_FOUND;
+ goto out;
+ }
+
+ crl = SEC_FindCrlByName(certHandle, &cert->derSubject,
+ SEC_CRL_TYPE);
+ if (crl == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ goto out;
+ }
+ } else {
+ /*
+ * If the deletion is based on the CRL's subject name, we will
+ * get all the CRLs from the internal database and search
+ * for the CRL with the same subject name.
+ */
+ boolean_t found = B_FALSE;
+ int nssrv;
+
+ nssrv = SEC_LookupCrls(certHandle, &crlList, SEC_CRL_TYPE);
+ if (nssrv) {
+ SET_ERROR(kmfh, nssrv);
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ goto out;
+ }
+
+ if (crlList == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ goto out;
+ }
+
+ /* Allocate space for name */
+ arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (arena == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto out;
+ }
+
+ name = PORT_ArenaZAlloc(arena, sizeof (*name));
+ if (name == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto out;
+ }
+ name->arena = arena;
+
+ crlNode = crlList->first;
+ while (crlNode && !found) {
+ char *asciiname = NULL;
+ SECItem* issuer;
+
+ name = &crlNode->crl->crl.name;
+ if (!name) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ break;
+ }
+
+ asciiname = CERT_NameToAscii(name);
+ if (asciiname == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ break;
+ }
+
+ if (strcmp(params->ks_opt_u.nss_opts.crl_subjName,
+ asciiname) == 0) {
+ found = B_TRUE;
+ issuer = &crlNode->crl->crl.derName;
+ crl = SEC_FindCrlByName(certHandle, issuer,
+ SEC_CRL_TYPE);
+ if (crl == NULL) {
+ /* We found a cert but no CRL */
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ }
+ }
+ PORT_Free(asciiname);
+ crlNode = crlNode->next;
+ }
+
+ if (rv) {
+ goto out;
+ }
+ }
+
+ if (crl) {
+ (void) SEC_DeletePermCRL(crl);
+ }
+
+out:
+ if (nss_slot != NULL) {
+ PK11_FreeSlot(nss_slot);
+ }
+
+ if (crlList != NULL) {
+ PORT_FreeArena(crlList->arena, PR_FALSE);
+ }
+
+ if (arena != NULL) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ if (cert != NULL) {
+ CERT_DestroyCertificate(cert);
+ }
+
+ if (crl != NULL) {
+ SEC_DestroyCrl(crl);
+ }
+
+ return (rv);
+}
+
+
+KMF_RETURN
+NSS_FindCRL(KMF_HANDLE_T handle, KMF_FINDCRL_PARAMS *params,
+ char **CRLNameList, int *CRLCount)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ PK11SlotInfo *nss_slot = NULL;
+ CERTCrlHeadNode *crlList = NULL;
+ CERTCrlNode *crlNode = NULL;
+ PRArenaPool *arena = NULL;
+ CERTName *name = NULL;
+ SECStatus nssrv;
+ char *asciiname = NULL;
+ int crl_num;
+ int i;
+ CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
+
+ if (CRLCount == NULL || params == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ *CRLCount = 0;
+
+ rv = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts, TRUE, &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ /* Look up Crls */
+ nssrv = SEC_LookupCrls(certHandle, &crlList, SEC_CRL_TYPE);
+ if (nssrv) {
+ SET_ERROR(kmfh, rv);
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ goto out;
+ }
+
+ /* Allocate space for name first */
+ arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (arena == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto out;
+ }
+
+ name = PORT_ArenaZAlloc(arena, sizeof (*name));
+ if (name == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto out;
+ }
+ name->arena = arena;
+
+ /*
+ * Loop thru the crlList and create a crl list with CRL's subject name.
+ */
+ crlNode = crlList->first;
+ crl_num = 0;
+ while (crlNode) {
+ char *subj_name;
+
+ /* Get the CRL subject name */
+ name = &crlNode->crl->crl.name;
+ if (!name) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ break;
+ }
+
+
+ if (CRLNameList != NULL) {
+ asciiname = CERT_NameToAscii(name);
+ if (asciiname == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ break;
+ }
+ subj_name = strdup(asciiname);
+ PORT_Free(asciiname);
+ if (subj_name == NULL) {
+ rv = KMF_ERR_MEMORY;
+ break;
+ }
+ CRLNameList[crl_num] = subj_name;
+ }
+
+ crl_num++;
+ crlNode = crlNode->next;
+ }
+
+ if (rv == KMF_OK) {
+ /* success */
+ *CRLCount = crl_num;
+ }
+
+out:
+ if (nss_slot != NULL) {
+ PK11_FreeSlot(nss_slot);
+ }
+
+ if (crlList != NULL) {
+ PORT_FreeArena(crlList->arena, PR_FALSE);
+ }
+
+ if (arena != NULL) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ /* If failed, free memory allocated for the returning rlist */
+ if (rv && (CRLNameList != NULL)) {
+ for (i = 0; i < crl_num; i++) {
+ free(CRLNameList[i]);
+ }
+ }
+
+ return (rv);
+}
+
+
+KMF_RETURN
+NSS_FindCertInCRL(KMF_HANDLE_T handle, KMF_FINDCERTINCRL_PARAMS *params)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ PK11SlotInfo *nss_slot = NULL;
+ CERTCertificate *cert = NULL;
+ CERTSignedCrl *crl = NULL;
+ CERTCrlEntry *entry;
+ boolean_t match = B_FALSE;
+ int i;
+ CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
+
+ /* check params */
+ if (params == NULL || params->certLabel == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ rv = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts, TRUE, &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ cert = CERT_FindCertByNicknameOrEmailAddr(certHandle,
+ params->certLabel);
+ if (!cert) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CERT_NOT_FOUND;
+ goto out;
+ }
+
+ /* Find the CRL with the same issuer as the given certificate. */
+ crl = SEC_FindCrlByName(certHandle, &cert->derIssuer, SEC_CRL_TYPE);
+ if (crl == NULL) {
+ /*
+ * Could not find the CRL issued by the same issuer. This
+ * usually means that the CRL is not installed in the DB.
+ */
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_CRL_NOT_FOUND;
+ goto out;
+
+ }
+
+ /* Check if the certificate's serialNumber is revoked in the CRL */
+ i = 0;
+ while ((entry = (crl->crl).entries[i++]) != NULL) {
+ if (SECITEM_CompareItem(&(cert->serialNumber),
+ &(entry->serialNumber)) == SECEqual) {
+ match = B_TRUE;
+ break;
+ }
+ }
+
+ if (!match) {
+ rv = KMF_ERR_NOT_REVOKED;
+ }
+
+out:
+ if (nss_slot != NULL) {
+ PK11_FreeSlot(nss_slot);
+ }
+
+ if (cert != NULL) {
+ CERT_DestroyCertificate(cert);
+ }
+
+ if (crl != NULL) {
+ SEC_DestroyCrl(crl);
+ }
+
+ return (rv);
+}
+
+KMF_RETURN
+NSS_GetErrorString(KMF_HANDLE_T handle, char **msgstr)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ char *str;
+
+ /* Get the error string in the default language */
+ str = (char *)PR_ErrorToName((PRErrorCode)kmfh->lasterr.errcode);
+
+ if (str != NULL) {
+ *msgstr = (char *)strdup(str);
+ if ((*msgstr) == NULL)
+ ret = KMF_ERR_MEMORY;
+ } else {
+ *msgstr = NULL;
+ }
+
+ return (ret);
+}
+
+KMF_RETURN
+NSS_GetPrikeyByCert(KMF_HANDLE_T handle, KMF_CRYPTOWITHCERT_PARAMS *params,
+ KMF_DATA *SignerCertData, KMF_KEY_HANDLE *key,
+ KMF_KEY_ALG keytype)
+{
+ CERTCertificate *nss_cert = NULL;
+ SECKEYPrivateKey* privkey = NULL;
+ PK11SlotInfo *nss_slot = NULL;
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ rv = Do_NSS_Init(handle,
+ params->nssparms, FALSE, &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ rv = nss_authenticate(handle, nss_slot, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ nss_cert = CERT_DecodeCertFromPackage((char *)SignerCertData->Data,
+ SignerCertData->Length);
+
+ if (nss_cert == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ return (KMF_ERR_BAD_CERT_FORMAT);
+ }
+
+ privkey = PK11_FindPrivateKeyFromCert(nss_slot, nss_cert, NULL);
+ if (privkey == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ return (KMF_ERR_KEY_NOT_FOUND);
+ }
+
+ key->kstype = KMF_KEYSTORE_NSS;
+ key->keyclass = KMF_ASYM_PRI;
+ key->keyalg = keytype;
+ key->keyp = (void *)privkey;
+ key->keylabel = PK11_GetPrivateKeyNickname(privkey);
+
+ CERT_DestroyCertificate(nss_cert);
+
+ return (KMF_OK);
+
+}
+
+KMF_RETURN
+NSS_DecryptData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key,
+ KMF_OID *AlgOID, KMF_DATA *ciphertext,
+ KMF_DATA *output)
+{
+ KMF_RETURN ret = KMF_OK;
+ SECKEYPrivateKey *NSSprivkey = NULL;
+ SECStatus rv;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ 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);
+
+ NSSprivkey = (SECKEYPrivateKey *)key->keyp;
+ modulus_len = PK11_GetPrivateModulusLen(NSSprivkey);
+
+ 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++) {
+ rv = PK11_PrivDecryptPKCS1(NSSprivkey, out_data,
+ &out_len, ciphertext->Length, in_data, in_len);
+
+ if (rv != 0) {
+ SET_ERROR(kmfh, rv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ out_data += out_len;
+ total_decrypted += out_len;
+ in_data += in_len;
+ }
+
+ output->Length = total_decrypted;
+
+ return (ret);
+}
+
+static KMF_KEY_ALG
+pk11keytype2kmf(CK_KEY_TYPE type)
+{
+ switch (type) {
+ case CKK_RSA:
+ return (KMF_RSA);
+ case CKK_DSA:
+ return (KMF_RSA);
+ case CKK_AES:
+ return (KMF_AES);
+ case CKK_RC4:
+ return (KMF_RC4);
+ case CKK_DES:
+ return (KMF_DES);
+ case CKK_DES3:
+ return (KMF_DES3);
+ default:
+ /* not supported */
+ return (KMF_KEYALG_NONE);
+ }
+}
+
+KMF_RETURN
+NSS_FindKey(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS *parms,
+ KMF_KEY_HANDLE *keys, uint32_t *numkeys)
+{
+ KMF_RETURN rv;
+ SECKEYPrivateKeyList *prilist;
+ SECKEYPrivateKeyListNode *prinode;
+ SECKEYPublicKeyList *publist;
+ SECKEYPublicKeyListNode *pubnode;
+ PK11SlotInfo *nss_slot = NULL;
+ PK11SymKey *symlist;
+ int count;
+
+ if (handle == NULL || parms == NULL || numkeys == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = Do_NSS_Init(handle,
+ parms->ks_opt_u.nss_opts, FALSE, &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ rv = nss_authenticate(handle, nss_slot, &parms->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ *numkeys = 0;
+ if (parms->keyclass == KMF_ASYM_PUB) {
+ publist = PK11_ListPublicKeysInSlot(nss_slot, parms->findLabel);
+ if (publist == NULL) {
+ rv = KMF_ERR_KEY_NOT_FOUND;
+ goto cleanup;
+ }
+ } else if (parms->keyclass == KMF_ASYM_PRI) {
+ prilist = PK11_ListPrivKeysInSlot(nss_slot,
+ parms->findLabel, NULL);
+ if (prilist == NULL) {
+ rv = KMF_ERR_KEY_NOT_FOUND;
+ goto cleanup;
+ }
+ } else if (parms->keyclass == KMF_SYMMETRIC) {
+ symlist = PK11_ListFixedKeysInSlot(nss_slot, parms->findLabel,
+ NULL);
+ if (symlist == NULL) {
+ rv = KMF_ERR_KEY_NOT_FOUND;
+ goto cleanup;
+ }
+ } else {
+ rv = KMF_ERR_BAD_KEY_CLASS;
+ goto cleanup;
+ }
+
+ if (parms->keyclass == KMF_ASYM_PUB) {
+ for (count = 0, pubnode = PUBKEY_LIST_HEAD(publist);
+ !PUBKEY_LIST_END(pubnode, publist);
+ pubnode = PUBKEY_LIST_NEXT(pubnode), count++) {
+ if (keys != NULL) {
+ keys[count].kstype = KMF_KEYSTORE_NSS;
+ keys[count].keyclass = KMF_ASYM_PUB;
+ keys[count].keyp = (void *)pubnode->key;
+ keys[count].keylabel =
+ PK11_GetPublicKeyNickname(
+ pubnode->key);
+
+ if (pubnode->key->keyType == rsaKey)
+ keys[count].keyalg = KMF_RSA;
+ else if (pubnode->key->keyType == dsaKey)
+ keys[count].keyalg = KMF_DSA;
+ }
+ }
+ *numkeys = count;
+ } else if (parms->keyclass == KMF_ASYM_PRI) {
+ for (count = 0, prinode = PRIVKEY_LIST_HEAD(prilist);
+ !PRIVKEY_LIST_END(prinode, prilist);
+ prinode = PRIVKEY_LIST_NEXT(prinode), count++) {
+ if (keys != NULL) {
+ keys[count].kstype = KMF_KEYSTORE_NSS;
+ keys[count].keyclass = KMF_ASYM_PRI;
+ keys[count].keyp = (void *)prinode->key;
+ keys[count].keylabel =
+ PK11_GetPrivateKeyNickname(
+ prinode->key);
+
+ if (prinode->key->keyType == rsaKey)
+ keys[count].keyalg = KMF_RSA;
+ else if (prinode->key->keyType == dsaKey)
+ keys[count].keyalg = KMF_DSA;
+ }
+ }
+ *numkeys = count;
+ } else if (parms->keyclass == KMF_SYMMETRIC) {
+ count = 0;
+ while (symlist) {
+ PK11SymKey *symkey = symlist;
+ CK_KEY_TYPE type;
+ KMF_KEY_ALG keyalg;
+
+ type = PK11_GetSymKeyType(symkey);
+ keyalg = pk11keytype2kmf(type);
+
+ /*
+ * If keytype is specified in the searching parameter,
+ * check the keytype and skip the key if its keytype
+ * doesn't match.
+ */
+ symlist = PK11_GetNextSymKey(symkey);
+ if (parms->keytype != KMF_KEYALG_NONE &&
+ parms->keytype != keyalg) {
+ continue;
+ }
+
+ if (keys != NULL) {
+ keys[count].kstype = KMF_KEYSTORE_NSS;
+ keys[count].keyclass = KMF_SYMMETRIC;
+ keys[count].keyp = (void *) symkey;
+ keys[count].keylabel =
+ PK11_GetSymKeyNickname(symkey);
+ keys[count].keyalg = keyalg;
+ } else {
+ PK11_FreeSymKey(symkey);
+ }
+ count++;
+ }
+ *numkeys = count;
+ }
+
+cleanup:
+ if (nss_slot != NULL) {
+ PK11_FreeSlot(nss_slot);
+ }
+
+ return (rv);
+}
+
+static SECStatus
+p12u_SwapUnicodeBytes(SECItem *uniItem)
+{
+ unsigned int i;
+ unsigned char a;
+ if ((uniItem == NULL) || (uniItem->len % 2)) {
+ return (SECFailure);
+ }
+ for (i = 0; i < uniItem->len; i += 2) {
+ a = uniItem->data[i];
+ uniItem->data[i] = uniItem->data[i+1];
+ uniItem->data[i+1] = a;
+ }
+ return (SECSuccess);
+}
+
+static PRBool
+p12u_ucs2_ascii_conversion_function(
+ PRBool toUnicode,
+ unsigned char *inBuf,
+ unsigned int inBufLen,
+ unsigned char *outBuf,
+ unsigned int maxOutBufLen,
+ unsigned int *outBufLen,
+ PRBool swapBytes)
+{
+ SECItem it = { 0 };
+ SECItem *dup = NULL;
+ PRBool ret;
+
+ it.data = inBuf;
+ it.len = inBufLen;
+ dup = SECITEM_DupItem(&it);
+ /*
+ * If converting Unicode to ASCII, swap bytes before conversion
+ * as neccessary.
+ */
+ if (!toUnicode && swapBytes) {
+ if (p12u_SwapUnicodeBytes(dup) != SECSuccess) {
+ SECITEM_ZfreeItem(dup, PR_TRUE);
+ return (PR_FALSE);
+ }
+ }
+ /* Perform the conversion. */
+ ret = PORT_UCS2_UTF8Conversion(toUnicode, dup->data, dup->len,
+ outBuf, maxOutBufLen, outBufLen);
+ if (dup)
+ SECITEM_ZfreeItem(dup, PR_TRUE);
+
+ return (ret);
+}
+
+static PRBool
+p12u_OpenFile(p12uContext *p12ctx, PRBool fileRead)
+{
+ if (!p12ctx || !p12ctx->filename) {
+ return (PR_FALSE);
+ }
+
+ if (fileRead) {
+ p12ctx->file = PR_Open(p12ctx->filename,
+ PR_RDONLY, 0400);
+ } else {
+ p12ctx->file = PR_Open(p12ctx->filename,
+ PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, 0600);
+ }
+
+ if (!p12ctx->file) {
+ p12ctx->error = PR_TRUE;
+ return (PR_FALSE);
+ }
+
+ return (PR_TRUE);
+}
+
+static void
+p12u_DestroyContext(p12uContext **ppCtx, PRBool removeFile)
+{
+ if (!ppCtx || !(*ppCtx)) {
+ return;
+ }
+
+ if ((*ppCtx)->file != NULL) {
+ PR_Close((*ppCtx)->file);
+ }
+
+ if ((*ppCtx)->filename != NULL) {
+ if (removeFile) {
+ PR_Delete((*ppCtx)->filename);
+ }
+ free((*ppCtx)->filename);
+ }
+
+ free(*ppCtx);
+ *ppCtx = NULL;
+}
+
+static p12uContext *
+p12u_InitContext(PRBool fileImport, char *filename)
+{
+ p12uContext *p12ctx;
+
+ p12ctx = PORT_ZNew(p12uContext);
+ if (!p12ctx) {
+ return (NULL);
+ }
+
+ p12ctx->error = PR_FALSE;
+ p12ctx->errorValue = 0;
+ p12ctx->filename = strdup(filename);
+
+ if (!p12u_OpenFile(p12ctx, fileImport)) {
+ p12u_DestroyContext(&p12ctx, PR_FALSE);
+ return (NULL);
+ }
+
+ return (p12ctx);
+}
+
+static void
+p12u_WriteToExportFile(void *arg, const char *buf, unsigned long len)
+{
+ p12uContext *p12cxt = arg;
+ int writeLen;
+
+ if (!p12cxt || (p12cxt->error == PR_TRUE)) {
+ return;
+ }
+
+ if (p12cxt->file == NULL) {
+ p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
+ p12cxt->error = PR_TRUE;
+ return;
+ }
+
+ writeLen = PR_Write(p12cxt->file, (unsigned char *)buf, (int32)len);
+
+ if (writeLen != (int)len) {
+ PR_Close(p12cxt->file);
+ free(p12cxt->filename);
+ p12cxt->filename = NULL;
+ p12cxt->file = NULL;
+ p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
+ p12cxt->error = PR_TRUE;
+ }
+}
+
+#define HANDLE_NSS_ERROR(r) {\
+ SET_ERROR(kmfh, PORT_GetError()); \
+ rv = r; \
+ goto out; }
+
+static KMF_RETURN
+add_cert_to_bag(SEC_PKCS12ExportContext *p12ecx,
+ CERTCertificate *cert, SECItem *pwitem)
+{
+ KMF_RETURN rv = KMF_OK;
+ SEC_PKCS12SafeInfo *keySafe = NULL, *certSafe = NULL;
+
+ keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx);
+ if (PK11_IsFIPS()) {
+ certSafe = keySafe;
+ } else {
+ certSafe = SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC);
+ }
+
+ if (!certSafe || !keySafe) {
+ rv = KMF_ERR_INTERNAL;
+ goto out;
+ }
+
+ if (SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert,
+ CERT_GetDefaultCertDB(), keySafe, NULL, PR_TRUE, pwitem,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC)
+ != SECSuccess) {
+ rv = KMF_ERR_INTERNAL;
+ }
+out:
+ return (rv);
+}
+
+/*ARGSUSED*/
+KMF_RETURN
+NSS_ExportP12(KMF_HANDLE_T handle,
+ KMF_EXPORTP12_PARAMS *params,
+ int numcerts, KMF_X509_DER_CERT *certs,
+ int numkeys, KMF_KEY_HANDLE *keylist,
+ char *filename)
+{
+ KMF_RETURN rv;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ SEC_PKCS12ExportContext *p12ecx = NULL;
+ p12uContext *p12ctx = NULL;
+ CERTCertList *certlist = NULL;
+ CERTCertificate *nsscert = NULL;
+ CERTCertListNode* node = NULL;
+ PK11SlotInfo *slot = NULL;
+ SECItem pwitem = {NULL, 0};
+
+ rv = Do_NSS_Init(handle,
+ params->nssparms, FALSE, &slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ rv = nss_authenticate(handle, slot, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ /*
+ * Find the certificate(s) first.
+ */
+ if (params->certLabel) {
+ nsscert = PK11_FindCertFromNickname(params->certLabel,
+ NULL);
+ if (nsscert == NULL) {
+ HANDLE_NSS_ERROR(KMF_ERR_CERT_NOT_FOUND)
+ }
+ } else {
+ rv = nss_find_matching_certs(slot,
+ params->issuer,
+ params->subject,
+ params->serial,
+ &certlist, 0);
+
+ if (rv == KMF_OK && certlist == NULL) {
+ return (KMF_ERR_CERT_NOT_FOUND);
+ }
+ if (rv != KMF_OK)
+ return (rv);
+ }
+
+ /*
+ * The KMF_CREDENTIAL holds the password to use for
+ * encrypting the PKCS12 key information.
+ */
+ pwitem.data = (uchar_t *)params->p12cred.cred;
+ pwitem.len = params->p12cred.credlen;
+
+ p12ctx = p12u_InitContext(PR_FALSE, filename);
+ if (!p12ctx) {
+ HANDLE_NSS_ERROR(KMF_ERR_OPEN_FILE)
+ }
+
+ PORT_SetUCS2_ASCIIConversionFunction(
+ p12u_ucs2_ascii_conversion_function);
+
+ p12ecx = SEC_PKCS12CreateExportContext(NULL, NULL,
+ slot, NULL);
+ if (!p12ecx) {
+ HANDLE_NSS_ERROR(KMF_ERR_OPEN_FILE)
+ }
+
+ if (SEC_PKCS12AddPasswordIntegrity(p12ecx, &pwitem, SEC_OID_SHA1)
+ != SECSuccess) {
+ HANDLE_NSS_ERROR(KMF_ERR_INTERNAL)
+ }
+
+ /*
+ * NSS actually supports storing a list of keys and certs
+ * in the PKCS#12 PDU. Nice feature.
+ */
+ if (certlist != NULL) {
+ for (node = CERT_LIST_HEAD(certlist);
+ !CERT_LIST_END(node, certlist) && rv == KMF_OK;
+ node = CERT_LIST_NEXT(node)) {
+
+ rv = add_cert_to_bag(p12ecx, node->cert, &pwitem);
+ }
+ } else if (nsscert != NULL) {
+ rv = add_cert_to_bag(p12ecx, nsscert, &pwitem);
+ }
+
+ if (SEC_PKCS12Encode(p12ecx, p12u_WriteToExportFile, p12ctx)
+ != SECSuccess) {
+ HANDLE_NSS_ERROR(KMF_ERR_ENCODING)
+ }
+out:
+ if (nsscert)
+ CERT_DestroyCertificate(nsscert);
+
+ if (certlist)
+ CERT_DestroyCertList(certlist);
+
+ if (p12ctx)
+ p12u_DestroyContext(&p12ctx, PR_FALSE);
+
+ if (p12ecx)
+ SEC_PKCS12DestroyExportContext(p12ecx);
+
+ return (rv);
+}
+
+#define SETATTR(t, n, atype, value, size) \
+ t[n].type = atype; \
+ t[n].pValue = (CK_BYTE *)value; \
+ t[n].ulValueLen = (CK_ULONG)size;
+
+KMF_RETURN
+NSS_StorePrivateKey(KMF_HANDLE_T handle, KMF_STOREKEY_PARAMS *params,
+ KMF_RAW_KEY_DATA *rawkey)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ SECStatus ckrv = SECSuccess;
+ PK11SlotInfo *slot = NULL;
+ CERTCertificate *nss_cert = NULL;
+ SECKEYPrivateKeyInfo rpk;
+ SECItem nickname;
+ KMF_DATA derkey = { NULL, 0 };
+ uchar_t ver = 0;
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (params == NULL || params->certificate == NULL || rawkey == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = Do_NSS_Init(handle,
+ params->nssparms, FALSE, &slot);
+
+ if (rv != KMF_OK)
+ return (rv);
+
+ rv = nss_authenticate(handle, slot, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ /*
+ * Decode the cert into an NSS CERT object so we can access the
+ * SPKI and KeyUsage data later.
+ */
+ nss_cert = CERT_DecodeCertFromPackage((char *)params->certificate->Data,
+ params->certificate->Length);
+
+ if (nss_cert == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_BAD_CERT_FORMAT;
+ goto cleanup;
+ }
+
+ (void) memset(&rpk, 0, sizeof (rpk));
+
+ rpk.arena = NULL;
+ rpk.version.type = siUnsignedInteger;
+ rpk.version.data = &ver;
+ rpk.version.len = 1;
+ if (rawkey->keytype == KMF_RSA) {
+
+ rv = DerEncodeRSAPrivateKey(&derkey, &rawkey->rawdata.rsa);
+ if (rv != KMF_OK)
+ goto cleanup;
+
+ rpk.algorithm = nss_cert->subjectPublicKeyInfo.algorithm;
+ rpk.privateKey.data = derkey.Data;
+ rpk.privateKey.len = derkey.Length;
+ rpk.attributes = NULL;
+
+
+ } else if (rawkey->keytype == KMF_DSA) {
+ rv = DerEncodeDSAPrivateKey(&derkey, &rawkey->rawdata.dsa);
+ if (rv != KMF_OK)
+ goto cleanup;
+
+ rpk.algorithm = nss_cert->subjectPublicKeyInfo.algorithm;
+ rpk.privateKey.data = derkey.Data;
+ rpk.privateKey.len = derkey.Length;
+ rpk.attributes = NULL;
+
+ } else {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ nickname.data = (uchar_t *)params->label;
+ nickname.len = (params->label ? strlen(params->label) : 0);
+
+ ckrv = PK11_ImportPrivateKeyInfo(slot, &rpk,
+ &nickname, &nss_cert->subjectPublicKeyInfo.subjectPublicKey,
+ TRUE, TRUE, nss_cert->keyUsage, NULL);
+
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_INTERNAL;
+ }
+
+cleanup:
+ if (nss_cert != NULL) {
+ CERT_DestroyCertificate(nss_cert);
+ }
+ KMF_FreeData(&derkey);
+ return (rv);
+}
+
+KMF_RETURN
+NSS_CreateSymKey(KMF_HANDLE_T handle,
+ KMF_CREATESYMKEY_PARAMS *params,
+ KMF_KEY_HANDLE *symkey)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ PK11SlotInfo *nss_slot = NULL;
+ PK11SymKey *nsskey = NULL;
+ CK_MECHANISM_TYPE keyType;
+ SECStatus nssrv;
+ int keySize;
+
+ if (params == NULL || symkey == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ switch (params->keytype) {
+ case KMF_AES:
+ keyType = CKM_AES_KEY_GEN;
+ keySize = params->keylength;
+ if (keySize == 0 || (keySize % 8) != 0)
+ return (KMF_ERR_BAD_KEY_SIZE);
+ break;
+ case KMF_RC4:
+ keyType = CKM_RC4_KEY_GEN;
+ keySize = params->keylength;
+ if (keySize == 0 || (keySize % 8) != 0)
+ return (KMF_ERR_BAD_KEY_SIZE);
+ break;
+ case KMF_DES:
+ keyType = CKM_DES_KEY_GEN;
+ keySize = 0; /* required by PK11_TokenKeyGen() */
+ break;
+ case KMF_DES3:
+ keyType = CKM_DES3_KEY_GEN;
+ keySize = 0; /* required by PK11_TokenKeyGen() */
+ break;
+ default:
+ rv = KMF_ERR_BAD_KEY_TYPE;
+ goto out;
+ }
+
+ rv = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts, FALSE, &nss_slot);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ rv = nss_authenticate(handle, nss_slot, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ nsskey = PK11_TokenKeyGen(nss_slot, keyType, NULL, keySize, NULL,
+ PR_TRUE, (void *)params->cred.cred);
+ if (nsskey == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto out;
+ }
+
+ nssrv = PK11_SetSymKeyNickname(nsskey, params->keylabel);
+ if (nssrv != SECSuccess) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto out;
+ }
+
+ symkey->kstype = KMF_KEYSTORE_NSS;
+ symkey->keyalg = params->keytype;
+ symkey->keyclass = KMF_SYMMETRIC;
+ symkey->israw = FALSE;
+ symkey->keyp = (void *)nsskey;
+
+out:
+ if (nss_slot != NULL)
+ PK11_FreeSlot(nss_slot);
+
+ if (rv != KMF_OK && nsskey != NULL) {
+ PK11_DeleteTokenSymKey(nsskey);
+ PK11_FreeSymKey(nsskey);
+ }
+ return (rv);
+}
+
+KMF_RETURN
+NSS_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;
+ SECItem *value = NULL;
+ PK11SymKey *nsskey;
+ SECStatus nss_rv;
+
+ 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_KEY_DATA *rawkey = (KMF_RAW_KEY_DATA *)symkey->keyp;
+
+ if (rawkey == NULL ||
+ rawkey->rawdata.sym.keydata.val == NULL ||
+ rawkey->rawdata.sym.keydata.len == 0)
+ return (KMF_ERR_BAD_KEYHANDLE);
+
+ rkey->keydata.len = rawkey->rawdata.sym.keydata.len;
+ if ((rkey->keydata.val = malloc(rkey->keydata.len)) == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memcpy(rkey->keydata.val,
+ rawkey->rawdata.sym.keydata.val, rkey->keydata.len);
+ } else {
+ nsskey = (PK11SymKey *)(symkey->keyp);
+ if (nsskey == NULL)
+ return (KMF_ERR_BAD_KEYHANDLE);
+
+ nss_rv = PK11_ExtractKeyValue(nsskey);
+ if (nss_rv != SECSuccess) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_GETKEYVALUE_FAILED;
+ goto out;
+ }
+
+ value = PK11_GetKeyData(nsskey);
+ if (value == NULL) {
+ SET_ERROR(kmfh, PORT_GetError());
+ rv = KMF_ERR_GETKEYVALUE_FAILED;
+ goto out;
+ }
+
+ if (value->len == 0 || value->data == NULL) {
+ rv = KMF_ERR_GETKEYVALUE_FAILED;
+ goto out;
+ }
+
+ rkey->keydata.val = malloc(value->len);
+ if (rkey->keydata.val == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto out;
+ }
+ (void) memcpy(rkey->keydata.val, value->data, value->len);
+ rkey->keydata.len = value->len;
+ (void) memset(value->data, 0, value->len);
+ }
+out:
+ if (value != NULL)
+ SECITEM_FreeItem(value, PR_TRUE);
+ return (rv);
+}
+
+KMF_RETURN
+NSS_SetTokenPin(KMF_HANDLE_T handle, KMF_SETPIN_PARAMS *params,
+ KMF_CREDENTIAL *newpin)
+{
+ KMF_RETURN ret = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ int rv;
+ PK11SlotInfo *nss_slot = NULL;
+
+ if (handle == NULL || params == NULL || newpin == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ ret = Do_NSS_Init(handle,
+ params->ks_opt_u.nss_opts,
+ FALSE, &nss_slot);
+ /* If it was uninitialized, set it */
+ if (ret == KMF_ERR_UNINITIALIZED_TOKEN) {
+ rv = PK11_InitPin(nss_slot, NULL, newpin->cred);
+ if (rv != SECSuccess) {
+ SET_ERROR(kmfh, PORT_GetError());
+ ret = KMF_ERR_AUTH_FAILED;
+ } else {
+ ret = KMF_OK;
+ }
+ } else if (ret == KMF_OK) {
+ ret = nss_authenticate(handle, nss_slot, &params->cred);
+ if (ret != KMF_OK) {
+ return (ret);
+ }
+ rv = PK11_ChangePW(nss_slot,
+ params->cred.cred, newpin->cred);
+ if (rv != SECSuccess) {
+ SET_ERROR(kmfh, PORT_GetError());
+ ret = KMF_ERR_AUTH_FAILED;
+ }
+ }
+
+ return (ret);
+}
diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/i386/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/i386/Makefile
new file mode 100644
index 0000000000..443f78537a
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_nss/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_nss/sparc/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/sparc/Makefile
new file mode 100644
index 0000000000..472ac90a9a
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_nss/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_nss/sparcv9/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/sparcv9/Makefile
new file mode 100644
index 0000000000..fe1e843387
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_nss/sparcv9/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 ../../../../Makefile.lib.64
+
+LDLIBS += $(NSSLIBS64)
+
+install: $(ROOTLIBS64)
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)
diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile
new file mode 100644
index 0000000000..b65a323ef5
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/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_pkcs11/Makefile.com b/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile.com
new file mode 100644
index 0000000000..f2a715de92
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile.com
@@ -0,0 +1,65 @@
+#
+# 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_pkcs11.a
+VERS= .1
+OBJECTS= pkcs11_spi.o
+
+include $(SRC)/lib/Makefile.lib
+
+LIBLINKS= $(DYNLIB:.so.1=.so)
+KMFINC= -I../../../include -I../../../ber_der/inc
+
+PKCS11LIBS= -lkmf -lkmfberder -lpkcs11 -lcryptoutil -lc
+
+SRCDIR= ../common
+INCDIR= ../../include
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -D_REENTRANT $(KMFINC) -I$(INCDIR) -I/usr/include/libxml2
+
+PICS= $(OBJECTS:%=pics/%)
+SONAME= $(PLUGIN)
+
+LDLIBS += $(PKCS11LIBS)
+
+ROOTLIBDIR= $(ROOT)/usr/lib/security
+ROOTLIBDIR64= $(ROOT)/usr/lib/security/$(MACH64)
+
+.KEEP_STATE:
+
+LIBS = $(DYNLIB)
+
+all: $(LIBS) $(LINTLIB)
+
+lint: lintcheck
+
+FRC:
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/amd64/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/amd64/Makefile
new file mode 100644
index 0000000000..dfd8150806
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/amd64/Makefile
@@ -0,0 +1,30 @@
+#
+# 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
+
+install: $(ROOTLIBS64)
diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/mapfile-vers b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/mapfile-vers
new file mode 100644
index 0000000000..ee3b6bcb92
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/mapfile-vers
@@ -0,0 +1,50 @@
+#
+# 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;
+ KMFPK11_FindCert;
+ KMFPK11_FreeKMFCert;
+ KMFPK11_StoreCert;
+ KMFPK11_ImportCert;
+ KMFPK11_DeleteCert;
+ KMFPK11_CreateKeypair;
+ KMFPK11_FindKey;
+ KMFPK11_EncodePubKeyData;
+ KMFPK11_SignData;
+ KMFPK11_DeleteKey;
+ KMFPK11_GetErrorString;
+ KMFPK11_GetPrikeyByCert;
+ KMFPK11_DecryptData;
+ KMFPK11_StorePrivateKey;
+ KMFPK11_CreateSymKey;
+ KMFPK11_GetSymKeyValue;
+ KMFPK11_SetTokenPin;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c
new file mode 100644
index 0000000000..e548c64eb8
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c
@@ -0,0 +1,2945 @@
+/*
+ * 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
+ */
+/*
+ * PKCS11 token KMF Plugin
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h> /* debugging only */
+#include <errno.h>
+#include <values.h>
+
+#include <kmfapiP.h>
+#include <oidsalg.h>
+#include <ber_der.h>
+#include <algorithm.h>
+
+#include <cryptoutil.h>
+#include <security/cryptoki.h>
+#include <security/pkcs11.h>
+
+#define SETATTR(t, n, atype, value, size) \
+ t[n].type = atype; \
+ t[n].pValue = (CK_BYTE *)value; \
+ t[n].ulValueLen = (CK_ULONG)size;
+
+#define SET_ERROR(h, c) h->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; \
+ h->lasterr.errcode = c;
+
+typedef struct _objlist {
+ CK_OBJECT_HANDLE handle;
+ struct _objlist *next;
+} OBJLIST;
+
+static KMF_RETURN
+search_certs(KMF_HANDLE_T, char *, char *, char *, KMF_BIGINT *,
+ boolean_t, KMF_CERT_VALIDITY, OBJLIST **, uint32_t *);
+
+static KMF_RETURN
+keyObj2RawKey(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_KEY_DATA **);
+
+KMF_RETURN
+KMFPK11_ConfigureKeystore(KMF_HANDLE_T, KMF_CONFIG_PARAMS *);
+
+KMF_RETURN
+KMFPK11_FindCert(KMF_HANDLE_T,
+ KMF_FINDCERT_PARAMS *,
+ KMF_X509_DER_CERT *,
+ uint32_t *);
+
+void
+KMFPK11_FreeKMFCert(KMF_HANDLE_T,
+ KMF_X509_DER_CERT *kmf_cert);
+
+KMF_RETURN
+KMFPK11_StoreCert(KMF_HANDLE_T, KMF_STORECERT_PARAMS *, KMF_DATA *);
+
+KMF_RETURN
+KMFPK11_ImportCert(KMF_HANDLE_T, KMF_IMPORTCERT_PARAMS *);
+
+KMF_RETURN
+KMFPK11_DeleteCert(KMF_HANDLE_T, KMF_DELETECERT_PARAMS *);
+
+KMF_RETURN
+KMFPK11_CreateKeypair(KMF_HANDLE_T, KMF_CREATEKEYPAIR_PARAMS *,
+ KMF_KEY_HANDLE *, KMF_KEY_HANDLE *);
+
+KMF_RETURN
+KMFPK11_DeleteKey(KMF_HANDLE_T, KMF_DELETEKEY_PARAMS *,
+ KMF_KEY_HANDLE *, boolean_t);
+
+KMF_RETURN
+KMFPK11_EncodePubKeyData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_DATA *);
+
+KMF_RETURN
+KMFPK11_SignData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *,
+ KMF_DATA *, KMF_DATA *);
+
+KMF_RETURN
+KMFPK11_GetErrorString(KMF_HANDLE_T, char **);
+
+KMF_RETURN
+KMFPK11_GetPrikeyByCert(KMF_HANDLE_T, KMF_CRYPTOWITHCERT_PARAMS *, KMF_DATA *,
+ KMF_KEY_HANDLE *, KMF_KEY_ALG);
+
+KMF_RETURN
+KMFPK11_DecryptData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *,
+ KMF_DATA *, KMF_DATA *);
+
+KMF_RETURN
+KMFPK11_FindKey(KMF_HANDLE_T, KMF_FINDKEY_PARAMS *,
+ KMF_KEY_HANDLE *, uint32_t *);
+
+KMF_RETURN
+KMFPK11_StorePrivateKey(KMF_HANDLE_T, KMF_STOREKEY_PARAMS *,
+ KMF_RAW_KEY_DATA *);
+
+KMF_RETURN
+KMFPK11_CreateSymKey(KMF_HANDLE_T, KMF_CREATESYMKEY_PARAMS *,
+ KMF_KEY_HANDLE *);
+
+KMF_RETURN
+KMFPK11_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_SYM_KEY *);
+
+KMF_RETURN
+KMFPK11_SetTokenPin(KMF_HANDLE_T, KMF_SETPIN_PARAMS *, KMF_CREDENTIAL *);
+
+static
+KMF_PLUGIN_FUNCLIST pk11token_plugin_table =
+{
+ 1, /* Version */
+ KMFPK11_ConfigureKeystore,
+ KMFPK11_FindCert,
+ KMFPK11_FreeKMFCert,
+ KMFPK11_StoreCert,
+ KMFPK11_ImportCert,
+ NULL, /* ImportCRL */
+ KMFPK11_DeleteCert,
+ NULL, /* DeleteCRL */
+ KMFPK11_CreateKeypair,
+ KMFPK11_FindKey,
+ KMFPK11_EncodePubKeyData,
+ KMFPK11_SignData,
+ KMFPK11_DeleteKey,
+ NULL, /* ListCRL */
+ NULL, /* FindCRL */
+ NULL, /* FindCertInCRL */
+ KMFPK11_GetErrorString,
+ KMFPK11_GetPrikeyByCert,
+ KMFPK11_DecryptData,
+ NULL, /* ExportP12 */
+ KMFPK11_StorePrivateKey,
+ KMFPK11_CreateSymKey,
+ KMFPK11_GetSymKeyValue,
+ KMFPK11_SetTokenPin,
+ NULL /* Finalize */
+};
+
+KMF_PLUGIN_FUNCLIST *
+KMF_Plugin_Initialize()
+{
+ return (&pk11token_plugin_table);
+}
+
+KMF_RETURN
+KMFPK11_ConfigureKeystore(KMF_HANDLE_T handle, KMF_CONFIG_PARAMS *params)
+{
+ KMF_RETURN rv = KMF_OK;
+
+ if (params == NULL || params->pkcs11config.label == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = KMF_SelectToken(handle, params->pkcs11config.label,
+ params->pkcs11config.readonly);
+
+ return (rv);
+}
+
+static KMF_RETURN
+pk11_authenticate(KMF_HANDLE_T handle,
+ KMF_CREDENTIAL *cred)
+{
+
+ CK_RV ck_rv = CKR_OK;
+ CK_SESSION_HANDLE hSession = (CK_SESSION_HANDLE)handle->pk11handle;
+
+ if (hSession == NULL)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (cred == NULL || cred->cred == NULL || cred->credlen == 0) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ if ((ck_rv = C_Login(hSession, CKU_USER,
+ (uchar_t *)cred->cred, cred->credlen)) != CKR_OK) {
+ if (ck_rv != CKR_USER_ALREADY_LOGGED_IN) {
+ handle->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
+ handle->lasterr.errcode = ck_rv;
+ return (KMF_ERR_AUTH_FAILED);
+ }
+ }
+
+ return (KMF_OK);
+}
+
+static KMF_RETURN
+PK11Cert2KMFCert(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE hObj,
+ KMF_X509_DER_CERT *kmfcert)
+{
+ KMF_RETURN rv = 0;
+ CK_RV ckrv = CKR_OK;
+
+ CK_CERTIFICATE_TYPE cktype;
+ CK_OBJECT_CLASS class;
+ CK_BBOOL cktrusted, token;
+ CK_ULONG subject_len, value_len, issuer_len, serno_len, id_len;
+ CK_BYTE *subject = NULL, *value = NULL;
+ CK_BYTE *label = NULL;
+ CK_ULONG label_len = 0;
+ CK_ATTRIBUTE templ[10];
+
+ SETATTR(templ, 0, CKA_CLASS, &class, sizeof (class));
+
+ /* Is this a certificate object ? */
+ ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, templ, 1);
+ if (ckrv != CKR_OK || class != CKO_CERTIFICATE) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ SETATTR(templ, 0, CKA_CERTIFICATE_TYPE, &cktype, sizeof (cktype));
+ SETATTR(templ, 1, CKA_TOKEN, &token, sizeof (token));
+ SETATTR(templ, 2, CKA_TRUSTED, &cktrusted, sizeof (cktrusted));
+
+ ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, templ, 3);
+
+ if (ckrv != CKR_OK || cktype != CKC_X_509) {
+ SET_ERROR(kmfh, ckrv);
+ return (ckrv);
+ } else {
+ /* What attributes are available and how big are they? */
+ subject_len = issuer_len = serno_len = id_len = value_len =
+ label_len = 0;
+ SETATTR(templ, 0, CKA_SUBJECT, NULL, subject_len);
+ SETATTR(templ, 1, CKA_ISSUER, NULL, issuer_len);
+ SETATTR(templ, 2, CKA_SERIAL_NUMBER, NULL, serno_len);
+ SETATTR(templ, 3, CKA_ID, NULL, id_len);
+ SETATTR(templ, 4, CKA_VALUE, NULL, value_len);
+ SETATTR(templ, 5, CKA_LABEL, NULL, label_len);
+
+ /*
+ * Query the object with NULL values in the pValue spot
+ * so we know how much space to allocate for each field.
+ */
+ ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, templ, 6);
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_INTERNAL); /* TODO - Error messages ? */
+ }
+
+ subject_len = templ[0].ulValueLen;
+ issuer_len = templ[1].ulValueLen;
+ serno_len = templ[2].ulValueLen;
+ id_len = templ[3].ulValueLen;
+ value_len = templ[4].ulValueLen;
+ label_len = templ[5].ulValueLen;
+
+ /*
+ * For PKCS#11 CKC_X_509 certificate objects,
+ * the following attributes must be defined.
+ * CKA_SUBJECT, CKA_ID, CKA_ISSUER, CKA_SERIAL_NUMBER,
+ * CKA_VALUE.
+ */
+ if (subject_len == 0 || issuer_len == 0 ||
+ serno_len == 0 || value_len == 0) {
+ return (KMF_ERR_INTERNAL);
+ }
+
+ /* Only fetch the value field if we are saving the data */
+ if (kmfcert != NULL) {
+ int i = 0;
+ value = malloc(value_len);
+ if (value == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto errout;
+ }
+
+ SETATTR(templ, i, CKA_VALUE, value, value_len);
+ i++;
+ if (label_len > 0) {
+ label = malloc(label_len + 1);
+ if (label == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto errout;
+ }
+ (void) memset(label, 0, label_len + 1);
+ SETATTR(templ, i, CKA_LABEL, label,
+ label_len);
+ i++;
+ }
+
+ /* re-query the object with room for the value attr */
+ ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj,
+ templ, i);
+
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ goto errout;
+ }
+
+ kmfcert->certificate.Data = value;
+ kmfcert->certificate.Length = value_len;
+ kmfcert->kmf_private.flags |= KMF_FLAG_CERT_SIGNED;
+ kmfcert->kmf_private.keystore_type =
+ KMF_KEYSTORE_PK11TOKEN;
+ kmfcert->kmf_private.label = (char *)label;
+
+ rv = KMF_OK;
+ }
+ }
+
+errout:
+ if (rv != KMF_OK) {
+ if (subject)
+ free(subject);
+ if (value)
+ free(value);
+
+ if (kmfcert) {
+ kmfcert->certificate.Data = NULL;
+ kmfcert->certificate.Length = 0;
+ }
+ }
+ return (rv);
+}
+
+static void
+free_objlist(OBJLIST *head)
+{
+ OBJLIST *temp = head;
+
+ while (temp != NULL) {
+ head = head->next;
+ free(temp);
+ temp = head;
+ }
+}
+
+/*
+ * The caller should make sure that the templ->pValue is NULL since
+ * it will be overwritten below.
+ */
+static KMF_RETURN
+get_attr(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj,
+ CK_ATTRIBUTE *templ)
+{
+ CK_RV rv;
+
+ rv = C_GetAttributeValue(kmfh->pk11handle, obj, templ, 1);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ if (templ->ulValueLen > 0) {
+ templ->pValue = malloc(templ->ulValueLen);
+ if (templ->pValue == NULL)
+ return (KMF_ERR_MEMORY);
+
+ rv = C_GetAttributeValue(kmfh->pk11handle, obj, templ, 1);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ return (KMF_ERR_INTERNAL);
+ }
+ }
+
+ return (KMF_OK);
+}
+
+/*
+ * Match a certificate with an issuer and/or subject name.
+ * This is tricky because we cannot reliably compare DER encodings
+ * because RDNs may have their AV-pairs in different orders even
+ * if the values are the same. You must compare individual
+ * AV pairs for the RDNs.
+ *
+ * RETURN: 0 for a match, non-zero for a non-match.
+ */
+static KMF_RETURN
+matchcert(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj,
+ KMF_X509_NAME *issuer, KMF_X509_NAME *subject)
+{
+ KMF_RETURN rv = KMF_OK;
+ CK_ATTRIBUTE certattr;
+ KMF_DATA name;
+ KMF_X509_NAME dn;
+
+ if (issuer->numberOfRDNs > 0) {
+ certattr.type = CKA_ISSUER;
+ certattr.pValue = NULL;
+ certattr.ulValueLen = 0;
+
+ rv = get_attr(kmfh, obj, &certattr);
+
+ if (rv == KMF_OK) {
+ name.Data = certattr.pValue;
+ name.Length = certattr.ulValueLen;
+ rv = DerDecodeName(&name, &dn);
+ if (rv == KMF_OK) {
+ rv = KMF_CompareRDNs(issuer, &dn);
+ KMF_FreeDN(&dn);
+ }
+ free(certattr.pValue);
+ }
+
+ if (rv != KMF_OK)
+ return (rv);
+ }
+ if (subject->numberOfRDNs > 0) {
+ certattr.type = CKA_SUBJECT;
+ certattr.pValue = NULL;
+ certattr.ulValueLen = 0;
+
+ rv = get_attr(kmfh, obj, &certattr);
+
+ if (rv == KMF_OK) {
+ name.Data = certattr.pValue;
+ name.Length = certattr.ulValueLen;
+ rv = DerDecodeName(&name, &dn);
+ if (rv == KMF_OK) {
+ rv = KMF_CompareRDNs(subject, &dn);
+ KMF_FreeDN(&dn);
+ }
+ free(certattr.pValue);
+ }
+ }
+
+ return (rv);
+}
+
+/*
+ * delete "curr" node from the "newlist".
+ */
+static void
+pk11_delete_obj_from_list(OBJLIST **newlist,
+ OBJLIST **prev, OBJLIST **curr)
+{
+
+ if (*curr == *newlist) {
+ /* first node in the list */
+ *newlist = (*curr)->next;
+ *prev = (*curr)->next;
+ free(*curr);
+ *curr = *newlist;
+ } else {
+ (*prev)->next = (*curr)->next;
+ free(*curr);
+ *curr = (*prev)->next;
+ }
+}
+
+/*
+ * prepare_object_search
+ *
+ * Because this code is shared by the FindCert and
+ * DeleteCert functions, put it in a separate routine
+ * to save some work and make code easier to debug and
+ * read.
+ */
+static KMF_RETURN
+search_certs(KMF_HANDLE_T handle,
+ char *label, char *issuer, char *subject, KMF_BIGINT *serial,
+ boolean_t private, KMF_CERT_VALIDITY validity,
+ OBJLIST **objlist, uint32_t *numobj)
+{
+ KMF_RETURN rv = KMF_OK;
+ CK_RV ckrv = CKR_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ CK_ATTRIBUTE templ[10];
+ CK_BBOOL true = TRUE;
+ CK_OBJECT_CLASS oclass = CKO_CERTIFICATE;
+ CK_CERTIFICATE_TYPE ctype = CKC_X_509;
+ KMF_X509_NAME subjectDN, issuerDN;
+ int i;
+ OBJLIST *newlist, *tail;
+ CK_ULONG num = 0;
+ uint32_t num_ok_certs = 0; /* number of non-expired or expired certs */
+
+ (void) memset(&templ, 0, 10 * sizeof (CK_ATTRIBUTE));
+ (void) memset(&issuerDN, 0, sizeof (KMF_X509_NAME));
+ (void) memset(&subjectDN, 0, sizeof (KMF_X509_NAME));
+ i = 0;
+ SETATTR(templ, i, CKA_TOKEN, &true, sizeof (true)); i++;
+ SETATTR(templ, i, CKA_CLASS, &oclass, sizeof (oclass)); i++;
+ SETATTR(templ, i, CKA_CERTIFICATE_TYPE, &ctype,
+ sizeof (ctype)); i++;
+
+ if (label != NULL && strlen(label)) {
+ SETATTR(templ, i, CKA_LABEL, label, strlen(label));
+ i++;
+ }
+ if (private) {
+ SETATTR(templ, i, CKA_PRIVATE, &true, sizeof (true)); i++;
+ }
+
+ if (issuer != NULL && strlen(issuer)) {
+ if ((rv = KMF_DNParser(issuer, &issuerDN)) != KMF_OK)
+ return (rv);
+ }
+ if (subject != NULL && strlen(subject)) {
+ if ((rv = KMF_DNParser(subject, &subjectDN)) != KMF_OK)
+ return (rv);
+ }
+
+ if (serial != NULL && serial->val != NULL && serial->len > 0) {
+ SETATTR(templ, i, CKA_SERIAL_NUMBER,
+ serial->val, serial->len);
+ i++;
+ }
+
+ (*numobj) = 0;
+ *objlist = NULL;
+ newlist = NULL;
+
+ ckrv = C_FindObjectsInit(kmfh->pk11handle, templ, i);
+ if (ckrv != CKR_OK)
+ goto cleanup;
+
+ tail = newlist = NULL;
+ while (ckrv == CKR_OK) {
+ CK_OBJECT_HANDLE tObj;
+ ckrv = C_FindObjects(kmfh->pk11handle, &tObj, 1, &num);
+ if (ckrv != CKR_OK || num == 0)
+ break;
+
+ /*
+ * 'matchcert' returns 0 if subject/issuer match
+ *
+ * If no match, move on to the next one
+ */
+ if (matchcert(kmfh, tObj, &issuerDN, &subjectDN))
+ continue;
+
+ if (newlist == NULL) {
+ newlist = malloc(sizeof (OBJLIST));
+ if (newlist == NULL) {
+ rv = KMF_ERR_MEMORY;
+ break;
+ }
+ newlist->handle = tObj;
+ newlist->next = NULL;
+ tail = newlist;
+ } else {
+ tail->next = malloc(sizeof (OBJLIST));
+ if (tail->next != NULL) {
+ tail = tail->next;
+ } else {
+ rv = KMF_ERR_MEMORY;
+ break;
+ }
+ tail->handle = tObj;
+ tail->next = NULL;
+ }
+ (*numobj)++;
+ }
+ ckrv = C_FindObjectsFinal(kmfh->pk11handle);
+
+cleanup:
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ if (newlist != NULL) {
+ free_objlist(newlist);
+ *numobj = 0;
+ newlist = NULL;
+ }
+ } else {
+ if (validity == KMF_ALL_CERTS) {
+ *objlist = newlist;
+ } else {
+ OBJLIST *node, *prev;
+ KMF_X509_DER_CERT tmp_kmf_cert;
+ uint32_t i = 0;
+
+ node = prev = newlist;
+ /*
+ * Now check to see if any found certificate is expired
+ * or valid.
+ */
+ while (node != NULL && i < (*numobj)) {
+ (void) memset(&tmp_kmf_cert, 0,
+ sizeof (KMF_X509_DER_CERT));
+ rv = PK11Cert2KMFCert(kmfh, node->handle,
+ &tmp_kmf_cert);
+ if (rv != KMF_OK) {
+ goto cleanup1;
+ }
+
+ rv = KMF_CheckCertDate(handle,
+ &tmp_kmf_cert.certificate);
+
+ if (validity == KMF_NONEXPIRED_CERTS) {
+ if (rv == KMF_OK) {
+ num_ok_certs++;
+ prev = node;
+ node = node->next;
+ } else if (rv ==
+ KMF_ERR_VALIDITY_PERIOD) {
+ /*
+ * expired - remove it from list
+ */
+ pk11_delete_obj_from_list(
+ &newlist, &prev, &node);
+ } else {
+ goto cleanup1;
+ }
+ }
+
+ if (validity == KMF_EXPIRED_CERTS) {
+ if (rv == KMF_ERR_VALIDITY_PERIOD) {
+ num_ok_certs++;
+ prev = node;
+ node = node->next;
+ rv = KMF_OK;
+ } else if (rv == KMF_OK) {
+ /*
+ * valid - remove it from list
+ */
+ pk11_delete_obj_from_list(
+ &newlist, &prev, &node);
+ } else {
+ goto cleanup1;
+ }
+ }
+ i++;
+ KMF_FreeKMFCert(handle, &tmp_kmf_cert);
+ }
+ *numobj = num_ok_certs;
+ *objlist = newlist;
+ }
+ }
+
+cleanup1:
+ if (rv != KMF_OK && newlist != NULL) {
+ free_objlist(newlist);
+ *numobj = 0;
+ *objlist = NULL;
+ }
+
+ if (issuer != NULL)
+ KMF_FreeDN(&issuerDN);
+
+ if (subject != NULL)
+ KMF_FreeDN(&subjectDN);
+
+ return (rv);
+}
+
+/*
+ * The caller may pass a NULL value for kmf_cert below and the function will
+ * just return the number of certs found (in num_certs).
+ */
+KMF_RETURN
+KMFPK11_FindCert(KMF_HANDLE_T handle, KMF_FINDCERT_PARAMS *params,
+ KMF_X509_DER_CERT *kmf_cert,
+ uint32_t *num_certs)
+{
+ KMF_RETURN rv = 0;
+ uint32_t want_certs;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ OBJLIST *objlist = NULL;
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (params == NULL || num_certs == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (*num_certs > 0)
+ want_certs = *num_certs;
+ else
+ want_certs = MAXINT; /* count them all */
+
+ *num_certs = 0;
+
+ rv = search_certs(handle,
+ params->certLabel, params->issuer,
+ params->subject, params->serial,
+ params->pkcs11parms.private,
+ params->find_cert_validity,
+ &objlist, num_certs);
+
+ if (rv == KMF_OK && objlist != NULL && kmf_cert != NULL) {
+ OBJLIST *node = objlist;
+ int i = 0;
+ while (node != NULL && i < want_certs) {
+ rv = PK11Cert2KMFCert(kmfh, node->handle,
+ &kmf_cert[i]);
+ i++;
+ node = node->next;
+ }
+ }
+
+ if (objlist != NULL)
+ free_objlist(objlist);
+
+ if (*num_certs == 0)
+ rv = KMF_ERR_CERT_NOT_FOUND;
+
+ return (rv);
+}
+
+/*ARGSUSED*/
+void
+KMFPK11_FreeKMFCert(KMF_HANDLE_T handle,
+ KMF_X509_DER_CERT *kmf_cert)
+{
+ if (kmf_cert != NULL && 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 != NULL) {
+ free(kmf_cert->kmf_private.label);
+ kmf_cert->kmf_private.label = NULL;
+ }
+ }
+}
+
+KMF_RETURN
+KMFPK11_EncodePubKeyData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *pKey,
+ KMF_DATA *eData)
+{
+ KMF_RETURN ret = KMF_OK;
+ CK_RV rv;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ CK_OBJECT_CLASS ckObjClass = CKO_PUBLIC_KEY;
+ CK_KEY_TYPE ckKeyType;
+ KMF_DATA Modulus, Exponent, Prime, Subprime, Base, Value;
+ KMF_OID *Algorithm;
+ BerElement *asn1 = NULL;
+ BerValue *PubKeyParams = NULL, *EncodedKey = NULL;
+ KMF_X509_SPKI spki;
+
+ CK_ATTRIBUTE rsaTemplate[4];
+ CK_ATTRIBUTE dsaTemplate[6];
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (pKey == NULL || pKey->keyp == CK_INVALID_HANDLE)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ (void) memset(&Modulus, 0, sizeof (Modulus));
+ (void) memset(&Exponent, 0, sizeof (Exponent));
+ (void) memset(&Prime, 0, sizeof (Prime));
+ (void) memset(&Subprime, 0, sizeof (Subprime));
+ (void) memset(&Base, 0, sizeof (Base));
+ (void) memset(&Value, 0, sizeof (Value));
+
+ SETATTR(rsaTemplate, 0, CKA_CLASS, &ckObjClass, sizeof (ckObjClass));
+ SETATTR(rsaTemplate, 1, CKA_KEY_TYPE, &ckKeyType, sizeof (ckKeyType));
+ SETATTR(rsaTemplate, 2, CKA_MODULUS, Modulus.Data, &Modulus.Length);
+ SETATTR(rsaTemplate, 3, CKA_PUBLIC_EXPONENT, Exponent.Data,
+ &Exponent.Length);
+
+ SETATTR(dsaTemplate, 0, CKA_CLASS, &ckObjClass, sizeof (ckObjClass));
+ SETATTR(dsaTemplate, 1, CKA_KEY_TYPE, &ckKeyType, sizeof (ckKeyType));
+ SETATTR(dsaTemplate, 2, CKA_PRIME, Prime.Data, &Prime.Length);
+ SETATTR(dsaTemplate, 3, CKA_SUBPRIME, Subprime.Data, &Subprime.Length);
+ SETATTR(dsaTemplate, 4, CKA_BASE, Base.Data, &Base.Length);
+ SETATTR(dsaTemplate, 5, CKA_VALUE, Value.Data, &Value.Length);
+
+ switch (pKey->keyalg) {
+ case KMF_RSA:
+ /* Get the length of the fields */
+ rv = C_GetAttributeValue(kmfh->pk11handle,
+ (CK_OBJECT_HANDLE)pKey->keyp,
+ rsaTemplate, 4);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ Modulus.Length = rsaTemplate[2].ulValueLen;
+ Modulus.Data = malloc(Modulus.Length);
+ if (Modulus.Data == NULL)
+ return (KMF_ERR_MEMORY);
+
+ Exponent.Length = rsaTemplate[3].ulValueLen;
+ Exponent.Data = malloc(Exponent.Length);
+ if (Exponent.Data == NULL) {
+ free(Modulus.Data);
+ return (KMF_ERR_MEMORY);
+ }
+
+ SETATTR(rsaTemplate, 2, CKA_MODULUS, Modulus.Data,
+ Modulus.Length);
+ SETATTR(rsaTemplate, 3, CKA_PUBLIC_EXPONENT,
+ Exponent.Data, Exponent.Length);
+ /* Now get the values */
+ rv = C_GetAttributeValue(kmfh->pk11handle,
+ (CK_OBJECT_HANDLE)pKey->keyp,
+ rsaTemplate, 4);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ free(Modulus.Data);
+ free(Exponent.Data);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /*
+ * This is the KEY algorithm, not the
+ * signature algorithm.
+ */
+ Algorithm = X509_AlgIdToAlgorithmOid(KMF_ALGID_RSA);
+ if (Algorithm != NULL) {
+
+ /* Encode the RSA Key Data */
+ if ((asn1 = kmfder_alloc()) == NULL) {
+ free(Modulus.Data);
+ free(Exponent.Data);
+ return (KMF_ERR_MEMORY);
+ }
+ if (kmfber_printf(asn1, "{II}",
+ Modulus.Data, Modulus.Length,
+ Exponent.Data, Exponent.Length) == -1) {
+ kmfber_free(asn1, 1);
+ free(Modulus.Data);
+ free(Exponent.Data);
+ return (KMF_ERR_ENCODING);
+ }
+ if (kmfber_flatten(asn1, &EncodedKey) == -1) {
+ kmfber_free(asn1, 1);
+ free(Modulus.Data);
+ free(Exponent.Data);
+ return (KMF_ERR_ENCODING);
+ }
+ kmfber_free(asn1, 1);
+ }
+
+ free(Exponent.Data);
+ free(Modulus.Data);
+
+ break;
+ case KMF_DSA:
+ /* Get the length of the fields */
+ rv = C_GetAttributeValue(kmfh->pk11handle,
+ (CK_OBJECT_HANDLE)pKey->keyp,
+ dsaTemplate, 6);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+ Prime.Length = dsaTemplate[2].ulValueLen;
+ Prime.Data = malloc(Prime.Length);
+ if (Prime.Data == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+
+ Subprime.Length = dsaTemplate[3].ulValueLen;
+ Subprime.Data = malloc(Subprime.Length);
+ if (Subprime.Data == NULL) {
+ free(Prime.Data);
+ return (KMF_ERR_MEMORY);
+ }
+
+ Base.Length = dsaTemplate[4].ulValueLen;
+ Base.Data = malloc(Base.Length);
+ if (Base.Data == NULL) {
+ free(Prime.Data);
+ free(Subprime.Data);
+ return (KMF_ERR_MEMORY);
+ }
+
+ Value.Length = dsaTemplate[5].ulValueLen;
+ Value.Data = malloc(Value.Length);
+ if (Value.Data == NULL) {
+ free(Prime.Data);
+ free(Subprime.Data);
+ free(Base.Data);
+ return (KMF_ERR_MEMORY);
+ }
+ SETATTR(dsaTemplate, 2, CKA_PRIME, Prime.Data,
+ Prime.Length);
+ SETATTR(dsaTemplate, 3, CKA_SUBPRIME, Subprime.Data,
+ Subprime.Length);
+ SETATTR(dsaTemplate, 4, CKA_BASE, Base.Data,
+ Base.Length);
+ SETATTR(dsaTemplate, 5, CKA_VALUE, Value.Data,
+ Value.Length);
+
+ /* Now get the values */
+ rv = C_GetAttributeValue(kmfh->pk11handle,
+ (CK_OBJECT_HANDLE)pKey->keyp,
+ dsaTemplate, 6);
+ if (rv != CKR_OK) {
+ free(Prime.Data);
+ free(Subprime.Data);
+ free(Base.Data);
+ free(Value.Data);
+ SET_ERROR(kmfh, rv);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+ /*
+ * This is the KEY algorithm, not the
+ * signature algorithm.
+ */
+ Algorithm =
+ X509_AlgIdToAlgorithmOid(KMF_ALGID_DSA);
+
+ /* Encode the DSA Algorithm Parameters */
+ if ((asn1 = kmfder_alloc()) == NULL) {
+ free(Prime.Data);
+ free(Subprime.Data);
+ free(Base.Data);
+ free(Value.Data);
+ return (KMF_ERR_MEMORY);
+ }
+
+ if (kmfber_printf(asn1, "{III}",
+ Prime.Data, Prime.Length,
+ Subprime.Data, Subprime.Length,
+ Base.Data, Base.Length) == -1) {
+
+ kmfber_free(asn1, 1);
+ free(Prime.Data);
+ free(Subprime.Data);
+ free(Base.Data);
+ free(Value.Data);
+ return (KMF_ERR_ENCODING);
+ }
+ if (kmfber_flatten(asn1, &PubKeyParams) == -1) {
+ kmfber_free(asn1, 1);
+ free(Prime.Data);
+ free(Subprime.Data);
+ free(Base.Data);
+ free(Value.Data);
+ return (KMF_ERR_ENCODING);
+ }
+ kmfber_free(asn1, 1);
+ free(Prime.Data);
+ free(Subprime.Data);
+ free(Base.Data);
+
+ /* Encode the DSA Key Value */
+ if ((asn1 = kmfder_alloc()) == NULL) {
+ free(Value.Data);
+ return (KMF_ERR_MEMORY);
+ }
+
+ if (kmfber_printf(asn1, "I",
+ Value.Data, Value.Length) == -1) {
+ kmfber_free(asn1, 1);
+ free(Value.Data);
+ return (KMF_ERR_ENCODING);
+ }
+ if (kmfber_flatten(asn1, &EncodedKey) == -1) {
+ kmfber_free(asn1, 1);
+ free(Value.Data);
+ return (KMF_ERR_ENCODING);
+ }
+ kmfber_free(asn1, 1);
+ free(Value.Data);
+ break;
+ default:
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /* Now, build an SPKI structure for the final encoding step */
+ spki.algorithm.algorithm = *Algorithm;
+ if (PubKeyParams != NULL) {
+ spki.algorithm.parameters.Data =
+ (uchar_t *)PubKeyParams->bv_val;
+ spki.algorithm.parameters.Length = PubKeyParams->bv_len;
+ } else {
+ spki.algorithm.parameters.Data = NULL;
+ spki.algorithm.parameters.Length = 0;
+ }
+
+ if (EncodedKey != NULL) {
+ spki.subjectPublicKey.Data = (uchar_t *)EncodedKey->bv_val;
+ spki.subjectPublicKey.Length = EncodedKey->bv_len;
+ } else {
+ spki.subjectPublicKey.Data = NULL;
+ spki.subjectPublicKey.Length = 0;
+ }
+
+ /* Finally, encode the entire SPKI record */
+ ret = DerEncodeSPKI(&spki, eData);
+
+cleanup:
+ if (EncodedKey) {
+ free(EncodedKey->bv_val);
+ free(EncodedKey);
+ }
+
+ if (PubKeyParams) {
+ free(PubKeyParams->bv_val);
+ free(PubKeyParams);
+ }
+
+ return (ret);
+}
+
+
+static KMF_RETURN
+CreateCertObject(KMF_HANDLE_T handle, char *label, KMF_DATA *pcert)
+{
+ KMF_RETURN rv = 0;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ KMF_X509_CERTIFICATE *signed_cert_ptr = NULL;
+ KMF_DATA data;
+ KMF_DATA Id;
+
+ CK_RV ckrv;
+ CK_ULONG subject_len, issuer_len, serno_len;
+ CK_BYTE *subject, *issuer, *serial;
+ CK_BBOOL true = TRUE;
+ CK_CERTIFICATE_TYPE certtype = CKC_X_509;
+ CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
+ CK_ATTRIBUTE x509templ[11];
+ CK_OBJECT_HANDLE hCert = NULL;
+ int i;
+
+ if (!kmfh)
+ return (KMF_ERR_INTERNAL); /* should not happen */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_INTERNAL); /* should not happen */
+
+ if (pcert == NULL || pcert->Data == NULL || pcert->Length == 0)
+ return (KMF_ERR_INTERNAL); /* should not happen */
+
+ /*
+ * The data *must* be a DER encoded X.509 certificate.
+ * Convert it to a CSSM cert and then parse the fields so
+ * the PKCS#11 attributes can be filled in correctly.
+ */
+ rv = DerDecodeSignedCertificate((const KMF_DATA *)pcert,
+ &signed_cert_ptr);
+ if (rv != KMF_OK) {
+ return (KMF_ERR_ENCODING);
+ }
+
+ /*
+ * Encode fields into PKCS#11 attributes.
+ */
+
+ /* Get the subject name */
+ rv = DerEncodeName(&signed_cert_ptr->certificate.subject, &data);
+ if (rv == KMF_OK) {
+ subject = data.Data;
+ subject_len = data.Length;
+ } else {
+ rv = KMF_ERR_ENCODING;
+ goto cleanup;
+ }
+
+ /* Encode the issuer */
+ rv = DerEncodeName(&signed_cert_ptr->certificate.issuer, &data);
+ if (rv == KMF_OK) {
+ issuer = data.Data;
+ issuer_len = data.Length;
+ } else {
+ rv = KMF_ERR_ENCODING;
+ goto cleanup;
+ }
+
+ /* Encode serial number */
+ if (signed_cert_ptr->certificate.serialNumber.len > 0 &&
+ signed_cert_ptr->certificate.serialNumber.val != NULL) {
+ serial = signed_cert_ptr->certificate.serialNumber.val;
+ serno_len = signed_cert_ptr->certificate.serialNumber.len;
+ } else {
+ rv = KMF_ERR_ENCODING;
+ goto cleanup;
+ }
+
+ /* Generate an ID from the SPKI data */
+ rv = GetIDFromSPKI(&signed_cert_ptr->certificate.subjectPublicKeyInfo,
+ &Id);
+
+ if (rv != KMF_OK) {
+ SET_ERROR(kmfh, rv);
+ goto cleanup;
+ }
+
+ i = 0;
+ SETATTR(x509templ, i, CKA_CLASS, &certClass,
+ sizeof (certClass)); i++;
+ SETATTR(x509templ, i, CKA_CERTIFICATE_TYPE, &certtype,
+ sizeof (certtype)); i++;
+ SETATTR(x509templ, i, CKA_TOKEN, &true, sizeof (true)); i++;
+ SETATTR(x509templ, i, CKA_SUBJECT, subject, subject_len); i++;
+ SETATTR(x509templ, i, CKA_ISSUER, issuer, issuer_len); i++;
+ SETATTR(x509templ, i, CKA_SERIAL_NUMBER, serial, serno_len); i++;
+ SETATTR(x509templ, i, CKA_VALUE, pcert->Data, pcert->Length); i++;
+ SETATTR(x509templ, i, CKA_ID, Id.Data, Id.Length); i++;
+ if (label != NULL && strlen(label)) {
+ SETATTR(x509templ, i, CKA_LABEL, label, strlen(label));
+ i++;
+ }
+
+ /*
+ * The cert object handle is actually "leaked" here. If the app
+ * really wants to clean up the data space, it will have to call
+ * KMF_DeleteCert and specify the softtoken keystore.
+ */
+ ckrv = C_CreateObject(kmfh->pk11handle, x509templ, i, &hCert);
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ rv = KMF_ERR_INTERNAL;
+ }
+ free(subject);
+ free(issuer);
+
+cleanup:
+ if (Id.Data != NULL)
+ free(Id.Data);
+
+ if (signed_cert_ptr) {
+ KMF_FreeSignedCert(signed_cert_ptr);
+ free(signed_cert_ptr);
+ }
+ return (rv);
+}
+
+
+KMF_RETURN
+KMFPK11_StoreCert(KMF_HANDLE_T handle, KMF_STORECERT_PARAMS *params,
+ KMF_DATA *pcert)
+{
+ KMF_RETURN rv = 0;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (pcert == NULL || pcert->Data == NULL || pcert->Length == 0)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = CreateCertObject(handle, params->certLabel, pcert);
+ return (rv);
+}
+
+
+
+KMF_RETURN
+KMFPK11_ImportCert(KMF_HANDLE_T handle, KMF_IMPORTCERT_PARAMS *params)
+{
+ KMF_RETURN rv = 0;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_ENCODE_FORMAT format;
+ KMF_DATA cert1 = { NULL, 0};
+ KMF_DATA cert2 = { NULL, 0};
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (params == NULL || params->certfile == NULL) {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ /*
+ * Check if the input cert file is a valid certificate and
+ * auto-detect the file format of it.
+ */
+ rv = KMF_IsCertFile(handle, params->certfile, &format);
+ if (rv != KMF_OK)
+ return (rv);
+
+ /* Read in the CERT file */
+ rv = KMF_ReadInputFile(handle, params->certfile, &cert1);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ /*
+ * If the input certificate is in PEM format, we need to convert
+ * it to DER first.
+ */
+ if (format == KMF_FORMAT_PEM) {
+ int derlen;
+ rv = KMF_Pem2Der(cert1.Data, cert1.Length,
+ &cert2.Data, &derlen);
+ if (rv != KMF_OK) {
+ goto out;
+ }
+ cert2.Length = (size_t)derlen;
+ }
+
+ rv = CreateCertObject(handle, params->certLabel,
+ format == KMF_FORMAT_ASN1 ? &cert1 : &cert2);
+
+out:
+ if (cert1.Data != NULL) {
+ free(cert1.Data);
+ }
+
+ if (cert2.Data != NULL) {
+ free(cert2.Data);
+ }
+
+ return (rv);
+}
+
+KMF_RETURN
+KMFPK11_DeleteCert(KMF_HANDLE_T handle, KMF_DELETECERT_PARAMS *params)
+{
+ KMF_RETURN rv = 0;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ OBJLIST *objlist;
+ uint32_t numObjects = 0;
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /*
+ * Use the same search routine as is used for the FindCert
+ * operation.
+ */
+ objlist = NULL;
+ rv = search_certs(handle,
+ params->certLabel, params->issuer,
+ params->subject, params->serial,
+ params->pkcs11parms.private,
+ params->find_cert_validity,
+ &objlist, &numObjects);
+
+ if (rv == KMF_OK && objlist != NULL) {
+ OBJLIST *node = objlist;
+
+ while (node != NULL) {
+ CK_RV ckrv;
+ ckrv = C_DestroyObject(kmfh->pk11handle,
+ node->handle);
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ break;
+ }
+ node = node->next;
+ }
+ free_objlist(objlist);
+ }
+
+ if (rv == KMF_OK && numObjects == 0)
+ rv = KMF_ERR_CERT_NOT_FOUND;
+
+out:
+ return (rv);
+}
+
+KMF_RETURN
+KMFPK11_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;
+
+ CK_RV ckrv = 0;
+ CK_OBJECT_HANDLE pubKey = CK_INVALID_HANDLE;
+ CK_OBJECT_HANDLE priKey = CK_INVALID_HANDLE;
+ CK_SESSION_HANDLE hSession = kmfh->pk11handle;
+
+ static CK_OBJECT_CLASS priClass = CKO_PRIVATE_KEY;
+ static CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY;
+
+ static CK_ULONG rsaKeyType = CKK_RSA;
+ static CK_ULONG modulusBits = 1024;
+ static CK_BYTE PubExpo[3] = {0x01, 0x00, 0x01};
+ static CK_BBOOL true = TRUE;
+ static CK_BBOOL ontoken = TRUE;
+ static CK_BBOOL false = FALSE;
+ static CK_ULONG dsaKeyType = CKK_DSA;
+
+ CK_ATTRIBUTE rsaPubKeyTemplate[8];
+ CK_ATTRIBUTE rsaPriKeyTemplate[6];
+
+ static CK_BYTE ckDsaPrime[128] = {
+ 0xb2, 0x6b, 0xc3, 0xfb, 0xe3, 0x26, 0xf4, 0xc2,
+ 0xcf, 0xdd, 0xf9, 0xae, 0x3e, 0x39, 0x7f, 0x9c,
+ 0xa7, 0x73, 0xc3, 0x00, 0xa3, 0x50, 0x67, 0xc3,
+ 0xab, 0x49, 0x2c, 0xea, 0x59, 0x10, 0xa4, 0xbc,
+ 0x09, 0x94, 0xa9, 0x05, 0x3b, 0x0d, 0x35, 0x3c,
+ 0x55, 0x52, 0x47, 0xf0, 0xe3, 0x72, 0x5b, 0xe8,
+ 0x72, 0xa0, 0x71, 0x1c, 0x23, 0x4f, 0x6d, 0xe8,
+ 0xac, 0xe5, 0x21, 0x1b, 0xc0, 0xd8, 0x42, 0xd3,
+ 0x87, 0xae, 0x83, 0x5e, 0x52, 0x7e, 0x46, 0x09,
+ 0xb5, 0xc7, 0x3d, 0xd6, 0x00, 0xf5, 0xf2, 0x9c,
+ 0x84, 0x30, 0x81, 0x7e, 0x7b, 0x30, 0x5b, 0xd5,
+ 0xab, 0xd0, 0x2f, 0x21, 0xb3, 0xd8, 0xed, 0xdb,
+ 0x97, 0x77, 0xe4, 0x7e, 0x6c, 0xcc, 0xb9, 0x6b,
+ 0xdd, 0xaa, 0x96, 0x04, 0xe7, 0xd4, 0x55, 0x11,
+ 0x53, 0xab, 0xba, 0x95, 0x9a, 0xa2, 0x8c, 0x27,
+ 0xd9, 0xcf, 0xad, 0xf3, 0xcf, 0x3a, 0x0c, 0x4b};
+
+ static CK_BYTE ckDsaSubPrime[20] = {
+ 0xa4, 0x5f, 0x2a, 0x27, 0x09, 0x49, 0xb6, 0xfe,
+ 0x73, 0xeb, 0x95, 0x7d, 0x00, 0xf3, 0x42, 0xfc,
+ 0x78, 0x47, 0xb0, 0xd5};
+
+ static CK_BYTE ckDsaBase[128] = {
+ 0x5c, 0x57, 0x16, 0x49, 0xef, 0xc8, 0xfb, 0x4b,
+ 0xee, 0x07, 0x45, 0x3b, 0x6a, 0x1d, 0xf3, 0xe5,
+ 0xeb, 0xee, 0xad, 0x11, 0x13, 0xe3, 0x52, 0xe3,
+ 0x0d, 0xc0, 0x21, 0x25, 0xfa, 0xf0, 0x93, 0x1c,
+ 0x53, 0x4d, 0xdc, 0x0d, 0x76, 0xd2, 0xfe, 0xc2,
+ 0xd7, 0x72, 0x64, 0x69, 0x53, 0x3d, 0x33, 0xbd,
+ 0xe1, 0x34, 0xf2, 0x5a, 0x67, 0x83, 0xe0, 0xd3,
+ 0x1c, 0xd6, 0x41, 0x4d, 0x16, 0xe8, 0x6c, 0x5a,
+ 0x07, 0x95, 0x21, 0x9a, 0xa3, 0xc4, 0xb9, 0x05,
+ 0x9d, 0x11, 0xcb, 0xc8, 0xc4, 0x9d, 0x00, 0x1a,
+ 0xf4, 0x85, 0x2a, 0xa9, 0x20, 0x3c, 0xba, 0x67,
+ 0xe5, 0xed, 0x31, 0xb2, 0x11, 0xfb, 0x1f, 0x73,
+ 0xec, 0x61, 0x29, 0xad, 0xc7, 0x68, 0xb2, 0x3f,
+ 0x38, 0xea, 0xd9, 0x87, 0x83, 0x9e, 0x7e, 0x19,
+ 0x18, 0xdd, 0xc2, 0xc3, 0x5b, 0x16, 0x6d, 0xce,
+ 0xcf, 0x88, 0x91, 0x07, 0xe0, 0x2b, 0xa8, 0x54 };
+
+ static CK_ATTRIBUTE ckDsaPubKeyTemplate[] = {
+ { CKA_CLASS, &pubClass, sizeof (pubClass) },
+ { CKA_KEY_TYPE, &dsaKeyType, sizeof (dsaKeyType) },
+ { CKA_TOKEN, &ontoken, sizeof (ontoken)},
+ { CKA_PRIVATE, &false, sizeof (false)},
+ { CKA_PRIME, &ckDsaPrime, sizeof (ckDsaPrime) },
+ { CKA_SUBPRIME, &ckDsaSubPrime, sizeof (ckDsaSubPrime)},
+ { CKA_BASE, &ckDsaBase, sizeof (ckDsaBase) },
+ { CKA_VERIFY, &true, sizeof (true) },
+};
+
+#define NUMBER_DSA_PUB_TEMPLATES (sizeof (ckDsaPubKeyTemplate) / \
+ sizeof (CK_ATTRIBUTE))
+#define MAX_DSA_PUB_TEMPLATES (sizeof (ckDsaPubKeyTemplate) / \
+ sizeof (CK_ATTRIBUTE))
+
+ static CK_ATTRIBUTE ckDsaPriKeyTemplate[] = {
+ {CKA_CLASS, &priClass, sizeof (priClass)},
+ {CKA_KEY_TYPE, &dsaKeyType, sizeof (dsaKeyType)},
+ {CKA_TOKEN, &ontoken, sizeof (ontoken)},
+ {CKA_PRIVATE, &true, sizeof (true)},
+ {CKA_SIGN, &true, sizeof (true)},
+ };
+
+ CK_ATTRIBUTE labelattr[1];
+ CK_ATTRIBUTE idattr[1];
+ char IDHashData[SHA1_HASH_LENGTH];
+ KMF_DATA IDInput, IDOutput;
+
+#define NUMBER_DSA_PRI_TEMPLATES (sizeof (ckDsaPriKeyTemplate) / \
+ sizeof (CK_ATTRIBUTE))
+#define MAX_DSA_PRI_TEMPLATES (sizeof (ckDsaPriKeyTemplate) / \
+ sizeof (CK_ATTRIBUTE))
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = pk11_authenticate(handle, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ if (params->keytype == KMF_RSA) {
+ CK_MECHANISM keyGenMech = {CKM_RSA_PKCS_KEY_PAIR_GEN,
+ NULL, 0};
+ CK_BYTE *modulus;
+ CK_ULONG modulusLength;
+ CK_ATTRIBUTE modattr[1];
+
+ SETATTR(rsaPubKeyTemplate, 0, CKA_CLASS,
+ &pubClass, sizeof (pubClass));
+ SETATTR(rsaPubKeyTemplate, 1, CKA_KEY_TYPE,
+ &rsaKeyType, sizeof (rsaKeyType));
+ SETATTR(rsaPubKeyTemplate, 2, CKA_TOKEN,
+ &false, sizeof (false));
+ SETATTR(rsaPubKeyTemplate, 3, CKA_PRIVATE,
+ &false, sizeof (false));
+ SETATTR(rsaPubKeyTemplate, 4, CKA_MODULUS_BITS,
+ &modulusBits, sizeof (modulusBits));
+ if (params->rsa_exponent.len > 0 &&
+ params->rsa_exponent.val != NULL) {
+ SETATTR(rsaPubKeyTemplate, 5,
+ CKA_PUBLIC_EXPONENT,
+ params->rsa_exponent.val,
+ params->rsa_exponent.len);
+ } else {
+ SETATTR(rsaPubKeyTemplate, 5,
+ CKA_PUBLIC_EXPONENT, &PubExpo,
+ sizeof (PubExpo));
+ }
+ SETATTR(rsaPubKeyTemplate, 6, CKA_ENCRYPT,
+ &true, sizeof (true));
+ SETATTR(rsaPubKeyTemplate, 7, CKA_VERIFY,
+ &true, sizeof (true));
+
+ SETATTR(rsaPriKeyTemplate, 0, CKA_CLASS, &priClass,
+ sizeof (priClass));
+ SETATTR(rsaPriKeyTemplate, 1, CKA_KEY_TYPE, &rsaKeyType,
+ sizeof (rsaKeyType));
+ SETATTR(rsaPriKeyTemplate, 2, CKA_TOKEN, &ontoken,
+ sizeof (ontoken));
+ SETATTR(rsaPriKeyTemplate, 3, CKA_PRIVATE, &true,
+ sizeof (true));
+ SETATTR(rsaPriKeyTemplate, 4, CKA_DECRYPT, &true,
+ sizeof (true));
+ SETATTR(rsaPriKeyTemplate, 5, CKA_SIGN, &true,
+ sizeof (true));
+
+ SETATTR(modattr, 0, CKA_MODULUS, NULL, &modulusLength);
+
+ modulusBits = params->keylength;
+
+ pubKey = CK_INVALID_HANDLE;
+ priKey = CK_INVALID_HANDLE;
+ ckrv = C_GenerateKeyPair(hSession, &keyGenMech,
+ rsaPubKeyTemplate,
+ (sizeof (rsaPubKeyTemplate)/sizeof (CK_ATTRIBUTE)),
+ rsaPriKeyTemplate,
+ (sizeof (rsaPriKeyTemplate)/sizeof (CK_ATTRIBUTE)),
+ &pubKey, &priKey);
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_KEYGEN_FAILED);
+ }
+
+ if (privkey != NULL) {
+ privkey->kstype = KMF_KEYSTORE_PK11TOKEN;
+ privkey->keyalg = KMF_RSA;
+ privkey->keyclass = KMF_ASYM_PRI;
+ privkey->keyp = (void *)priKey;
+ }
+ if (pubkey != NULL) {
+ pubkey->kstype = KMF_KEYSTORE_PK11TOKEN;
+ pubkey->keyalg = KMF_RSA;
+ pubkey->keyclass = KMF_ASYM_PUB;
+ pubkey->keyp = (void *)pubKey;
+ }
+
+ /* Get the Modulus field to use as input for creating the ID */
+ rv = C_GetAttributeValue(kmfh->pk11handle,
+ (CK_OBJECT_HANDLE)pubKey,
+ modattr, 1);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ modulusLength = modattr[0].ulValueLen;
+ modulus = malloc(modulusLength);
+ if (modulus == NULL)
+ return (KMF_ERR_MEMORY);
+
+ modattr[0].pValue = modulus;
+ rv = C_GetAttributeValue(kmfh->pk11handle,
+ (CK_OBJECT_HANDLE)pubKey,
+ modattr, 1);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ free(modulus);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ IDInput.Data = modulus;
+ IDInput.Length = modulusLength;
+
+ } else if (params->keytype == KMF_DSA) {
+ CK_MECHANISM keyGenMech = {CKM_DSA_KEY_PAIR_GEN, NULL, 0};
+ CK_BYTE *keyvalue;
+ CK_ULONG valueLen;
+ CK_ATTRIBUTE valattr[1];
+
+ SETATTR(ckDsaPriKeyTemplate, 2, CKA_TOKEN,
+ &ontoken, sizeof (ontoken));
+ SETATTR(valattr, 0, CKA_VALUE, NULL, &valueLen);
+
+ ckrv = C_GenerateKeyPair(hSession, &keyGenMech,
+ ckDsaPubKeyTemplate,
+ (sizeof (ckDsaPubKeyTemplate)/sizeof (CK_ATTRIBUTE)),
+ ckDsaPriKeyTemplate,
+ (sizeof (ckDsaPriKeyTemplate)/sizeof (CK_ATTRIBUTE)),
+ &pubKey, &priKey);
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_KEYGEN_FAILED);
+ }
+
+ if (privkey != NULL) {
+ privkey->kstype = KMF_KEYSTORE_PK11TOKEN;
+ privkey->keyalg = KMF_DSA;
+ privkey->keyclass = KMF_ASYM_PRI;
+ privkey->keyp = (void *)priKey;
+ }
+ if (pubkey != NULL) {
+ pubkey->kstype = KMF_KEYSTORE_PK11TOKEN;
+ pubkey->keyalg = KMF_DSA;
+ pubkey->keyclass = KMF_ASYM_PUB;
+ pubkey->keyp = (void *)pubKey;
+ }
+ /* Get the Public Value to use as input for creating the ID */
+ rv = C_GetAttributeValue(hSession,
+ (CK_OBJECT_HANDLE)pubKey,
+ valattr, 1);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ valueLen = valattr[0].ulValueLen;
+ keyvalue = malloc(valueLen);
+ if (keyvalue == NULL)
+ return (KMF_ERR_MEMORY);
+
+ valattr[0].pValue = keyvalue;
+ rv = C_GetAttributeValue(hSession,
+ (CK_OBJECT_HANDLE)pubKey,
+ valattr, 1);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ free(keyvalue);
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ IDInput.Data = keyvalue;
+ IDInput.Length = valueLen;
+ } else {
+ return (KMF_ERR_BAD_PARAMETER);
+ }
+
+ if (params->keylabel != NULL &&
+ strlen(params->keylabel)) {
+
+ SETATTR(labelattr, 0, CKA_LABEL, params->keylabel,
+ strlen(params->keylabel));
+
+ /* Set the CKA_LABEL if one was indicated */
+ if ((ckrv = C_SetAttributeValue(hSession, pubKey,
+ labelattr, 1)) != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ goto cleanup;
+ }
+ if (pubkey != NULL) {
+ pubkey->keylabel =
+ (char *)strdup(params->keylabel);
+ if (pubkey->keylabel == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ }
+ if ((ckrv = C_SetAttributeValue(hSession, priKey,
+ labelattr, 1)) != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ goto cleanup;
+ }
+ if (privkey != NULL) {
+ privkey->keylabel =
+ (char *)strdup(params->keylabel);
+ if (privkey->keylabel == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto cleanup;
+ }
+ }
+ }
+
+ /* Now, assign a CKA_ID value so it can be searched */
+ /* ID_Input was assigned above in the RSA or DSA keygen section */
+ IDOutput.Data = (uchar_t *)IDHashData;
+ IDOutput.Length = sizeof (IDHashData);
+
+ rv = DigestData(hSession, &IDInput, &IDOutput);
+ free(IDInput.Data);
+
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ goto cleanup;
+ }
+ SETATTR(idattr, 0, CKA_ID, IDOutput.Data, IDOutput.Length);
+ if ((ckrv = C_SetAttributeValue(hSession, pubKey,
+ idattr, 1)) != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ goto cleanup;
+ }
+ if ((ckrv = C_SetAttributeValue(hSession, priKey,
+ idattr, 1)) != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ goto cleanup;
+ }
+
+cleanup:
+ if (rv != KMF_OK) {
+ if (pubKey != CK_INVALID_HANDLE)
+ (void) C_DestroyObject(hSession, pubKey);
+ if (priKey != CK_INVALID_HANDLE)
+ (void) C_DestroyObject(hSession, priKey);
+ if (privkey) {
+ privkey->keyp = NULL;
+ if (privkey->keylabel)
+ free(privkey->keylabel);
+ }
+ if (pubkey) {
+ pubkey->keyp = NULL;
+ if (pubkey->keylabel)
+ free(pubkey->keylabel);
+ }
+ }
+ return (rv);
+}
+
+KMF_RETURN
+KMFPK11_DeleteKey(KMF_HANDLE_T handle, KMF_DELETEKEY_PARAMS *params,
+ KMF_KEY_HANDLE *key, boolean_t destroy)
+{
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ CK_RV ckrv = CKR_OK;
+ KMF_RETURN rv = KMF_OK;
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ 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 (destroy) {
+ rv = pk11_authenticate(handle, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+ }
+
+ if (!key->israw && destroy)
+ ckrv = C_DestroyObject(kmfh->pk11handle,
+ (CK_OBJECT_HANDLE)key->keyp);
+
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ /* Report authentication failures to the caller */
+ if (ckrv == CKR_PIN_EXPIRED ||
+ ckrv == CKR_SESSION_READ_ONLY)
+ rv = KMF_ERR_AUTH_FAILED;
+ else
+ rv = KMF_ERR_INTERNAL;
+ }
+ return (rv);
+
+}
+
+KMF_RETURN
+KMFPK11_SignData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *keyp,
+ KMF_OID *algOID,
+ KMF_DATA *tobesigned,
+ KMF_DATA *output)
+{
+ CK_RV ckrv;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ CK_SESSION_HANDLE hSession = kmfh->pk11handle;
+ CK_MECHANISM mechanism;
+ PKCS_ALGORITHM_MAP *pAlgMap;
+ KMF_ALGORITHM_INDEX AlgId;
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (keyp == NULL || algOID == NULL ||
+ tobesigned == NULL || output == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* These functions are available to the plugin from libkmf */
+ AlgId = X509_AlgorithmOidToAlgId(algOID);
+ if (AlgId == KMF_ALGID_NONE)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* Map the Algorithm OID to a PKCS#11 mechanism */
+ pAlgMap = PKCS_GetAlgorithmMap(KMF_ALGCLASS_SIGNATURE,
+ AlgId, PKCS_GetDefaultSignatureMode(AlgId));
+
+ if (pAlgMap == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ mechanism.mechanism = pAlgMap->pkcs_mechanism;
+ mechanism.pParameter = NULL;
+ mechanism.ulParameterLen = 0;
+
+ ckrv = C_SignInit(hSession, &mechanism, (CK_OBJECT_HANDLE)keyp->keyp);
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ ckrv = C_Sign(hSession,
+ tobesigned->Data, tobesigned->Length,
+ output->Data, (CK_ULONG *)&output->Length);
+
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ return (KMF_OK);
+}
+
+KMF_RETURN
+KMFPK11_GetErrorString(KMF_HANDLE_T handle, char **msgstr)
+{
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ *msgstr = NULL;
+ if (kmfh->lasterr.errcode != 0) {
+ char *e = pkcs11_strerror(kmfh->lasterr.errcode);
+ if (e == NULL || (*msgstr = (char *)strdup(e)) == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+ }
+
+ return (KMF_OK);
+}
+
+static CK_RV
+getObjectKeytype(KMF_HANDLE_T handle, CK_OBJECT_HANDLE obj,
+ CK_ULONG *keytype)
+{
+ CK_RV rv = CKR_OK;
+ CK_ATTRIBUTE templ;
+ CK_ULONG len = sizeof (CK_ULONG);
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ templ.type = CKA_KEY_TYPE;
+ templ.pValue = keytype;
+ templ.ulValueLen = len;
+
+ rv = C_GetAttributeValue(kmfh->pk11handle, obj, &templ, 1);
+
+ return (rv);
+
+}
+static CK_RV
+getObjectLabel(KMF_HANDLE_T handle, CK_OBJECT_HANDLE obj,
+ char **outlabel)
+{
+ CK_RV rv = CKR_OK;
+ CK_ATTRIBUTE templ;
+ char Label[BUFSIZ];
+ CK_ULONG len = sizeof (Label);
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ (void) memset(Label, 0, len);
+ templ.type = CKA_LABEL;
+ templ.pValue = Label;
+ templ.ulValueLen = len;
+
+ rv = C_GetAttributeValue(kmfh->pk11handle, obj, &templ, 1);
+ if (rv == CKR_OK) {
+ *outlabel = (char *)strdup(Label);
+ } else {
+ *outlabel = NULL;
+ }
+ return (rv);
+}
+
+KMF_RETURN
+KMFPK11_GetPrikeyByCert(KMF_HANDLE_T handle,
+ KMF_CRYPTOWITHCERT_PARAMS *params,
+ KMF_DATA *SignerCertData, KMF_KEY_HANDLE *key,
+ KMF_KEY_ALG keytype)
+{
+ KMF_X509_SPKI *pubkey;
+ KMF_X509_CERTIFICATE *SignerCert = NULL;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ KMF_RETURN rv = KMF_OK;
+ CK_RV ckrv = CKR_OK;
+ CK_ATTRIBUTE templ[4];
+ CK_OBJECT_HANDLE pri_obj = CK_INVALID_HANDLE;
+ CK_ULONG obj_count;
+ CK_OBJECT_CLASS certClass = CKO_PRIVATE_KEY;
+ CK_BBOOL true = TRUE;
+ KMF_DATA Id = { NULL, 0 };
+
+ /* Decode the signer cert so we can get the SPKI data */
+ if ((rv = DerDecodeSignedCertificate(SignerCertData,
+ &SignerCert)) != KMF_OK)
+ return (rv);
+
+ /* Get the public key info from the signer certificate */
+ pubkey = &SignerCert->certificate.subjectPublicKeyInfo;
+
+ /* Generate an ID from the SPKI data */
+ rv = GetIDFromSPKI(pubkey, &Id);
+
+ if (rv != KMF_OK) {
+ SET_ERROR(kmfh, rv);
+ goto errout;
+ }
+
+ SETATTR(templ, 0, CKA_CLASS, &certClass, sizeof (certClass));
+ SETATTR(templ, 1, CKA_TOKEN, &true, sizeof (true));
+ SETATTR(templ, 2, CKA_PRIVATE, &true, sizeof (true));
+ SETATTR(templ, 3, CKA_ID, Id.Data, Id.Length);
+
+ rv = pk11_authenticate(handle, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ if ((ckrv = C_FindObjectsInit(kmfh->pk11handle, templ, 4)) != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ goto errout;
+ }
+
+ if ((rv = C_FindObjects(kmfh->pk11handle, &pri_obj, 1,
+ &obj_count)) != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ goto errout;
+ }
+
+ if (obj_count == 0) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ goto errout;
+ }
+
+ key->kstype = KMF_KEYSTORE_PK11TOKEN;
+ key->keyclass = KMF_ASYM_PRI;
+ key->keyalg = keytype;
+ key->keyp = (void *)pri_obj;
+
+ (void) C_FindObjectsFinal(kmfh->pk11handle);
+
+ ckrv = getObjectLabel(handle, (CK_OBJECT_HANDLE)key->keyp,
+ &key->keylabel);
+
+ if (ckrv != CKR_OK) {
+ SET_ERROR(handle, ckrv);
+ rv = KMF_ERR_INTERNAL;
+ } else {
+ rv = KMF_OK;
+ }
+
+ if (rv == KMF_OK && params->format == KMF_FORMAT_RAWKEY) {
+ KMF_RAW_KEY_DATA *rkey = NULL;
+ rv = keyObj2RawKey(handle, key, &rkey);
+ if (rv == KMF_OK) {
+ key->keyp = rkey;
+ key->israw = TRUE;
+ }
+ }
+
+errout:
+ if (Id.Data != NULL)
+ free(Id.Data);
+
+ if (SignerCert != NULL) {
+ KMF_FreeSignedCert(SignerCert);
+ free(SignerCert);
+ }
+ return (rv);
+}
+
+KMF_RETURN
+KMFPK11_DecryptData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key,
+ KMF_OID *algOID, KMF_DATA *ciphertext,
+ KMF_DATA *output)
+{
+ CK_RV ckrv;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ CK_SESSION_HANDLE hSession = kmfh->pk11handle;
+ CK_MECHANISM mechanism;
+ PKCS_ALGORITHM_MAP *pAlgMap;
+ KMF_ALGORITHM_INDEX AlgId;
+ CK_ULONG out_len = 0, block_len = 0, total_decrypted = 0;
+ uint8_t *in_data, *out_data;
+ int i, blocks;
+ CK_ATTRIBUTE ckTemplate[1];
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (key == NULL || algOID == NULL ||
+ ciphertext == NULL || output == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ AlgId = X509_AlgorithmOidToAlgId(algOID);
+ if (AlgId == KMF_ALGID_NONE)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ /* Map the Algorithm ID to a PKCS#11 mechanism */
+ pAlgMap = PKCS_GetAlgorithmMap(KMF_ALGCLASS_SIGNATURE,
+ AlgId, PKCS_GetDefaultSignatureMode(AlgId));
+
+ if (pAlgMap == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ mechanism.mechanism = pAlgMap->pkcs_mechanism;
+ mechanism.pParameter = NULL;
+ mechanism.ulParameterLen = 0;
+
+ SETATTR(ckTemplate, 0, CKA_MODULUS, (CK_BYTE *)NULL,
+ sizeof (CK_ULONG));
+
+ /* Get the modulus length */
+ ckrv = C_GetAttributeValue(hSession,
+ (CK_OBJECT_HANDLE)key->keyp, ckTemplate, 1);
+
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ block_len = ckTemplate[0].ulValueLen;
+
+ /* Compute the number of times to do single-part decryption */
+ blocks = ciphertext->Length/block_len;
+
+ out_data = output->Data;
+ in_data = ciphertext->Data;
+ out_len = block_len - 11;
+
+ for (i = 0; i < blocks; i++) {
+ ckrv = C_DecryptInit(hSession, &mechanism,
+ (CK_OBJECT_HANDLE)key->keyp);
+
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ ckrv = C_Decrypt(hSession, in_data, block_len,
+ out_data, (CK_ULONG *)&out_len);
+
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ out_data += out_len;
+ total_decrypted += out_len;
+ in_data += block_len;
+
+ }
+
+ output->Length = total_decrypted;
+ return (KMF_OK);
+}
+
+static void
+attr2bigint(CK_ATTRIBUTE_PTR attr, KMF_BIGINT *big)
+{
+ big->val = attr->pValue;
+ big->len = attr->ulValueLen;
+}
+
+
+static KMF_RETURN
+get_raw_rsa(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, KMF_RAW_RSA_KEY *rawrsa)
+{
+ KMF_RETURN rv = KMF_OK;
+ CK_SESSION_HANDLE sess = kmfh->pk11handle;
+ CK_ATTRIBUTE rsa_pri_attrs[8] = {
+ { CKA_MODULUS, NULL, 0 },
+ { CKA_PUBLIC_EXPONENT, NULL, 0 },
+ { CKA_PRIVATE_EXPONENT, NULL, 0 }, /* optional */
+ { CKA_PRIME_1, NULL, 0 }, /* | */
+ { CKA_PRIME_2, NULL, 0 }, /* | */
+ { CKA_EXPONENT_1, NULL, 0 }, /* | */
+ { CKA_EXPONENT_2, NULL, 0 }, /* | */
+ { CKA_COEFFICIENT, NULL, 0 } /* V */
+ };
+ CK_ULONG count = sizeof (rsa_pri_attrs) / sizeof (CK_ATTRIBUTE);
+ int i;
+
+ if ((rv = C_GetAttributeValue(sess, obj,
+ rsa_pri_attrs, count)) != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ /* Allocate memory for each attribute. */
+ for (i = 0; i < count; i++) {
+ if (rsa_pri_attrs[i].ulValueLen == (CK_ULONG)-1 ||
+ rsa_pri_attrs[i].ulValueLen == 0) {
+ rsa_pri_attrs[i].ulValueLen = 0;
+ continue;
+ }
+ if ((rsa_pri_attrs[i].pValue =
+ malloc(rsa_pri_attrs[i].ulValueLen)) == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto end;
+ }
+ }
+ /* Now that we have space, really get the attributes */
+ if ((rv = C_GetAttributeValue(sess, obj,
+ rsa_pri_attrs, count)) != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ rv = KMF_ERR_INTERNAL;
+ goto end;
+ }
+ i = 0;
+ attr2bigint(&(rsa_pri_attrs[i++]), &rawrsa->mod);
+ attr2bigint(&(rsa_pri_attrs[i++]), &rawrsa->pubexp);
+
+ if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ rsa_pri_attrs[i].ulValueLen != 0)
+ attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->priexp);
+ i++;
+
+ if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ rsa_pri_attrs[i].ulValueLen != 0)
+ attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->prime1);
+ i++;
+
+ if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ rsa_pri_attrs[i].ulValueLen != 0)
+ attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->prime2);
+ i++;
+
+ if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ rsa_pri_attrs[i].ulValueLen != 0)
+ attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->exp1);
+ i++;
+
+ if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ rsa_pri_attrs[i].ulValueLen != 0)
+ attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->exp2);
+ i++;
+
+ if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 &&
+ rsa_pri_attrs[i].ulValueLen != 0)
+ attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->coef);
+ i++;
+
+end:
+ if (rv != KMF_OK) {
+ for (i = 0; i < count; i++) {
+ if (rsa_pri_attrs[i].pValue != NULL)
+ free(rsa_pri_attrs[i].pValue);
+ }
+ (void) memset(rawrsa, 0, sizeof (KMF_RAW_RSA_KEY));
+ }
+ return (rv);
+}
+
+static KMF_RETURN
+get_raw_dsa(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, KMF_RAW_DSA_KEY *rawdsa)
+{
+ KMF_RETURN rv = KMF_OK;
+ CK_SESSION_HANDLE sess = kmfh->pk11handle;
+ CK_ATTRIBUTE dsa_pri_attrs[8] = {
+ { CKA_PRIME, NULL, 0 },
+ { CKA_SUBPRIME, NULL, 0 },
+ { CKA_BASE, NULL, 0 },
+ { CKA_VALUE, NULL, 0 }
+ };
+ CK_ULONG count = sizeof (dsa_pri_attrs) / sizeof (CK_ATTRIBUTE);
+ int i;
+
+ if ((rv = C_GetAttributeValue(sess, obj,
+ dsa_pri_attrs, count)) != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ /* Allocate memory for each attribute. */
+ for (i = 0; i < count; i++) {
+ if (dsa_pri_attrs[i].ulValueLen == (CK_ULONG)-1 ||
+ dsa_pri_attrs[i].ulValueLen == 0) {
+ dsa_pri_attrs[i].ulValueLen = 0;
+ continue;
+ }
+ if ((dsa_pri_attrs[i].pValue =
+ malloc(dsa_pri_attrs[i].ulValueLen)) == NULL) {
+ rv = KMF_ERR_MEMORY;
+ goto end;
+ }
+ }
+ if ((rv = C_GetAttributeValue(sess, obj,
+ dsa_pri_attrs, count)) != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ rv = KMF_ERR_INTERNAL;
+ goto end;
+ }
+
+ /* Fill in all the temp variables. They are all required. */
+ i = 0;
+ attr2bigint(&(dsa_pri_attrs[i++]), &rawdsa->prime);
+ attr2bigint(&(dsa_pri_attrs[i++]), &rawdsa->subprime);
+ attr2bigint(&(dsa_pri_attrs[i++]), &rawdsa->base);
+ attr2bigint(&(dsa_pri_attrs[i++]), &rawdsa->value);
+
+end:
+ if (rv != KMF_OK) {
+ for (i = 0; i < count; i++) {
+ if (dsa_pri_attrs[i].pValue != NULL)
+ free(dsa_pri_attrs[i].pValue);
+ }
+ (void) memset(rawdsa, 0, sizeof (KMF_RAW_DSA_KEY));
+ }
+ return (rv);
+}
+
+static KMF_RETURN
+get_raw_sym(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, KMF_RAW_SYM_KEY *rawsym)
+{
+ KMF_RETURN rv = KMF_OK;
+ CK_RV ckrv;
+ CK_SESSION_HANDLE sess = kmfh->pk11handle;
+ CK_ATTRIBUTE sym_attr[1];
+ CK_ULONG value_len = 0;
+
+ /* find the key length first */
+ sym_attr[0].type = CKA_VALUE;
+ sym_attr[0].pValue = NULL;
+ sym_attr[0].ulValueLen = value_len;
+ if ((ckrv = C_GetAttributeValue(sess, obj, sym_attr, 1)) != CKR_OK) {
+ /*
+ * Don't return error if the key is sensitive, just
+ * don't return any raw data. Operations like "list"
+ * need to succeed even if the raw data is not
+ * available.
+ */
+ if (ckrv == CKR_ATTRIBUTE_SENSITIVE) {
+ rawsym->keydata.val = NULL;
+ rawsym->keydata.len = 0;
+ return (CKR_OK);
+ }
+ SET_ERROR(kmfh, ckrv);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ /* Allocate memory for pValue */
+ sym_attr[0].pValue = malloc(sym_attr[0].ulValueLen);
+ if (sym_attr[0].pValue == NULL) {
+ return (KMF_ERR_MEMORY);
+ }
+
+ /* get the key data */
+ if ((rv = C_GetAttributeValue(sess, obj, sym_attr, 1)) != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ free(sym_attr[0].pValue);
+ return (KMF_ERR_INTERNAL);
+ }
+
+ rawsym->keydata.val = sym_attr[0].pValue;
+ rawsym->keydata.len = sym_attr[0].ulValueLen;
+ return (rv);
+}
+
+static KMF_RETURN
+keyObj2RawKey(KMF_HANDLE_T handle, KMF_KEY_HANDLE *inkey,
+ KMF_RAW_KEY_DATA **outkey)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_RAW_KEY_DATA *rkey;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+
+ rkey = malloc(sizeof (KMF_RAW_KEY_DATA));
+ if (rkey == NULL)
+ return (KMF_ERR_MEMORY);
+
+ (void) memset(rkey, 0, sizeof (KMF_RAW_KEY_DATA));
+
+ rkey->keytype = inkey->keyalg;
+
+ if (inkey->keyalg == KMF_RSA) {
+ rv = get_raw_rsa(kmfh, (CK_OBJECT_HANDLE)inkey->keyp,
+ &rkey->rawdata.rsa);
+ } else if (inkey->keyalg == KMF_DSA) {
+ rv = get_raw_dsa(kmfh, (CK_OBJECT_HANDLE)inkey->keyp,
+ &rkey->rawdata.dsa);
+ } else if (inkey->keyalg == KMF_AES ||
+ inkey->keyalg == KMF_RC4 ||
+ inkey->keyalg == KMF_DES ||
+ inkey->keyalg == KMF_DES3) {
+ rv = get_raw_sym(kmfh, (CK_OBJECT_HANDLE)inkey->keyp,
+ &rkey->rawdata.sym);
+ } else {
+ rv = KMF_ERR_BAD_PARAMETER;
+ }
+
+ if (rv == KMF_OK) {
+ *outkey = rkey;
+ } else if (rkey != NULL) {
+ free(rkey);
+ *outkey = NULL;
+ }
+
+ return (rv);
+}
+
+
+static KMF_RETURN
+kmf2pk11keytype(KMF_KEY_ALG keyalg, CK_KEY_TYPE *type)
+{
+ switch (keyalg) {
+ case KMF_RSA:
+ *type = CKK_RSA;
+ break;
+ case KMF_DSA:
+ *type = CKK_DSA;
+ break;
+ case KMF_AES:
+ *type = CKK_AES;
+ break;
+ case KMF_RC4:
+ *type = CKK_RC4;
+ break;
+ case KMF_DES:
+ *type = CKK_DES;
+ break;
+ case KMF_DES3:
+ *type = CKK_DES3;
+ break;
+ default:
+ return (KMF_ERR_BAD_KEY_TYPE);
+ }
+
+ return (KMF_OK);
+}
+
+static int
+IDStringToData(char *idstr, KMF_DATA *iddata)
+{
+ int len, i;
+ char *iddup, *byte;
+ uint_t lvalue;
+
+ if (idstr == NULL || !strlen(idstr))
+ return (-1);
+
+ iddup = (char *)strdup(idstr);
+ if (iddup == NULL)
+ return (KMF_ERR_MEMORY);
+
+ len = strlen(iddup) / 3 + 1;
+ iddata->Data = malloc(len);
+ if (iddata->Data == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memset(iddata->Data, 0, len);
+ iddata->Length = len;
+
+ byte = strtok(iddup, ":");
+ if (byte == NULL) {
+ free(iddup);
+ free(iddata->Data);
+ iddata->Data = NULL;
+ iddata->Length = 0;
+ return (-1);
+ }
+
+ i = 0;
+ do {
+ (void) sscanf(byte, "%x", &lvalue);
+ iddata->Data[i++] = (uchar_t)(lvalue & 0x000000FF);
+ byte = strtok(NULL, ":");
+ } while (byte != NULL && i < len);
+
+ iddata->Length = i;
+ free(iddup);
+ return (0);
+}
+
+KMF_RETURN
+KMFPK11_FindKey(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS *parms,
+ KMF_KEY_HANDLE *keys, uint32_t *numkeys)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ uint32_t want_keys, i;
+ CK_RV ckrv;
+ CK_ATTRIBUTE pTmpl[10];
+ CK_OBJECT_CLASS class;
+ CK_BBOOL true = TRUE;
+ CK_BBOOL false = FALSE;
+ CK_ULONG alg;
+ CK_BBOOL is_token;
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (parms == NULL || numkeys == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (numkeys != NULL && *numkeys > 0)
+ want_keys = *numkeys;
+ else
+ want_keys = MAXINT; /* count them all */
+
+ if (parms->keyclass == KMF_ASYM_PUB) {
+ class = CKO_PUBLIC_KEY;
+ is_token = false;
+ } else if (parms->keyclass == KMF_ASYM_PRI) {
+ class = CKO_PRIVATE_KEY;
+ is_token = true;
+ } else if (parms->keyclass == KMF_SYMMETRIC) {
+ class = CKO_SECRET_KEY;
+ is_token = true;
+ } else {
+ return (KMF_ERR_BAD_KEY_CLASS);
+ }
+
+ i = 0;
+ pTmpl[i].type = CKA_TOKEN;
+ pTmpl[i].pValue = &is_token;
+ pTmpl[i].ulValueLen = sizeof (CK_BBOOL);
+ i++;
+
+ pTmpl[i].type = CKA_CLASS;
+ pTmpl[i].pValue = &class;
+ pTmpl[i].ulValueLen = sizeof (class);
+ i++;
+
+ if (parms->findLabel != NULL && strlen(parms->findLabel)) {
+ pTmpl[i].type = CKA_LABEL;
+ pTmpl[i].pValue = parms->findLabel;
+ pTmpl[i].ulValueLen = strlen(parms->findLabel);
+ i++;
+ }
+
+ if (parms->keytype != 0) {
+ rv = kmf2pk11keytype(parms->keytype, &alg);
+ if (rv != KMF_OK) {
+ return (KMF_ERR_BAD_KEY_TYPE);
+ }
+ pTmpl[i].type = CKA_KEY_TYPE;
+ pTmpl[i].pValue = &alg;
+ pTmpl[i].ulValueLen = sizeof (alg);
+ i++;
+ }
+
+ if (parms->idstr != NULL) {
+ KMF_DATA iddata = { NULL, 0 };
+
+ /*
+ * ID String parameter is assumed to be of form:
+ * XX:XX:XX:XX:XX ... :XX
+ * where XX is a hex number.
+ *
+ * We must convert this back to binary in order to
+ * use it in a search.
+ */
+ rv = IDStringToData(parms->idstr, &iddata);
+ if (rv == KMF_OK) {
+ pTmpl[i].type = CKA_ID;
+ pTmpl[i].pValue = iddata.Data;
+ pTmpl[i].ulValueLen = iddata.Length;
+ i++;
+ } else {
+ return (rv);
+ }
+ }
+
+ if (parms->pkcs11parms.private) {
+ pTmpl[i].type = CKA_PRIVATE;
+ pTmpl[i].pValue = &true;
+ pTmpl[i].ulValueLen = sizeof (true);
+ i++;
+ }
+
+ if (is_token) {
+ rv = pk11_authenticate(handle, &parms->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+ }
+
+ ckrv = C_FindObjectsInit(kmfh->pk11handle, pTmpl, i);
+ if (ckrv == CKR_OK) {
+ CK_ULONG obj_count, n = 0;
+ while (ckrv == CKR_OK && n < want_keys) {
+ CK_OBJECT_HANDLE hObj;
+
+ ckrv = C_FindObjects(kmfh->pk11handle, &hObj,
+ 1, &obj_count);
+ if (ckrv == CKR_OK && obj_count == 1) {
+ if (keys != NULL) {
+ CK_ULONG keytype;
+ keys[n].kstype = KMF_KEYSTORE_PK11TOKEN;
+ keys[n].keyclass = parms->keyclass;
+ keys[n].israw = FALSE;
+ keys[n].keyp = (void *)hObj;
+
+ ckrv = getObjectKeytype(handle,
+ (CK_OBJECT_HANDLE)keys[n].keyp,
+ &keytype);
+ if (ckrv != CKR_OK)
+ goto end;
+
+ ckrv = getObjectLabel(handle,
+ (CK_OBJECT_HANDLE)keys[n].keyp,
+ &(keys[n].keylabel));
+ if (ckrv != CKR_OK)
+ goto end;
+
+ if (keytype == CKK_RSA)
+ keys[n].keyalg = KMF_RSA;
+ else if (keytype == CKK_DSA)
+ keys[n].keyalg = KMF_DSA;
+ else if (keytype == CKK_AES)
+ keys[n].keyalg = KMF_AES;
+ else if (keytype == CKK_RC4)
+ keys[n].keyalg = KMF_RC4;
+ else if (keytype == CKK_DES)
+ keys[n].keyalg = KMF_DES;
+ else if (keytype == CKK_DES3)
+ keys[n].keyalg = KMF_DES3;
+
+ }
+ n++;
+ } else {
+ break;
+ }
+ }
+ ckrv = C_FindObjectsFinal(kmfh->pk11handle);
+
+ /* "numkeys" indicates the number that were actually found */
+ *numkeys = n;
+ }
+ if (ckrv == KMF_OK && keys != NULL && (*numkeys) > 0 &&
+ parms->format == KMF_FORMAT_RAWKEY) {
+ /* Convert keys to "rawkey" format */
+ for (i = 0; i < (*numkeys); i++) {
+ KMF_RAW_KEY_DATA *rkey = NULL;
+ rv = keyObj2RawKey(handle, &keys[i], &rkey);
+ if (rv == KMF_OK) {
+ keys[i].keyp = rkey;
+ keys[i].israw = TRUE;
+ } else {
+ break;
+ }
+ }
+ }
+end:
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ /* Report authentication failures to the caller */
+ if (ckrv == CKR_USER_NOT_LOGGED_IN ||
+ ckrv == CKR_PIN_INCORRECT ||
+ ckrv == CKR_PIN_INVALID ||
+ ckrv == CKR_PIN_EXPIRED ||
+ ckrv == CKR_PIN_LOCKED ||
+ ckrv == CKR_SESSION_READ_ONLY)
+ rv = KMF_ERR_AUTH_FAILED;
+ else
+ rv = KMF_ERR_INTERNAL;
+ } else if ((*numkeys) == 0) {
+ rv = KMF_ERR_KEY_NOT_FOUND;
+ }
+
+ return (rv);
+}
+
+static char *
+convertDate(char *fulldate)
+{
+ struct tm tms;
+ char newtime[9];
+
+ (void) strptime(fulldate, "%b %d %T %Y %Z", &tms);
+
+ if (tms.tm_year < 69)
+ tms.tm_year += 100;
+
+ (void) strftime(newtime, sizeof (newtime), "m%d", &tms);
+
+ newtime[8] = 0;
+
+ /* memory returned must be freed by the caller */
+ return ((char *)strdup(newtime));
+}
+
+KMF_RETURN
+KMFPK11_StorePrivateKey(KMF_HANDLE_T handle, KMF_STOREKEY_PARAMS *params,
+ KMF_RAW_KEY_DATA *rawkey)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ int i;
+ CK_RV ckrv = CKR_OK;
+ CK_ATTRIBUTE templ[32];
+ CK_OBJECT_HANDLE keyobj;
+ CK_KEY_TYPE keytype;
+ CK_OBJECT_CLASS oClass = CKO_PRIVATE_KEY;
+ CK_BBOOL cktrue = TRUE;
+ CK_DATE startdate, enddate;
+ KMF_DATA id = {NULL, 0};
+ KMF_DATA subject = {NULL, 0};
+ KMF_X509EXT_KEY_USAGE kuext;
+ KMF_X509_CERTIFICATE *x509 = NULL;
+ CK_BBOOL kufound;
+ char *notbefore = NULL, *start = NULL;
+ char *notafter = NULL, *end = NULL;
+
+ if (!kmfh)
+ return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (params == NULL || params->certificate == NULL ||
+ rawkey == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ if (rawkey->keytype == KMF_RSA)
+ keytype = CKK_RSA;
+ else if (rawkey->keytype == KMF_DSA)
+ keytype = CKK_DSA;
+ else
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = pk11_authenticate(handle, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ id.Data = NULL;
+ id.Length = 0;
+ rv = KMF_GetCertIDData(params->certificate, &id);
+ if (rv != KMF_OK) {
+ goto cleanup;
+ }
+
+ rv = DerDecodeSignedCertificate(
+ (const KMF_DATA *)params->certificate, &x509);
+ if (rv != KMF_OK) {
+ goto cleanup;
+ }
+
+ rv = DerEncodeName(&x509->certificate.subject, &subject);
+ if (rv != KMF_OK) {
+ goto cleanup;
+ }
+
+ rv = KMF_GetCertStartDateString(handle, params->certificate,
+ &notbefore);
+ if (rv != KMF_OK) {
+ goto cleanup;
+ }
+ start = convertDate(notbefore);
+
+ rv = KMF_GetCertEndDateString(handle, params->certificate,
+ &notafter);
+ if (rv != KMF_OK) {
+ goto cleanup;
+ }
+ end = convertDate(notafter);
+
+ if ((rv = KMF_GetCertKeyUsageExt(params->certificate, &kuext))
+ != KMF_OK && rv != KMF_ERR_EXTENSION_NOT_FOUND)
+ goto cleanup;
+
+ kufound = (rv == KMF_OK);
+ rv = KMF_OK; /* reset if we got KMF_ERR_EXTENSION_NOT_FOUND above */
+
+ i = 0;
+ SETATTR(templ, i, CKA_CLASS, &oClass, sizeof (CK_OBJECT_CLASS)); i++;
+ SETATTR(templ, i, CKA_KEY_TYPE, &keytype, sizeof (keytype)); i++;
+ SETATTR(templ, i, CKA_TOKEN, &cktrue, sizeof (cktrue)); i++;
+ SETATTR(templ, i, CKA_PRIVATE, &cktrue, sizeof (cktrue)); i++;
+ SETATTR(templ, i, CKA_SUBJECT, subject.Data, subject.Length); i++;
+
+ /*
+ * Only set the KeyUsage stuff if the KU extension was present.
+ */
+ if (kufound) {
+ CK_BBOOL condition;
+
+ condition = (kuext.KeyUsageBits & KMF_keyEncipherment) ?
+ B_TRUE : B_FALSE;
+ SETATTR(templ, i, CKA_UNWRAP, &condition,
+ sizeof (CK_BBOOL)); i++;
+ condition = (kuext.KeyUsageBits & KMF_dataEncipherment) ?
+ B_TRUE : B_FALSE;
+ SETATTR(templ, i, CKA_DECRYPT, &condition,
+ sizeof (CK_BBOOL)); i++;
+ condition = (kuext.KeyUsageBits & KMF_digitalSignature) ?
+ B_TRUE : B_FALSE;
+ SETATTR(templ, i, CKA_SIGN, &condition,
+ sizeof (CK_BBOOL)); i++;
+ condition = (kuext.KeyUsageBits & KMF_digitalSignature) ?
+ B_TRUE : B_FALSE;
+ SETATTR(templ, i, CKA_SIGN_RECOVER, &condition,
+ sizeof (CK_BBOOL)); i++;
+ }
+ if (params->label != NULL) {
+ SETATTR(templ, i, CKA_LABEL, params->label,
+ strlen(params->label));
+ i++;
+ }
+ if (id.Data != NULL &&
+ id.Data != NULL && id.Length > 0) {
+ SETATTR(templ, i, CKA_ID, id.Data, id.Length);
+ i++;
+ }
+ if (start != NULL) {
+ /*
+ * This make some potentially dangerous assumptions:
+ * 1. that the startdate in the parameter block is
+ * properly formatted as YYYYMMDD
+ * 2. That the CK_DATE structure is always the same.
+ */
+ (void) memcpy(&startdate, start, sizeof (CK_DATE));
+ SETATTR(templ, i, CKA_START_DATE, &startdate,
+ sizeof (startdate));
+ i++;
+ }
+ if (end != NULL) {
+ (void) memcpy(&enddate, end, sizeof (CK_DATE));
+ SETATTR(templ, i, CKA_END_DATE, &enddate, sizeof (enddate));
+ i++;
+ }
+ if (keytype == CKK_RSA) {
+ SETATTR(templ, i, CKA_MODULUS,
+ rawkey->rawdata.rsa.mod.val,
+ rawkey->rawdata.rsa.mod.len);
+ i++;
+ SETATTR(templ, i, CKA_PUBLIC_EXPONENT,
+ rawkey->rawdata.rsa.pubexp.val,
+ rawkey->rawdata.rsa.pubexp.len);
+ i++;
+ if (rawkey->rawdata.rsa.priexp.val != NULL) {
+ SETATTR(templ, i, CKA_PRIVATE_EXPONENT,
+ rawkey->rawdata.rsa.priexp.val,
+ rawkey->rawdata.rsa.priexp.len);
+ i++;
+ }
+ if (rawkey->rawdata.rsa.prime1.val != NULL) {
+ SETATTR(templ, i, CKA_PRIME_1,
+ rawkey->rawdata.rsa.prime1.val,
+ rawkey->rawdata.rsa.prime1.len);
+ i++;
+ }
+ if (rawkey->rawdata.rsa.prime2.val != NULL) {
+ SETATTR(templ, i, CKA_PRIME_2,
+ rawkey->rawdata.rsa.prime2.val,
+ rawkey->rawdata.rsa.prime2.len);
+ i++;
+ }
+ if (rawkey->rawdata.rsa.exp1.val != NULL) {
+ SETATTR(templ, i, CKA_EXPONENT_1,
+ rawkey->rawdata.rsa.exp1.val,
+ rawkey->rawdata.rsa.exp1.len);
+ i++;
+ }
+ if (rawkey->rawdata.rsa.exp2.val != NULL) {
+ SETATTR(templ, i, CKA_EXPONENT_2,
+ rawkey->rawdata.rsa.exp2.val,
+ rawkey->rawdata.rsa.exp2.len);
+ i++;
+ }
+ if (rawkey->rawdata.rsa.coef.val != NULL) {
+ SETATTR(templ, i, CKA_COEFFICIENT,
+ rawkey->rawdata.rsa.coef.val,
+ rawkey->rawdata.rsa.coef.len);
+ i++;
+ }
+ } else {
+ SETATTR(templ, i, CKA_PRIME,
+ rawkey->rawdata.dsa.prime.val,
+ rawkey->rawdata.dsa.prime.len);
+ i++;
+ SETATTR(templ, i, CKA_SUBPRIME,
+ rawkey->rawdata.dsa.subprime.val,
+ rawkey->rawdata.dsa.subprime.len);
+ i++;
+ SETATTR(templ, i, CKA_BASE,
+ rawkey->rawdata.dsa.base.val,
+ rawkey->rawdata.dsa.base.len);
+ i++;
+ SETATTR(templ, i, CKA_VALUE,
+ rawkey->rawdata.dsa.value.val,
+ rawkey->rawdata.dsa.value.len);
+ i++;
+ }
+
+ ckrv = C_CreateObject(kmfh->pk11handle, templ, i, &keyobj);
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+
+ /* Report authentication failures to the caller */
+ if (ckrv == CKR_USER_NOT_LOGGED_IN ||
+ ckrv == CKR_PIN_INCORRECT ||
+ ckrv == CKR_PIN_INVALID ||
+ ckrv == CKR_PIN_EXPIRED ||
+ ckrv == CKR_PIN_LOCKED ||
+ ckrv == CKR_SESSION_READ_ONLY)
+ rv = KMF_ERR_AUTH_FAILED;
+ else
+ rv = KMF_ERR_INTERNAL;
+ }
+cleanup:
+ KMF_FreeData(&id);
+ KMF_FreeData(&subject);
+ KMF_FreeSignedCert(x509);
+ free(x509);
+
+ return (rv);
+}
+
+KMF_RETURN
+KMFPK11_CreateSymKey(KMF_HANDLE_T handle, KMF_CREATESYMKEY_PARAMS *params,
+ KMF_KEY_HANDLE *symkey)
+{
+ KMF_RETURN rv = KMF_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ CK_RV ckrv;
+ CK_SESSION_HANDLE hSession = kmfh->pk11handle;
+ CK_OBJECT_HANDLE keyhandle;
+ CK_MECHANISM keyGenMech;
+ CK_OBJECT_CLASS class = CKO_SECRET_KEY;
+ CK_ULONG secKeyType;
+ CK_ULONG secKeyLen; /* for RC4 and AES */
+ CK_BBOOL true = TRUE;
+ CK_BBOOL false = FALSE;
+ CK_ATTRIBUTE templ[15];
+ int i;
+
+ if (kmfh == NULL)
+ return (KMF_ERR_UNINITIALIZED);
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ if (params == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ keyGenMech.pParameter = NULL_PTR;
+ keyGenMech.ulParameterLen = 0;
+ switch (params->keytype) {
+ case KMF_AES:
+ keyGenMech.mechanism = CKM_AES_KEY_GEN;
+ secKeyType = CKK_AES;
+ break;
+ case KMF_RC4:
+ keyGenMech.mechanism = CKM_RC4_KEY_GEN;
+ secKeyType = CKK_RC4;
+ break;
+ case KMF_DES:
+ keyGenMech.mechanism = CKM_DES_KEY_GEN;
+ secKeyType = CKK_DES;
+ break;
+ case KMF_DES3:
+ keyGenMech.mechanism = CKM_DES3_KEY_GEN;
+ secKeyType = CKK_DES3;
+ break;
+ default:
+ return (KMF_ERR_BAD_KEY_TYPE);
+ }
+
+ i = 0;
+ SETATTR(templ, i, CKA_CLASS, &class, sizeof (class));
+ i++;
+ SETATTR(templ, i, CKA_KEY_TYPE, &secKeyType, sizeof (secKeyType));
+ i++;
+
+ if (params->keytype == KMF_AES || params->keytype == KMF_RC4) {
+ if ((params->keylength % 8) != 0) {
+ return (KMF_ERR_BAD_KEY_SIZE);
+ }
+ secKeyLen = params->keylength/8; /* in bytes for RC4/AES */
+ SETATTR(templ, i, CKA_VALUE_LEN, &secKeyLen,
+ sizeof (secKeyLen));
+ i++;
+ }
+
+ if (params->keylabel != NULL) {
+ SETATTR(templ, i, CKA_LABEL, params->keylabel,
+ strlen(params->keylabel));
+ i++;
+ }
+
+ if (params->pkcs11parms.sensitive == B_TRUE) {
+ SETATTR(templ, i, CKA_SENSITIVE, &true, sizeof (true));
+ } else {
+ SETATTR(templ, i, CKA_SENSITIVE, &false, sizeof (false));
+ }
+ i++;
+
+ if (params->pkcs11parms.not_extractable == B_TRUE) {
+ SETATTR(templ, i, CKA_EXTRACTABLE, &false, sizeof (false));
+ } else {
+ SETATTR(templ, i, CKA_EXTRACTABLE, &true, sizeof (true));
+ }
+ i++;
+
+ SETATTR(templ, i, CKA_TOKEN, &true, sizeof (true));
+ i++;
+ SETATTR(templ, i, CKA_PRIVATE, &true, sizeof (true));
+ i++;
+ SETATTR(templ, i, CKA_ENCRYPT, &true, sizeof (true));
+ i++;
+ SETATTR(templ, i, CKA_DECRYPT, &true, sizeof (true));
+ i++;
+ SETATTR(templ, i, CKA_SIGN, &true, sizeof (true));
+ i++;
+ SETATTR(templ, i, CKA_VERIFY, &true, sizeof (true));
+ i++;
+
+ rv = pk11_authenticate(handle, &params->cred);
+ if (rv != KMF_OK) {
+ return (rv);
+ }
+
+ ckrv = C_GenerateKey(hSession, &keyGenMech, templ, i, &keyhandle);
+ if (ckrv != CKR_OK) {
+ SET_ERROR(kmfh, ckrv);
+ rv = KMF_ERR_KEYGEN_FAILED;
+ goto out;
+ }
+
+ symkey->kstype = KMF_KEYSTORE_PK11TOKEN;
+ symkey->keyalg = params->keytype;
+ symkey->keyclass = KMF_SYMMETRIC;
+ symkey->israw = FALSE;
+ symkey->keyp = (void *)keyhandle;
+
+out:
+ return (rv);
+}
+
+
+KMF_RETURN
+KMFPK11_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;
+
+ if (kmfh == NULL)
+ return (KMF_ERR_UNINITIALIZED);
+
+ if (kmfh->pk11handle == CK_INVALID_HANDLE)
+ return (KMF_ERR_NO_TOKEN_SELECTED);
+
+ 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_KEY_DATA *rawkey = (KMF_RAW_KEY_DATA *)symkey->keyp;
+
+ if (rawkey == NULL ||
+ rawkey->rawdata.sym.keydata.val == NULL ||
+ rawkey->rawdata.sym.keydata.len == 0)
+ return (KMF_ERR_BAD_KEYHANDLE);
+
+ rkey->keydata.len = rawkey->rawdata.sym.keydata.len;
+ if ((rkey->keydata.val = malloc(rkey->keydata.len)) == NULL)
+ return (KMF_ERR_MEMORY);
+ (void) memcpy(rkey->keydata.val,
+ rawkey->rawdata.sym.keydata.val, rkey->keydata.len);
+ } else {
+ rv = get_raw_sym(kmfh, (CK_OBJECT_HANDLE)symkey->keyp, rkey);
+ }
+
+ return (rv);
+}
+
+KMF_RETURN
+KMFPK11_SetTokenPin(KMF_HANDLE_T handle, KMF_SETPIN_PARAMS *params,
+ KMF_CREDENTIAL *newpin)
+{
+ KMF_RETURN ret = KMF_OK;
+ CK_RV rv = CKR_OK;
+ KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+ CK_SESSION_HANDLE session = NULL;
+
+ if (handle == NULL || params == NULL || newpin == NULL)
+ return (KMF_ERR_BAD_PARAMETER);
+
+ rv = C_OpenSession(params->pkcs11parms.slot,
+ CKF_SERIAL_SESSION | CKF_RW_SESSION,
+ NULL, NULL, &session);
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ ret = KMF_ERR_UNINITIALIZED;
+ goto end;
+ }
+
+ rv = C_SetPIN(session,
+ (CK_BYTE *)params->cred.cred, params->cred.credlen,
+ (CK_BYTE *)newpin->cred, newpin->credlen);
+
+ if (rv != CKR_OK) {
+ SET_ERROR(kmfh, rv);
+ if (rv == CKR_PIN_INCORRECT ||
+ rv == CKR_PIN_INVALID ||
+ rv == CKR_PIN_EXPIRED ||
+ rv == CKR_PIN_LOCKED)
+ ret = KMF_ERR_AUTH_FAILED;
+ else
+ ret = KMF_ERR_INTERNAL;
+ }
+end:
+ if (session != NULL)
+ (void) C_CloseSession(session);
+ return (ret);
+}
diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/i386/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/i386/Makefile
new file mode 100644
index 0000000000..443f78537a
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/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_pkcs11/sparc/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparc/Makefile
new file mode 100644
index 0000000000..472ac90a9a
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/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_pkcs11/sparcv9/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparcv9/Makefile
new file mode 100644
index 0000000000..0dd91e1065
--- /dev/null
+++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparcv9/Makefile
@@ -0,0 +1,30 @@
+#
+# 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
+
+install: $(ROOTLIBS64)