--- /dev/null	Fri May 30 18:31:12 2014
+++ new/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c	Fri May 30 18:31:12 2014
@@ -0,0 +1,5583 @@
+/*
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2012, OmniTI Computer Consulting, Inc. All rights reserved.
+ */
+/*
+ * Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
+ * project 2000.
+ */
+/*
+ * ====================================================================
+ * Copyright (c) 2000-2004 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdlib.h>
+#include <kmfapiP.h>
+#include <ber_der.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 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;
+
+/*
+ * Declare some new macros for managing stacks of EVP_PKEYS, similar to
+ * what wanboot did.
+ */
+DECLARE_STACK_OF(EVP_PKEY)
+
+#define	sk_EVP_PKEY_new_null() SKM_sk_new_null(EVP_PKEY)
+#define	sk_EVP_PKEY_free(st) SKM_sk_free(EVP_PKEY, (st))
+#define	sk_EVP_PKEY_num(st) SKM_sk_num(EVP_PKEY, (st))
+#define	sk_EVP_PKEY_value(st, i) SKM_sk_value(EVP_PKEY, (st), (i))
+#define	sk_EVP_PKEY_push(st, val) SKM_sk_push(EVP_PKEY, (st), (val))
+#define	sk_EVP_PKEY_pop_free(st, free_func) SKM_sk_pop_free(EVP_PKEY, (st), \
+	(free_func))
+
+mutex_t init_lock = DEFAULTMUTEX;
+static int ssl_initialized = 0;
+static BIO *bio_err = NULL;
+
+static int
+test_for_file(char *, mode_t);
+static KMF_RETURN
+openssl_parse_bag(PKCS12_SAFEBAG *, char *, int,
+    STACK_OF(EVP_PKEY) *, STACK_OF(X509) *);
+
+static KMF_RETURN
+local_export_pk12(KMF_HANDLE_T, KMF_CREDENTIAL *, int, KMF_X509_DER_CERT *,
+    int, KMF_KEY_HANDLE *, char *);
+
+static KMF_RETURN set_pkey_attrib(EVP_PKEY *, ASN1_TYPE *, int);
+
+static KMF_RETURN
+extract_pem(KMF_HANDLE *, char *, char *, KMF_BIGINT *, char *,
+    CK_UTF8CHAR *, CK_ULONG, EVP_PKEY **, KMF_DATA **, int *);
+
+static KMF_RETURN
+kmf_load_cert(KMF_HANDLE *, char *, char *, KMF_BIGINT *, KMF_CERT_VALIDITY,
+    char *, KMF_DATA *);
+
+static KMF_RETURN
+load_certs(KMF_HANDLE *, char *, char *, KMF_BIGINT *, KMF_CERT_VALIDITY,
+    char *, KMF_DATA **, uint32_t *);
+
+static KMF_RETURN
+sslBN2KMFBN(BIGNUM *, KMF_BIGINT *);
+
+static EVP_PKEY *
+ImportRawRSAKey(KMF_RAW_RSA_KEY *);
+
+static KMF_RETURN
+convertToRawKey(EVP_PKEY *, KMF_RAW_KEY_DATA *);
+
+KMF_RETURN
+OpenSSL_FindCert(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
+
+void
+OpenSSL_FreeKMFCert(KMF_HANDLE_T, KMF_X509_DER_CERT *);
+
+KMF_RETURN
+OpenSSL_StoreCert(KMF_HANDLE_T handle, int, KMF_ATTRIBUTE *);
+
+KMF_RETURN
+OpenSSL_DeleteCert(KMF_HANDLE_T handle, int, KMF_ATTRIBUTE *);
+
+KMF_RETURN
+OpenSSL_CreateKeypair(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
+
+KMF_RETURN
+OpenSSL_StoreKey(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
+
+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, int, KMF_ATTRIBUTE *);
+
+KMF_RETURN
+OpenSSL_ImportCRL(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
+
+KMF_RETURN
+OpenSSL_DeleteCRL(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
+
+KMF_RETURN
+OpenSSL_ListCRL(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
+
+KMF_RETURN
+OpenSSL_FindCertInCRL(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
+
+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_FindPrikeyByCert(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
+
+KMF_RETURN
+OpenSSL_DecryptData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *,
+	KMF_DATA *, KMF_DATA *);
+
+KMF_RETURN
+OpenSSL_CreateOCSPRequest(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
+
+KMF_RETURN
+OpenSSL_GetOCSPStatusForCert(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
+
+KMF_RETURN
+OpenSSL_FindKey(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
+
+KMF_RETURN
+OpenSSL_ExportPK12(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
+
+KMF_RETURN
+OpenSSL_CreateSymKey(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
+
+KMF_RETURN
+OpenSSL_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_SYM_KEY *);
+
+KMF_RETURN
+OpenSSL_VerifyCRLFile(KMF_HANDLE_T, char *, KMF_DATA *);
+
+KMF_RETURN
+OpenSSL_CheckCRLDate(KMF_HANDLE_T, char *);
+
+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_FindPrikeyByCert,
+	OpenSSL_DecryptData,
+	OpenSSL_ExportPK12,
+	OpenSSL_CreateSymKey,
+	OpenSSL_GetSymKeyValue,
+	NULL,	/* SetTokenPin */
+	OpenSSL_StoreKey,
+	NULL	/* Finalize */
+};
+
+static mutex_t *lock_cs;
+static long *lock_count;
+
+static void
+/* ARGSUSED1 */
+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) {
+		/*
+		 * 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);
+		if (CRYPTO_get_locking_callback() == NULL)
+			CRYPTO_set_locking_callback((void (*)())locking_cb);
+
+		OpenSSL_add_all_algorithms();
+
+		/* Enable error strings for reporting */
+		ERR_load_crypto_strings();
+
+		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);
+}
+
+int
+isdir(char *path)
+{
+	struct stat s;
+
+	if (stat(path, &s) == -1)
+		return (0);
+
+	return ((s.st_mode & S_IFMT) == 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, char *issuer, char *subject, KMF_BIGINT *serial,
+    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 (issuer != NULL && strlen(issuer)) {
+		rv = kmf_dn_parser(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_free_dn(&issuerDN);
+			return (KMF_ERR_BAD_PARAMETER);
+		}
+
+		findIssuer = TRUE;
+	}
+	if (subject != NULL && strlen(subject)) {
+		rv = kmf_dn_parser(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 (serial != NULL && 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 == 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, serial->val, serial->len) ==
+				    0);
+				rv = KMF_OK;
+				free(a);
+			}
+			BN_free(bn);
+			if (!(*match))
+				goto cleanup;
+		} else {
+			rv = KMF_OK;
+			goto cleanup;
+		}
+	}
+	if (findIssuer) {
+		*match = (kmf_compare_rdns(&issuerDN, &certIssuerDN) == 0);
+		if ((*match) == B_FALSE) {
+			/* stop checking and bail */
+			rv = KMF_OK;
+			goto cleanup;
+		}
+	}
+	if (findSubject) {
+		*match = (kmf_compare_rdns(&subjectDN, &certSubjectDN) == 0);
+		if ((*match) == B_FALSE) {
+			/* stop checking and bail */
+			rv = KMF_OK;
+			goto cleanup;
+		}
+	}
+
+	*match = TRUE;
+cleanup:
+	if (findIssuer) {
+		kmf_free_dn(&issuerDN);
+		kmf_free_dn(&certIssuerDN);
+	}
+	if (findSubject) {
+		kmf_free_dn(&subjectDN);
+		kmf_free_dn(&certSubjectDN);
+	}
+
+	return (rv);
+}
+
+
+/*
+ * This function loads a certificate file into an X509 data structure, and
+ * checks if its issuer, subject or the serial number matches with those
+ * values.  If it matches, then return the X509 data structure.
+ */
+static KMF_RETURN
+load_X509cert(KMF_HANDLE *kmfh,
+    char *issuer, char *subject, KMF_BIGINT *serial,
+    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_get_file_format(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, issuer, subject, serial, &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 int
+datacmp(const void *a, const void *b)
+{
+	KMF_DATA *adata = (KMF_DATA *)a;
+	KMF_DATA *bdata = (KMF_DATA *)b;
+	if (adata->Length > bdata->Length)
+		return (-1);
+	if (adata->Length < bdata->Length)
+		return (1);
+	return (0);
+}
+
+static KMF_RETURN
+load_certs(KMF_HANDLE *kmfh, char *issuer, char *subject, KMF_BIGINT *serial,
+    KMF_CERT_VALIDITY validity, char *pathname,
+    KMF_DATA **certlist, uint32_t *numcerts)
+{
+	KMF_RETURN rv = KMF_OK;
+	int i;
+	KMF_DATA *certs = NULL;
+	int nc = 0;
+	int hits = 0;
+	KMF_ENCODE_FORMAT format;
+
+	rv = kmf_get_file_format(pathname, &format);
+	if (rv != KMF_OK) {
+		if (rv == KMF_ERR_OPEN_FILE)
+			rv = KMF_ERR_CERT_NOT_FOUND;
+		return (rv);
+	}
+	if (format == KMF_FORMAT_ASN1) {
+		/* load a single certificate */
+		certs = (KMF_DATA *)malloc(sizeof (KMF_DATA));
+		if (certs == NULL)
+			return (KMF_ERR_MEMORY);
+		certs->Data = NULL;
+		certs->Length = 0;
+		rv = kmf_load_cert(kmfh, issuer, subject, serial, validity,
+		    pathname, certs);
+		if (rv == KMF_OK) {
+			*certlist = certs;
+			*numcerts = 1;
+		} else {
+			kmf_free_data(certs);
+			free(certs);
+			certs = NULL;
+		}
+		return (rv);
+	} else if (format == KMF_FORMAT_PKCS12) {
+		/* We need a credential to access a PKCS#12 file */
+		rv = KMF_ERR_BAD_CERT_FORMAT;
+	} else if (format == KMF_FORMAT_PEM ||
+	    format != KMF_FORMAT_PEM_KEYPAIR) {
+
+		/* This function only works on PEM files */
+		rv = extract_pem(kmfh, issuer, subject, serial, pathname,
+		    (uchar_t *)NULL, 0, NULL, &certs, &nc);
+	} else {
+		return (KMF_ERR_ENCODING);
+	}
+
+	if (rv != KMF_OK)
+		return (rv);
+
+	for (i = 0; i < nc; i++) {
+		if (validity == KMF_NONEXPIRED_CERTS) {
+			rv = kmf_check_cert_date(kmfh, &certs[i]);
+		} else if (validity == KMF_EXPIRED_CERTS) {
+			rv = kmf_check_cert_date(kmfh, &certs[i]);
+			if (rv == KMF_OK)
+				rv = KMF_ERR_CERT_NOT_FOUND;
+			if (rv == KMF_ERR_VALIDITY_PERIOD)
+				rv = KMF_OK;
+		}
+		if (rv != KMF_OK) {
+			/* Remove this cert from the list by clearing it. */
+			kmf_free_data(&certs[i]);
+		} else {
+			hits++; /* count valid certs found */
+		}
+		rv = KMF_OK;
+	}
+	if (rv == KMF_OK && hits > 0) {
+		/*
+		 * Sort the list of certs by length to put the cleared ones
+		 * at the end so they don't get accessed by the caller.
+		 */
+		qsort((void *)certs, nc, sizeof (KMF_DATA), datacmp);
+		*certlist = certs;
+
+		/* since we sorted the list, just return the number of hits */
+		*numcerts = hits;
+	} else {
+		if (rv == KMF_OK && hits == 0)
+			rv = KMF_ERR_CERT_NOT_FOUND;
+		if (certs != NULL) {
+			free(certs);
+			certs = NULL;
+		}
+	}
+	return (rv);
+}
+
+static KMF_RETURN
+kmf_load_cert(KMF_HANDLE *kmfh,
+    char *issuer, char *subject, KMF_BIGINT *serial,
+    KMF_CERT_VALIDITY validity,
+    char *pathname,
+    KMF_DATA *cert)
+{
+	KMF_RETURN rv = KMF_OK;
+	X509 *x509cert = NULL;
+
+	rv = load_X509cert(kmfh, issuer, subject, serial, pathname, &x509cert);
+	if (rv == KMF_OK && x509cert != NULL && cert != NULL) {
+		rv = ssl_cert2KMFDATA(kmfh, x509cert, cert);
+		if (rv != KMF_OK) {
+			goto cleanup;
+		}
+		if (validity == KMF_NONEXPIRED_CERTS) {
+			rv = kmf_check_cert_date(kmfh, cert);
+		} else if (validity == KMF_EXPIRED_CERTS) {
+			rv = kmf_check_cert_date(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 KMF_RETURN
+readAltFormatPrivateKey(KMF_DATA *filedata, EVP_PKEY **pkey)
+{
+	KMF_RETURN ret = KMF_OK;
+	KMF_RAW_RSA_KEY rsa;
+	BerElement *asn1 = NULL;
+	BerValue filebuf;
+	BerValue OID = { NULL, 0 };
+	BerValue *Mod = NULL, *PubExp = NULL;
+	BerValue *PriExp = NULL, *Prime1 = NULL, *Prime2 = NULL;
+	BerValue *Coef = NULL;
+	BIGNUM *D = NULL, *P = NULL, *Q = NULL, *COEF = NULL;
+	BIGNUM *Exp1 = NULL, *Exp2 = NULL, *pminus1 = NULL;
+	BIGNUM *qminus1 = NULL;
+	BN_CTX *ctx = NULL;
+
+	*pkey = NULL;
+
+	filebuf.bv_val = (char *)filedata->Data;
+	filebuf.bv_len = filedata->Length;
+
+	asn1 = kmfder_init(&filebuf);
+	if (asn1 == NULL) {
+		ret = KMF_ERR_MEMORY;
+		goto out;
+	}
+
+	if (kmfber_scanf(asn1, "{{Dn{IIIIII}}}",
+	    &OID, &Mod, &PubExp, &PriExp, &Prime1,
+	    &Prime2, &Coef) == -1)  {
+		ret = KMF_ERR_ENCODING;
+		goto out;
+	}
+
+	/*
+	 * We have to derive the 2 Exponents using Bignumber math.
+	 * Exp1 = PriExp mod (Prime1 - 1)
+	 * Exp2 = PriExp mod (Prime2 - 1)
+	 */
+
+	/* D = PrivateExponent */
+	D = BN_bin2bn((const uchar_t *)PriExp->bv_val, PriExp->bv_len, D);
+	if (D == NULL) {
+		ret = KMF_ERR_MEMORY;
+		goto out;
+	}
+
+	/* P = Prime1 (first prime factor of Modulus) */
+	P = BN_bin2bn((const uchar_t *)Prime1->bv_val, Prime1->bv_len, P);
+	if (D == NULL) {
+		ret = KMF_ERR_MEMORY;
+		goto out;
+	}
+
+	/* Q = Prime2 (second prime factor of Modulus) */
+	Q = BN_bin2bn((const uchar_t *)Prime2->bv_val, Prime2->bv_len, Q);
+
+	if ((ctx = BN_CTX_new()) == NULL) {
+		ret = KMF_ERR_MEMORY;
+		goto out;
+	}
+
+	/* Compute (P - 1) */
+	pminus1 = BN_new();
+	(void) BN_sub(pminus1, P, BN_value_one());
+
+	/* Exponent1 = D mod (P - 1) */
+	Exp1 = BN_new();
+	(void) BN_mod(Exp1, D, pminus1, ctx);
+
+	/* Compute (Q - 1) */
+	qminus1 = BN_new();
+	(void) BN_sub(qminus1, Q, BN_value_one());
+
+	/* Exponent2 = D mod (Q - 1) */
+	Exp2 = BN_new();
+	(void) BN_mod(Exp2, D, qminus1, ctx);
+
+	/* Coef = (Inverse Q) mod P */
+	COEF = BN_new();
+	(void) BN_mod_inverse(COEF, Q, P, ctx);
+
+	/* Convert back to KMF format */
+	(void) memset(&rsa, 0, sizeof (rsa));
+
+	if ((ret = sslBN2KMFBN(Exp1, &rsa.exp1)) != KMF_OK)
+		goto out;
+	if ((ret = sslBN2KMFBN(Exp2, &rsa.exp2)) != KMF_OK)
+		goto out;
+	if ((ret = sslBN2KMFBN(COEF, &rsa.coef)) != KMF_OK)
+		goto out;
+
+	rsa.mod.val = (uchar_t *)Mod->bv_val;
+	rsa.mod.len = Mod->bv_len;
+
+	rsa.pubexp.val = (uchar_t *)PubExp->bv_val;
+	rsa.pubexp.len = PubExp->bv_len;
+
+	rsa.priexp.val = (uchar_t *)PriExp->bv_val;
+	rsa.priexp.len = PriExp->bv_len;
+
+	rsa.prime1.val = (uchar_t *)Prime1->bv_val;
+	rsa.prime1.len = Prime1->bv_len;
+
+	rsa.prime2.val = (uchar_t *)Prime2->bv_val;
+	rsa.prime2.len = Prime2->bv_len;
+
+	*pkey = ImportRawRSAKey(&rsa);
+out:
+	if (asn1 != NULL)
+		kmfber_free(asn1, 1);
+
+	if (OID.bv_val) {
+		free(OID.bv_val);
+	}
+	if (PriExp)
+		free(PriExp);
+
+	if (Mod)
+		free(Mod);
+
+	if (PubExp)
+		free(PubExp);
+
+	if (Coef) {
+		(void) memset(Coef->bv_val, 0, Coef->bv_len);
+		free(Coef->bv_val);
+		free(Coef);
+	}
+	if (Prime1)
+		free(Prime1);
+	if (Prime2)
+		free(Prime2);
+
+	if (ctx != NULL)
+		BN_CTX_free(ctx);
+
+	if (D)
+		BN_clear_free(D);
+	if (P)
+		BN_clear_free(P);
+	if (Q)
+		BN_clear_free(Q);
+	if (pminus1)
+		BN_clear_free(pminus1);
+	if (qminus1)
+		BN_clear_free(qminus1);
+	if (Exp1)
+		BN_clear_free(Exp1);
+	if (Exp2)
+		BN_clear_free(Exp2);
+
+	return (ret);
+
+}
+
+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;
+	KMF_RETURN rv;
+	KMF_DATA filedata;
+
+	if (file == NULL) {
+		return (NULL);
+	}
+
+	if (kmf_get_file_format((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);
+		if (pkey == NULL) {
+
+			(void) BIO_free(keyfile);
+			keyfile = NULL;
+			/* Try odd ASN.1 variations */
+			rv = kmf_read_input_file(kmfh, (char *)file,
+			    &filedata);
+			if (rv == KMF_OK) {
+				(void) readAltFormatPrivateKey(&filedata,
+				    &pkey);
+				kmf_free_data(&filedata);
+			}
+		}
+	} else if (format == KMF_FORMAT_PEM ||
+	    format == KMF_FORMAT_PEM_KEYPAIR) {
+		pkey = PEM_read_bio_PrivateKey(keyfile, NULL, NULL, NULL);
+		if (pkey == NULL) {
+			KMF_DATA derdata;
+			/*
+			 * Check if this is the alt. format
+			 * RSA private key file.
+			 */
+			rv = kmf_read_input_file(kmfh, (char *)file,
+			    &filedata);
+			if (rv == KMF_OK) {
+				uchar_t *d = NULL;
+				int len;
+				rv = kmf_pem_to_der(filedata.Data,
+				    filedata.Length, &d, &len);
+				if (rv == KMF_OK && d != NULL) {
+					derdata.Data = d;
+					derdata.Length = (size_t)len;
+					(void) readAltFormatPrivateKey(
+					    &derdata, &pkey);
+					free(d);
+				}
+				kmf_free_data(&filedata);
+			}
+		}
+	}
+
+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, int numattr, KMF_ATTRIBUTE *attrlist)
+{
+	KMF_RETURN rv = KMF_OK;
+	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+	int i, n;
+	uint32_t maxcerts = 0;
+	uint32_t *num_certs;
+	KMF_X509_DER_CERT *kmf_cert = NULL;
+	char *dirpath = NULL;
+	char *filename = NULL;
+	char *fullpath = NULL;
+	char *issuer = NULL;
+	char *subject = NULL;
+	KMF_BIGINT *serial = NULL;
+	KMF_CERT_VALIDITY validity;
+
+	num_certs = kmf_get_attr_ptr(KMF_COUNT_ATTR, attrlist, numattr);
+	if (num_certs == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	/* num_certs should reference the size of kmf_cert */
+	maxcerts = *num_certs;
+	if (maxcerts == 0)
+		maxcerts = 0xFFFFFFFF;
+	*num_certs = 0;
+
+	/* Get the optional returned certificate list  */
+	kmf_cert = kmf_get_attr_ptr(KMF_X509_DER_CERT_ATTR, attrlist,
+	    numattr);
+
+	/*
+	 * The dirpath attribute and the filename attribute can not be NULL
+	 * at the same time.
+	 */
+	dirpath = kmf_get_attr_ptr(KMF_DIRPATH_ATTR, attrlist, numattr);
+	filename = kmf_get_attr_ptr(KMF_CERT_FILENAME_ATTR, attrlist,
+	    numattr);
+
+	fullpath = get_fullpath(dirpath, filename);
+	if (fullpath == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	/* Get optional search criteria attributes */
+	issuer = kmf_get_attr_ptr(KMF_ISSUER_NAME_ATTR, attrlist, numattr);
+	subject = kmf_get_attr_ptr(KMF_SUBJECT_NAME_ATTR, attrlist, numattr);
+	serial = kmf_get_attr_ptr(KMF_BIGINT_ATTR, attrlist, numattr);
+	rv = kmf_get_attr(KMF_CERT_VALIDITY_ATTR, attrlist, numattr,
+	    &validity, NULL);
+	if (rv != KMF_OK) {
+		validity = KMF_ALL_CERTS;
+		rv = KMF_OK;
+	}
+
+	if (isdir(fullpath)) {
+		DIR *dirp;
+		struct dirent *dp;
+
+		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;
+			KMF_DATA *certlist = NULL;
+			uint32_t loaded_certs = 0;
+
+			if (strcmp(dp->d_name, ".") == 0 ||
+			    strcmp(dp->d_name, "..") == 0)
+				continue;
+
+			fname = get_fullpath(fullpath, (char *)&dp->d_name);
+
+			rv = load_certs(kmfh, issuer, subject, serial,
+			    validity, fname, &certlist,	&loaded_certs);
+
+			if (rv != KMF_OK) {
+				free(fname);
+				if (certlist != NULL) {
+					for (i = 0; i < loaded_certs; i++)
+						kmf_free_data(&certlist[i]);
+					free(certlist);
+				}
+				continue;
+			}
+
+			/* If load succeeds, add certdata to the list */
+			if (kmf_cert != NULL) {
+				for (i = 0; i < loaded_certs &&
+				    n < maxcerts; i++) {
+					kmf_cert[n].certificate.Data =
+					    certlist[i].Data;
+					kmf_cert[n].certificate.Length =
+					    certlist[i].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 =
+					    strdup(fname);
+					n++;
+				}
+				/*
+				 * If maxcerts < loaded_certs, clean up the
+				 * certs that were not used.
+				 */
+				for (; i < loaded_certs; i++)
+					kmf_free_data(&certlist[i]);
+			} else {
+				for (i = 0; i < loaded_certs; i++)
+					kmf_free_data(&certlist[i]);
+				n += loaded_certs;
+			}
+			free(certlist);
+			free(fname);
+		}
+		(*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 {
+		KMF_DATA *certlist = NULL;
+		uint32_t loaded_certs = 0;
+
+		rv = load_certs(kmfh, issuer, subject, serial, validity,
+		    fullpath, &certlist, &loaded_certs);
+		if (rv != KMF_OK) {
+			free(fullpath);
+			return (rv);
+		}
+
+		n = 0;
+		if (kmf_cert != NULL && certlist != NULL) {
+			for (i = 0; i < loaded_certs && i < maxcerts; i++) {
+				kmf_cert[n].certificate.Data =
+				    certlist[i].Data;
+				kmf_cert[n].certificate.Length =
+				    certlist[i].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 =
+				    strdup(fullpath);
+				n++;
+			}
+			/* If maxcerts < loaded_certs, clean up */
+			for (; i < loaded_certs; i++)
+				kmf_free_data(&certlist[i]);
+		} else if (certlist != NULL) {
+			for (i = 0; i < loaded_certs; i++)
+				kmf_free_data(&certlist[i]);
+			n = loaded_certs;
+		}
+		if (certlist != NULL)
+			free(certlist);
+		*num_certs = n;
+	}
+
+	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) {
+			kmf_free_data(&kmf_cert->certificate);
+		}
+		if (kmf_cert->kmf_private.label)
+			free(kmf_cert->kmf_private.label);
+	}
+}
+
+/*ARGSUSED*/
+KMF_RETURN
+OpenSSL_StoreCert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
+{
+	KMF_RETURN ret = KMF_OK;
+	KMF_DATA *cert = NULL;
+	char *outfilename = NULL;
+	char *dirpath = NULL;
+	char *fullpath = NULL;
+	KMF_ENCODE_FORMAT format;
+
+	/* Get the cert data */
+	cert = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist, numattr);
+	if (cert == NULL || cert->Data == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	/* Check the output filename and directory attributes. */
+	outfilename = kmf_get_attr_ptr(KMF_CERT_FILENAME_ATTR, attrlist,
+	    numattr);
+	if (outfilename == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	dirpath = kmf_get_attr_ptr(KMF_DIRPATH_ATTR, attrlist, numattr);
+	fullpath = get_fullpath(dirpath, outfilename);
+	if (fullpath == NULL)
+		return (KMF_ERR_BAD_CERTFILE);
+
+	/* Check the optional format attribute */
+	ret = kmf_get_attr(KMF_ENCODE_FORMAT_ATTR, attrlist, numattr,
+	    &format, NULL);
+	if (ret != KMF_OK) {
+		/* If there is no format attribute, then default to PEM */
+		format = KMF_FORMAT_PEM;
+		ret = KMF_OK;
+	} else if (format != KMF_FORMAT_ASN1 && format != KMF_FORMAT_PEM) {
+		ret = KMF_ERR_BAD_CERT_FORMAT;
+		goto out;
+	}
+
+	/* Store the certificate in the file with the specified format */
+	ret = kmf_create_cert_file(cert, format, fullpath);
+
+out:
+	if (fullpath != NULL)
+		free(fullpath);
+
+	return (ret);
+}
+
+
+KMF_RETURN
+OpenSSL_DeleteCert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
+{
+	KMF_RETURN rv;
+	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+	KMF_DATA certdata = {NULL, 0};
+	char *dirpath = NULL;
+	char *filename = NULL;
+	char *fullpath = NULL;
+	char *issuer = NULL;
+	char *subject = NULL;
+	KMF_BIGINT *serial = NULL;
+	KMF_CERT_VALIDITY validity;
+
+	/*
+	 * Get the DIRPATH and CERT_FILENAME attributes.  They can not be
+	 * NULL at the same time.
+	 */
+	dirpath = kmf_get_attr_ptr(KMF_DIRPATH_ATTR, attrlist, numattr);
+	filename = kmf_get_attr_ptr(KMF_CERT_FILENAME_ATTR, attrlist,
+	    numattr);
+	fullpath = get_fullpath(dirpath, filename);
+	if (fullpath == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	/* Get optional search criteria attributes */
+	issuer = kmf_get_attr_ptr(KMF_ISSUER_NAME_ATTR, attrlist, numattr);
+	subject = kmf_get_attr_ptr(KMF_SUBJECT_NAME_ATTR, attrlist, numattr);
+	serial = kmf_get_attr_ptr(KMF_BIGINT_ATTR, attrlist, numattr);
+	rv = kmf_get_attr(KMF_CERT_VALIDITY_ATTR, attrlist, numattr,
+	    &validity, NULL);
+	if (rv != KMF_OK) {
+		validity = KMF_ALL_CERTS;
+		rv = KMF_OK;
+	}
+
+	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, issuer, subject,
+				    serial, validity, fname, &certdata);
+
+				if (rv == KMF_ERR_CERT_NOT_FOUND) {
+					free(fname);
+					kmf_free_data(&certdata);
+					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);
+				kmf_free_data(&certdata);
+			}
+		}
+		(void) closedir(dirp);
+	} else {
+		/* Just try to load a single certificate */
+		rv = kmf_load_cert(kmfh, issuer, subject, serial, validity,
+		    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);
+
+	kmf_free_data(&certdata);
+
+	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_key(KMF_HANDLE *kmfh, KMF_ENCODE_FORMAT format, BIO *out,
+	KMF_CREDENTIAL *cred, EVP_PKEY *pkey, boolean_t private)
+{
+	int rv = 0;
+	RSA *rsa;
+	DSA *dsa;
+
+	if (pkey == NULL || out == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	switch (format) {
+		case KMF_FORMAT_RAWKEY:
+			/* same as ASN.1 */
+		case KMF_FORMAT_ASN1:
+			if (pkey->type == EVP_PKEY_RSA) {
+				rsa = EVP_PKEY_get1_RSA(pkey);
+				if (private)
+					rv = i2d_RSAPrivateKey_bio(out, rsa);
+				else
+					rv = i2d_RSAPublicKey_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);
+				if (private)
+					rv = PEM_write_bio_RSAPrivateKey(out,
+					    rsa, NULL, NULL, 0, NULL,
+					    (cred != NULL ? cred->cred : NULL));
+				else
+					rv = PEM_write_bio_RSAPublicKey(out,
+					    rsa);
+				RSA_free(rsa);
+			} else if (pkey->type == EVP_PKEY_DSA) {
+				dsa = EVP_PKEY_get1_DSA(pkey);
+				rv = PEM_write_bio_DSAPrivateKey(out,
+				    dsa, NULL, NULL, 0, NULL,
+				    (cred != NULL ? cred->cred : NULL));
+				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, int numattr,
+	KMF_ATTRIBUTE *attrlist)
+{
+	KMF_RETURN rv = KMF_OK;
+	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+	uint32_t eValue = 0x010001;
+	RSA *sslPrivKey = NULL;
+	DSA *sslDSAKey = NULL;
+	EVP_PKEY *eprikey = NULL;
+	EVP_PKEY *epubkey = NULL;
+	BIO *out = NULL;
+	KMF_KEY_HANDLE *pubkey = NULL, *privkey = NULL;
+	uint32_t keylen = 1024;
+	uint32_t keylen_size = sizeof (uint32_t);
+	boolean_t storekey = TRUE;
+	KMF_KEY_ALG keytype = KMF_RSA;
+
+	rv = kmf_get_attr(KMF_STOREKEY_BOOL_ATTR, attrlist, numattr,
+	    &storekey, NULL);
+	if (rv != KMF_OK) {
+		/* "storekey" is optional. Default is TRUE */
+		rv = KMF_OK;
+	}
+
+	rv = kmf_get_attr(KMF_KEYALG_ATTR, attrlist, numattr,
+	    (void *)&keytype, NULL);
+	if (rv != KMF_OK)
+		/* keytype is optional.  KMF_RSA is default */
+		rv = KMF_OK;
+
+	pubkey = kmf_get_attr_ptr(KMF_PUBKEY_HANDLE_ATTR, attrlist, numattr);
+	if (pubkey == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	privkey = kmf_get_attr_ptr(KMF_PRIVKEY_HANDLE_ATTR, attrlist, numattr);
+	if (privkey == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	(void) memset(pubkey, 0, sizeof (KMF_KEY_HANDLE));
+	(void) memset(privkey, 0, sizeof (KMF_KEY_HANDLE));
+
+	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 (keytype == KMF_RSA) {
+		KMF_BIGINT *rsaexp = NULL;
+
+		rsaexp = kmf_get_attr_ptr(KMF_RSAEXP_ATTR, attrlist, numattr);
+		if (rsaexp != NULL) {
+			if (rsaexp->len > 0 &&
+			    rsaexp->len <= sizeof (eValue) &&
+			    rsaexp->val != NULL) {
+				/* LINTED E_BAD_PTR_CAST_ALIGN */
+				eValue = *(uint32_t *)rsaexp->val;
+			} else {
+				rv = KMF_ERR_BAD_PARAMETER;
+				goto cleanup;
+			}
+		} else {
+			/* RSA Exponent is optional. Default is 0x10001 */
+			rv = KMF_OK;
+		}
+
+		rv = kmf_get_attr(KMF_KEYLENGTH_ATTR, attrlist, numattr,
+		    &keylen, &keylen_size);
+		if (rv == KMF_ERR_ATTR_NOT_FOUND)
+			/* keylen is optional, default is 1024 */
+			rv = KMF_OK;
+		if (rv != KMF_OK) {
+			rv = KMF_ERR_BAD_PARAMETER;
+			goto cleanup;
+		}
+
+		sslPrivKey = RSA_generate_key(keylen, eValue, NULL, NULL);
+		if (sslPrivKey == NULL) {
+			SET_ERROR(kmfh, ERR_get_error());
+			rv = KMF_ERR_KEYGEN_FAILED;
+		} else {
+			(void) EVP_PKEY_set1_RSA(eprikey, sslPrivKey);
+			privkey->kstype = KMF_KEYSTORE_OPENSSL;
+			privkey->keyalg = KMF_RSA;
+			privkey->keyclass = KMF_ASYM_PRI;
+			privkey->israw = FALSE;
+			privkey->keyp = (void *)eprikey;
+
+			/* OpenSSL derives the public key from the private */
+			(void) EVP_PKEY_set1_RSA(epubkey, sslPrivKey);
+			pubkey->kstype = KMF_KEYSTORE_OPENSSL;
+			pubkey->keyalg = KMF_RSA;
+			pubkey->israw = FALSE;
+			pubkey->keyclass = KMF_ASYM_PUB;
+			pubkey->keyp = (void *)epubkey;
+		}
+	} else if (keytype == KMF_DSA) {
+		DSA *dp;
+		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;
+		}
+
+		privkey->kstype = KMF_KEYSTORE_OPENSSL;
+		privkey->keyalg = KMF_DSA;
+		privkey->keyclass = KMF_ASYM_PRI;
+		privkey->israw = FALSE;
+		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;
+		}
+		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;
+
+			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;
+	}
+
+	if (storekey) {
+		KMF_ATTRIBUTE storeattrs[4]; /* max. 4 attributes needed */
+		int i = 0;
+		char *keyfile = NULL, *dirpath = NULL;
+		KMF_ENCODE_FORMAT format;
+		/*
+		 * Construct a new attribute arrray and call openssl_store_key
+		 */
+		kmf_set_attr_at_index(storeattrs, i, KMF_PRIVKEY_HANDLE_ATTR,
+		    privkey, sizeof (privkey));
+		i++;
+
+		dirpath = kmf_get_attr_ptr(KMF_DIRPATH_ATTR, attrlist, numattr);
+		if (dirpath != NULL) {
+			storeattrs[i].type = KMF_DIRPATH_ATTR;
+			storeattrs[i].pValue = dirpath;
+			storeattrs[i].valueLen = strlen(dirpath);
+			i++;
+		} else {
+			rv = KMF_OK; /* DIRPATH is optional */
+		}
+		keyfile = kmf_get_attr_ptr(KMF_KEY_FILENAME_ATTR,
+		    attrlist, numattr);
+		if (keyfile != NULL) {
+			storeattrs[i].type = KMF_KEY_FILENAME_ATTR;
+			storeattrs[i].pValue = keyfile;
+			storeattrs[i].valueLen = strlen(keyfile);
+			i++;
+		} else {
+			goto cleanup; /* KEYFILE is required */
+		}
+		rv = kmf_get_attr(KMF_ENCODE_FORMAT_ATTR, attrlist, numattr,
+		    (void *)&format, NULL);
+		if (rv == KMF_OK) {
+			storeattrs[i].type = KMF_ENCODE_FORMAT_ATTR;
+			storeattrs[i].pValue = &format;
+			storeattrs[i].valueLen = sizeof (format);
+			i++;
+		}
+
+		rv = OpenSSL_StoreKey(handle, i, storeattrs);
+	}
+
+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);
+
+	return (rv);
+}
+
+/*
+ * Make sure the BN conversion is properly padded with 0x00
+ * bytes.  If not, signature verification for DSA signatures
+ * may fail in the case where the bignum value does not use
+ * all of the bits.
+ */
+static int
+fixbnlen(BIGNUM *bn, unsigned char *buf, int len) {
+	int bytes = len - BN_num_bytes(bn);
+
+	/* prepend with leading 0x00 if necessary */
+	while (bytes-- > 0)
+		*buf++ = 0;
+
+	(void) BN_bn2bin(bn, buf);
+	/*
+	 * Return the desired length since we prepended it
+	 * with the necessary 0x00 padding.
+	 */
+	return (len);
+}
+
+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_algoid_to_algid(AlgOID);
+	if (AlgId == KMF_ALGID_NONE)
+		return (KMF_ERR_BAD_ALGORITHM);
+
+	if (key->keyalg == KMF_RSA) {
+		EVP_PKEY *pkey = (EVP_PKEY *)key->keyp;
+		uchar_t *p;
+		int 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 if (AlgId == KMF_ALGID_SHA256WithRSA)
+			md = EVP_sha256();
+		else if (AlgId == KMF_ALGID_SHA384WithRSA)
+			md = EVP_sha384();
+		else if (AlgId == KMF_ALGID_SHA512WithRSA)
+			md = EVP_sha512();
+		else if (AlgId == KMF_ALGID_RSA)
+			md = NULL;
+		else
+			return (KMF_ERR_BAD_ALGORITHM);
+
+		if ((md == NULL) && (AlgId == KMF_ALGID_RSA)) {
+			RSA *rsa = EVP_PKEY_get1_RSA((EVP_PKEY *)pkey);
+
+			p = output->Data;
+			if ((len = RSA_private_encrypt(tobesigned->Length,
+			    tobesigned->Data, p, rsa,
+			    RSA_PKCS1_PADDING)) <= 0) {
+				SET_ERROR(kmfh, ERR_get_error());
+				ret = KMF_ERR_INTERNAL;
+			}
+			output->Length = len;
+		} else {
+			(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, (uint32_t *)&len, pkey)) {
+				SET_ERROR(kmfh, ERR_get_error());
+				len = 0;
+				ret = KMF_ERR_INTERNAL;
+			}
+			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;
+
+		if (AlgId == KMF_ALGID_DSA ||
+		    AlgId == KMF_ALGID_SHA1WithDSA)
+			md = EVP_sha1();
+		else if (AlgId == KMF_ALGID_SHA256WithDSA)
+			md = EVP_sha256();
+		else /* Bad algorithm */
+			return (KMF_ERR_BAD_ALGORITHM);
+
+		/*
+		 * 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).
+		 */
+		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);
+
+		/* Only sign first 20 bytes for SHA2 */
+		if (AlgId == KMF_ALGID_SHA256WithDSA)
+			hashlen = 20;
+		dsasig = DSA_do_sign(hash, hashlen, dsa);
+		if (dsasig != NULL) {
+			int i;
+			output->Length = i = fixbnlen(dsasig->r, output->Data,
+			    hashlen);
+
+			output->Length += fixbnlen(dsasig->s, &output->Data[i],
+			    hashlen);
+
+			DSA_SIG_free(dsasig);
+		} else {
+			SET_ERROR(kmfh, ERR_get_error());
+		}
+		(void) EVP_MD_CTX_cleanup(&ctx);
+	} else {
+		return (KMF_ERR_BAD_PARAMETER);
+	}
+cleanup:
+	return (ret);
+}
+
+KMF_RETURN
+/*ARGSUSED*/
+OpenSSL_DeleteKey(KMF_HANDLE_T handle,
+	int numattr, KMF_ATTRIBUTE *attrlist)
+{
+	KMF_RETURN rv = KMF_OK;
+	KMF_KEY_HANDLE *key;
+	boolean_t destroy = B_TRUE;
+
+	key = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr);
+	if (key == NULL || key->keyp == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	rv = kmf_get_attr(KMF_DESTROY_BOOL_ATTR, attrlist, numattr,
+	    (void *)&destroy, NULL);
+	if (rv != KMF_OK) {
+		/* "destroy" is optional. Default is TRUE */
+		rv = KMF_OK;
+	}
+
+	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_free_raw_sym_key((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) {
+			if (key->keylabel != 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_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;
+#if OPENSSL_VERSION_NUMBER < 0x10000000L
+	STACK *emlst = NULL;
+#else
+        STACK_OF(OPENSSL_STRING) *emlst = NULL;
+#endif
+	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);
+#if OPENSSL_VERSION_NUMBER < 0x10000000L
+		for (j = 0; j < sk_num(emlst); j++)
+			(void) BIO_printf(mem, "%s\n", sk_value(emlst, j));
+#else
+		for (j = 0; j < sk_OPENSSL_STRING_num(emlst); j++)
+			(void) BIO_printf(mem, "%s\n",
+                            sk_OPENSSL_STRING_value(emlst, j));
+#endif
+
+		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_FindPrikeyByCert(KMF_HANDLE_T handle, int numattr,
+    KMF_ATTRIBUTE *attrlist)
+{
+	KMF_RETURN rv = KMF_OK;
+	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL;
+	KMF_KEY_CLASS keyclass = KMF_ASYM_PRI;
+	KMF_KEY_HANDLE *key = NULL;
+	uint32_t numkeys = 1; /* 1 key only */
+	char *dirpath = NULL;
+	char *keyfile = NULL;
+	KMF_ATTRIBUTE new_attrlist[16];
+	int i = 0;
+
+	/*
+	 * This is really just a FindKey operation, reuse the
+	 * FindKey function.
+	 */
+	kmf_set_attr_at_index(new_attrlist, i,
+	    KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
+	i++;
+
+	kmf_set_attr_at_index(new_attrlist, i,
+	    KMF_COUNT_ATTR, &numkeys, sizeof (uint32_t));
+	i++;
+
+	kmf_set_attr_at_index(new_attrlist, i,
+	    KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass));
+	i++;
+
+	key = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr);
+	if (key == NULL) {
+		return (KMF_ERR_BAD_PARAMETER);
+	} else {
+		kmf_set_attr_at_index(new_attrlist, i,
+		    KMF_KEY_HANDLE_ATTR, key, sizeof (KMF_KEY_HANDLE));
+		i++;
+	}
+
+	dirpath = kmf_get_attr_ptr(KMF_DIRPATH_ATTR, attrlist, numattr);
+	if (dirpath != NULL) {
+		kmf_set_attr_at_index(new_attrlist, i,
+		    KMF_DIRPATH_ATTR, dirpath, strlen(dirpath));
+		i++;
+	}
+
+	keyfile = kmf_get_attr_ptr(KMF_KEY_FILENAME_ATTR, attrlist, numattr);
+	if (keyfile == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+	else {
+		kmf_set_attr_at_index(new_attrlist, i,
+		    KMF_KEY_FILENAME_ATTR, keyfile, strlen(keyfile));
+		i++;
+	}
+
+	rv = OpenSSL_FindKey(handle, i, new_attrlist);
+	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,
+	int numattr, KMF_ATTRIBUTE *attrlist)
+{
+	KMF_RETURN ret = KMF_OK;
+	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+	OCSP_CERTID *id = NULL;
+	OCSP_REQUEST *req = NULL;
+	BIO *derbio = NULL;
+	char *reqfile;
+	KMF_DATA *issuer_cert;
+	KMF_DATA *user_cert;
+
+	user_cert = kmf_get_attr_ptr(KMF_USER_CERT_DATA_ATTR,
+	    attrlist, numattr);
+	if (user_cert == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	issuer_cert = kmf_get_attr_ptr(KMF_ISSUER_CERT_DATA_ATTR,
+	    attrlist, numattr);
+	if (issuer_cert == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	reqfile = kmf_get_attr_ptr(KMF_OCSP_REQUEST_FILENAME_ATTR,
+	    attrlist, numattr);
+	if (reqfile == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	ret = create_certid(handle, issuer_cert, 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 also deallocate certid's space.
+	 */
+	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++) {
+		X509 *x = sk_X509_value(certs, i);
+		/* Use pubkey_digest to get the key ID value */
+		(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 */
+/* ARGSUSED2 */
+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,
+	int numattr, KMF_ATTRIBUTE *attrlist)
+{
+	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;
+	KMF_DATA *issuer_cert;
+	KMF_DATA *user_cert;
+	KMF_DATA *signer_cert;
+	KMF_DATA *response;
+	int *response_reason, *response_status, *cert_status;
+	boolean_t ignore_response_sign = B_FALSE;	/* default is FALSE */
+	uint32_t response_lifetime;
+
+	issuer_cert = kmf_get_attr_ptr(KMF_ISSUER_CERT_DATA_ATTR,
+	    attrlist, numattr);
+	if (issuer_cert == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	user_cert = kmf_get_attr_ptr(KMF_USER_CERT_DATA_ATTR,
+	    attrlist, numattr);
+	if (user_cert == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	response = kmf_get_attr_ptr(KMF_OCSP_RESPONSE_DATA_ATTR,
+	    attrlist, numattr);
+	if (response == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	response_status = kmf_get_attr_ptr(KMF_OCSP_RESPONSE_STATUS_ATTR,
+	    attrlist, numattr);
+	if (response_status == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	response_reason = kmf_get_attr_ptr(KMF_OCSP_RESPONSE_REASON_ATTR,
+	    attrlist, numattr);
+	if (response_reason == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	cert_status = kmf_get_attr_ptr(KMF_OCSP_RESPONSE_CERT_STATUS_ATTR,
+	    attrlist, numattr);
+	if (cert_status == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	/* Read in the response */
+	derbio = BIO_new_mem_buf(response->Data, 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);
+	*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 */
+	ret = kmf_get_attr(KMF_IGNORE_RESPONSE_SIGN_ATTR, attrlist, numattr,
+	    (void *)&ignore_response_sign, NULL);
+	if (ret != KMF_OK)
+		ret = KMF_OK;
+
+	signer_cert = kmf_get_attr_ptr(KMF_SIGNER_CERT_DATA_ATTR,
+	    attrlist, numattr);
+
+	if (ignore_response_sign == B_FALSE) {
+		ret = check_response_signature(handle, bs,
+		    signer_cert, 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, issuer_cert, 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) {
+		*cert_status = OCSP_GOOD;
+	} else if (status == V_OCSP_CERTSTATUS_UNKNOWN) {
+		*cert_status = OCSP_UNKNOWN;
+	} else { /* revoked */
+		*cert_status = OCSP_REVOKED;
+		*response_reason = reason;
+	}
+	ret = KMF_OK;
+
+	/* resp. time is optional, so we don't care about the return code. */
+	(void) kmf_get_attr(KMF_RESPONSE_LIFETIME_ATTR, attrlist, numattr,
+	    (void *)&response_lifetime, NULL);
+
+	if (!OCSP_check_validity(thisupd, nextupd, 300,
+	    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 = NULL;
+	KMF_RAW_SYM_KEY *rkey = NULL;
+
+	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;
+			if (path != NULL &&
+			    ((key->keylabel = strdup(path)) == NULL)) {
+				EVP_PKEY_free(pkey);
+				return (KMF_ERR_MEMORY);
+			}
+		} 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_get_file_format(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;
+		} else if (rv == KMF_ERR_OPEN_FILE) {
+			return (KMF_ERR_KEY_NOT_FOUND);
+		}
+
+		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_read_input_file(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->keyp = (void *)rkey;
+			if (path != NULL &&
+			    ((key->keylabel = strdup(path)) == NULL)) {
+				rv = KMF_ERR_MEMORY;
+			}
+		}
+	}
+out:
+	if (rv != KMF_OK) {
+		if (rkey != NULL) {
+			kmf_free_raw_sym_key(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,
+	int numattr, KMF_ATTRIBUTE *attrlist)
+{
+	KMF_RETURN rv = KMF_OK;
+	char *fullpath = NULL;
+	uint32_t maxkeys;
+	KMF_KEY_HANDLE *key;
+	uint32_t *numkeys;
+	KMF_KEY_CLASS keyclass;
+	KMF_RAW_KEY_DATA *rawkey;
+	char *dirpath;
+	char *keyfile;
+
+	if (handle == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	numkeys = kmf_get_attr_ptr(KMF_COUNT_ATTR, attrlist, numattr);
+	if (numkeys == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	rv = kmf_get_attr(KMF_KEYCLASS_ATTR, attrlist, numattr,
+	    (void *)&keyclass, NULL);
+	if (rv != KMF_OK)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	if (keyclass != KMF_ASYM_PUB &&
+	    keyclass != KMF_ASYM_PRI &&
+	    keyclass != KMF_SYMMETRIC)
+		return (KMF_ERR_BAD_KEY_CLASS);
+
+	dirpath = kmf_get_attr_ptr(KMF_DIRPATH_ATTR, attrlist, numattr);
+	keyfile = kmf_get_attr_ptr(KMF_KEY_FILENAME_ATTR, attrlist, numattr);
+
+	fullpath = get_fullpath(dirpath, keyfile);
+
+	if (fullpath == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	maxkeys = *numkeys;
+	if (maxkeys == 0)
+		maxkeys = 0xFFFFFFFF;
+	*numkeys = 0;
+
+	key = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr);
+	/* it is okay to have "keys" contains NULL */
+
+	/*
+	 * The caller may want a list of the raw key data as well.
+	 * Useful for importing keys from a file into other keystores.
+	 */
+	rawkey = kmf_get_attr_ptr(KMF_RAW_KEY_ATTR, attrlist, numattr);
+
+	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 && n < maxkeys) {
+			if (strcmp(dp->d_name, ".") &&
+			    strcmp(dp->d_name, "..")) {
+				char *fname;
+
+				fname = get_fullpath(fullpath,
+				    (char *)&dp->d_name);
+
+				rv = fetch_key(handle, fname,
+				    keyclass, key ? &key[n] : NULL);
+
+				if (rv == KMF_OK) {
+					if (key != NULL && rawkey != NULL)
+						rv = convertToRawKey(
+						    key[n].keyp, &rawkey[n]);
+					n++;
+				}
+
+				if (rv != KMF_OK || key == NULL)
+					free(fname);
+			}
+		}
+		(void) closedir(dirp);
+		free(fullpath);
+		(*numkeys) = n;
+	} else {
+		rv = fetch_key(handle, fullpath, keyclass, key);
+		if (rv == KMF_OK)
+			(*numkeys) = 1;
+
+		if (rv != KMF_OK || key == NULL)
+			free(fullpath);
+
+		if (rv == KMF_OK && key != NULL && rawkey != NULL) {
+			rv = convertToRawKey(key->keyp, rawkey);
+		}
+	}
+
+	if (rv == KMF_OK && (*numkeys) == 0)
+		rv = KMF_ERR_KEY_NOT_FOUND;
+	else if (rv == KMF_ERR_KEY_NOT_FOUND && (*numkeys) > 0)
+		rv = KMF_OK;
+
+	return (rv);
+}
+
+#define	HANDLE_PK12_ERROR { \
+	SET_ERROR(kmfh, ERR_get_error()); \
+	rv = KMF_ERR_ENCODING; \
+	goto out; \
+}
+
+static int
+add_alias_to_bag(PKCS12_SAFEBAG *bag, X509 *xcert)
+{
+	if (xcert != NULL && xcert->aux != NULL &&
+	    xcert->aux->alias != NULL) {
+		if (PKCS12_add_friendlyname_asc(bag,
+		    (const char *)xcert->aux->alias->data,
+		    xcert->aux->alias->length) == 0)
+			return (0);
+	}
+	return (1);
+}
+
+static PKCS7 *
+add_cert_to_safe(X509 *sslcert, KMF_CREDENTIAL *cred,
+	uchar_t *keyid, unsigned int keyidlen)
+{
+	PKCS12_SAFEBAG *bag = NULL;
+	PKCS7 *cert_authsafe = NULL;
+	STACK_OF(PKCS12_SAFEBAG) *bag_stack;
+
+	bag_stack = sk_PKCS12_SAFEBAG_new_null();
+	if (bag_stack == NULL)
+		return (NULL);
+
+	/* Convert cert from X509 struct to PKCS#12 bag */
+	bag = PKCS12_x5092certbag(sslcert);
+	if (bag == NULL) {
+		goto out;
+	}
+
+	/* Add the key id to the certificate bag. */
+	if (keyidlen > 0 && !PKCS12_add_localkeyid(bag, keyid, keyidlen)) {
+		goto out;
+	}
+
+	if (!add_alias_to_bag(bag, sslcert))
+		goto out;
+
+	/* Pile it on the bag_stack. */
+	if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag)) {
+		goto out;
+	}
+	/* 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);
+
+out:
+	if (bag_stack != NULL)
+		sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free);
+
+	return (cert_authsafe);
+}
+
+static PKCS7 *
+add_key_to_safe(EVP_PKEY *pkey, KMF_CREDENTIAL *cred,
+	uchar_t *keyid,  unsigned int keyidlen,
+	char *label, int label_len)
+{
+	PKCS8_PRIV_KEY_INFO *p8 = NULL;
+	STACK_OF(PKCS12_SAFEBAG) *bag_stack = NULL;
+	PKCS12_SAFEBAG *bag = NULL;
+	PKCS7 *key_authsafe = NULL;
+
+	p8 = EVP_PKEY2PKCS8(pkey);
+	if (p8 == NULL) {
+		return (NULL);
+	}
+	/* 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) {
+		return (NULL);
+	}
+	if (keyidlen && !PKCS12_add_localkeyid(bag, keyid, keyidlen))
+		goto out;
+	if (label != NULL && !PKCS12_add_friendlyname(bag, label, label_len))
+		goto out;
+
+	/* Start a PKCS#12 safebag container for the private key. */
+	bag_stack = sk_PKCS12_SAFEBAG_new_null();
+	if (bag_stack == NULL)
+		goto out;
+
+	/* Pile on the private key on the bag_stack. */
+	if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag))
+		goto out;
+
+	key_authsafe = PKCS12_pack_p7data(bag_stack);
+
+out:
+	if (bag_stack != NULL)
+		sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free);
+	bag_stack = NULL;
+	return (key_authsafe);
+}
+
+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 (key->pubvalue.val != NULL) {
+		if ((dsa->pub_key = BN_bin2bn(key->pubvalue.val,
+		    key->pubvalue.len, dsa->pub_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 EVP_PKEY *
+raw_key_to_pkey(KMF_KEY_HANDLE *key)
+{
+	EVP_PKEY *pkey = NULL;
+	KMF_RAW_KEY_DATA *rawkey;
+	ASN1_TYPE *attr = NULL;
+	KMF_RETURN ret;
+
+	if (key == NULL || !key->israw)
+		return (NULL);
+
+	rawkey = (KMF_RAW_KEY_DATA *)key->keyp;
+	if (rawkey->keytype == KMF_RSA) {
+		pkey = ImportRawRSAKey(&rawkey->rawdata.rsa);
+	} else if (rawkey->keytype == KMF_DSA) {
+		pkey = ImportRawDSAKey(&rawkey->rawdata.dsa);
+	} else if (rawkey->keytype == KMF_ECDSA) {
+		/*
+		 * OpenSSL in Solaris does not support EC for
+		 * legal reasons
+		 */
+		return (NULL);
+	} else {
+		/* wrong kind of key */
+		return (NULL);
+	}
+
+	if (rawkey->label != NULL) {
+		if ((attr = ASN1_TYPE_new()) == NULL) {
+			EVP_PKEY_free(pkey);
+			return (NULL);
+		}
+		attr->value.bmpstring = ASN1_STRING_type_new(V_ASN1_BMPSTRING);
+		(void) ASN1_STRING_set(attr->value.bmpstring, rawkey->label,
+		    strlen(rawkey->label));
+		attr->type = V_ASN1_BMPSTRING;
+		attr->value.ptr = (char *)attr->value.bmpstring;
+		ret = set_pkey_attrib(pkey, attr, NID_friendlyName);
+		if (ret != KMF_OK) {
+			EVP_PKEY_free(pkey);
+			ASN1_TYPE_free(attr);
+			return (NULL);
+		}
+	}
+	if (rawkey->id.Data != NULL) {
+		if ((attr = ASN1_TYPE_new()) == NULL) {
+			EVP_PKEY_free(pkey);
+			return (NULL);
+		}
+		attr->value.octet_string =
+		    ASN1_STRING_type_new(V_ASN1_OCTET_STRING);
+		attr->type = V_ASN1_OCTET_STRING;
+		(void) ASN1_STRING_set(attr->value.octet_string,
+		    rawkey->id.Data, rawkey->id.Length);
+		attr->value.ptr = (char *)attr->value.octet_string;
+		ret = set_pkey_attrib(pkey, attr, NID_localKeyID);
+		if (ret != KMF_OK) {
+			EVP_PKEY_free(pkey);
+			ASN1_TYPE_free(attr);
+			return (NULL);
+		}
+	}
+	return (pkey);
+}
+
+/*
+ * Search a list of private keys to find one that goes with the certificate.
+ */
+static EVP_PKEY *
+find_matching_key(X509 *xcert, int numkeys, KMF_KEY_HANDLE *keylist)
+{
+	int i;
+	EVP_PKEY *pkey = NULL;
+
+	if (numkeys == 0 || keylist == NULL || xcert == NULL)
+		return (NULL);
+	for (i = 0; i < numkeys; i++) {
+		if (keylist[i].israw)
+			pkey = raw_key_to_pkey(&keylist[i]);
+		else
+			pkey = (EVP_PKEY *)keylist[i].keyp;
+		if (pkey != NULL) {
+			if (X509_check_private_key(xcert, pkey)) {
+				return (pkey);
+			} else {
+				EVP_PKEY_free(pkey);
+				pkey = NULL;
+			}
+		}
+	}
+	return (pkey);
+}
+
+static KMF_RETURN
+local_export_pk12(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;
+	PKCS7 *cert_authsafe = NULL;
+	PKCS7 *key_authsafe = NULL;
+	STACK_OF(PKCS7) *authsafe_stack = NULL;
+	PKCS12 *p12_elem = NULL;
+	int i;
+
+	if (numcerts == 0 && numkeys == 0)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	/*
+	 * 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;
+	}
+
+	/* Start a PKCS#7 stack. */
+	authsafe_stack = sk_PKCS7_new_null();
+	if (authsafe_stack == NULL) {
+		rv = KMF_ERR_MEMORY;
+		goto cleanup;
+	}
+	if (numcerts > 0) {
+		for (i = 0; rv == KMF_OK && i < numcerts; i++) {
+			const uchar_t *p = certlist[i].certificate.Data;
+			long len = certlist[i].certificate.Length;
+			X509 *xcert = NULL;
+			EVP_PKEY *pkey = NULL;
+			unsigned char keyid[EVP_MAX_MD_SIZE];
+			unsigned int keyidlen = 0;
+
+			xcert = d2i_X509(NULL, &p, len);
+			if (xcert == NULL) {
+				SET_ERROR(kmfh, ERR_get_error());
+				rv = KMF_ERR_ENCODING;
+			}
+			if (certlist[i].kmf_private.label != NULL) {
+				/* Set alias attribute */
+				(void) X509_alias_set1(xcert,
+				    (uchar_t *)certlist[i].kmf_private.label,
+				    strlen(certlist[i].kmf_private.label));
+			}
+			/* Check if there is a key corresponding to this cert */
+			pkey = find_matching_key(xcert, numkeys, keylist);
+
+			/*
+			 * If key is found, get fingerprint and create a
+			 * safebag.
+			 */
+			if (pkey != NULL) {
+				(void) X509_digest(xcert, EVP_sha1(),
+				    keyid, &keyidlen);
+				key_authsafe = add_key_to_safe(pkey, cred,
+				    keyid, keyidlen,
+				    certlist[i].kmf_private.label,
+				    (certlist[i].kmf_private.label ?
+				    strlen(certlist[i].kmf_private.label) : 0));
+
+				if (key_authsafe == NULL) {
+					X509_free(xcert);
+					EVP_PKEY_free(pkey);
+					goto cleanup;
+				}
+				/* Put the key safe into the Auth Safe */
+				if (!sk_PKCS7_push(authsafe_stack,
+				    key_authsafe)) {
+					X509_free(xcert);
+					EVP_PKEY_free(pkey);
+					goto cleanup;
+				}
+			}
+
+			/* create a certificate safebag */
+			cert_authsafe = add_cert_to_safe(xcert, cred, keyid,
+			    keyidlen);
+			if (cert_authsafe == NULL) {
+				X509_free(xcert);
+				EVP_PKEY_free(pkey);
+				goto cleanup;
+			}
+			if (!sk_PKCS7_push(authsafe_stack, cert_authsafe)) {
+				X509_free(xcert);
+				EVP_PKEY_free(pkey);
+				goto cleanup;
+			}
+
+			X509_free(xcert);
+			if (pkey)
+				EVP_PKEY_free(pkey);
+		}
+	} else if (numcerts == 0 && numkeys > 0) {
+		/*
+		 * If only adding keys to the file.
+		 */
+		for (i = 0; i < numkeys; i++) {
+			EVP_PKEY *pkey = NULL;
+
+			if (keylist[i].israw)
+				pkey = raw_key_to_pkey(&keylist[i]);
+			else
+				pkey = (EVP_PKEY *)keylist[i].keyp;
+
+			if (pkey == NULL)
+				continue;
+
+			key_authsafe = add_key_to_safe(pkey, cred,
+			    NULL, 0, NULL, 0);
+
+			if (key_authsafe == NULL) {
+				EVP_PKEY_free(pkey);
+				goto cleanup;
+			}
+			if (!sk_PKCS7_push(authsafe_stack, key_authsafe)) {
+				EVP_PKEY_free(pkey);
+				goto cleanup;
+			}
+		}
+	}
+	p12_elem = PKCS12_init(NID_pkcs7_data);
+	if (p12_elem == NULL) {
+		goto cleanup;
+	}
+
+	/* Put the PKCS#7 stack into the PKCS#12 element. */
+	if (!PKCS12_pack_authsafes(p12_elem, authsafe_stack)) {
+		goto cleanup;
+	}
+
+	/* 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)) {
+		goto cleanup;
+	}
+
+	/* Write the PKCS#12 element to the export file. */
+	if (!i2d_PKCS12_bio(bio, p12_elem)) {
+		goto cleanup;
+	}
+	PKCS12_free(p12_elem);
+
+cleanup:
+	/* Clear away the PKCS#7 stack, we're done with it. */
+	if (authsafe_stack)
+		sk_PKCS7_pop_free(authsafe_stack, PKCS7_free);
+
+	if (bio != NULL)
+		(void) BIO_free_all(bio);
+
+	return (rv);
+}
+
+KMF_RETURN
+openssl_build_pk12(KMF_HANDLE_T handle, int numcerts,
+    KMF_X509_DER_CERT *certlist, int numkeys, KMF_KEY_HANDLE *keylist,
+    KMF_CREDENTIAL *p12cred, char *filename)
+{
+	KMF_RETURN rv;
+
+	if (certlist == NULL && keylist == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	rv = local_export_pk12(handle, p12cred, numcerts, certlist,
+	    numkeys, keylist, filename);
+
+	return (rv);
+}
+
+KMF_RETURN
+OpenSSL_ExportPK12(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
+{
+	KMF_RETURN rv;
+	KMF_HANDLE *kmfh = (KMF_HANDLE  *)handle;
+	char *fullpath = NULL;
+	char *dirpath = NULL;
+	char *certfile = NULL;
+	char *keyfile = NULL;
+	char *filename = NULL;
+	KMF_CREDENTIAL *p12cred = NULL;
+	KMF_X509_DER_CERT certdata;
+	KMF_KEY_HANDLE key;
+	int gotkey = 0;
+	int gotcert = 0;
+
+	if (handle == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	/*
+	 *  First, find the certificate.
+	 */
+	dirpath = kmf_get_attr_ptr(KMF_DIRPATH_ATTR, attrlist, numattr);
+	certfile = kmf_get_attr_ptr(KMF_CERT_FILENAME_ATTR, attrlist, numattr);
+	if (certfile != NULL) {
+		fullpath = get_fullpath(dirpath, certfile);
+		if (fullpath == NULL)
+			return (KMF_ERR_BAD_PARAMETER);
+
+		if (isdir(fullpath)) {
+			free(fullpath);
+			return (KMF_ERR_AMBIGUOUS_PATHNAME);
+		}
+
+		(void) memset(&certdata, 0, sizeof (certdata));
+		rv = kmf_load_cert(kmfh, NULL, NULL, NULL, NULL,
+		    fullpath, &certdata.certificate);
+		if (rv != KMF_OK)
+			goto end;
+
+		gotcert++;
+		certdata.kmf_private.keystore_type = KMF_KEYSTORE_OPENSSL;
+		free(fullpath);
+	}
+
+	/*
+	 * Now find the private key.
+	 */
+	keyfile = kmf_get_attr_ptr(KMF_KEY_FILENAME_ATTR, attrlist, numattr);
+	if (keyfile != NULL) {
+		fullpath = get_fullpath(dirpath, keyfile);
+		if (fullpath == NULL)
+			return (KMF_ERR_BAD_PARAMETER);
+
+		if (isdir(fullpath)) {
+			free(fullpath);
+			return (KMF_ERR_AMBIGUOUS_PATHNAME);
+		}
+
+		(void) memset(&key, 0, sizeof (KMF_KEY_HANDLE));
+		rv = fetch_key(handle, fullpath, KMF_ASYM_PRI, &key);
+		if (rv != KMF_OK)
+			goto end;
+		gotkey++;
+	}
+
+	/*
+	 * Open the output file.
+	 */
+	filename = kmf_get_attr_ptr(KMF_OUTPUT_FILENAME_ATTR, attrlist,
+	    numattr);
+	if (filename == NULL) {
+		rv = KMF_ERR_BAD_PARAMETER;
+		goto end;
+	}
+
+	/* Stick the key and the cert into a PKCS#12 file */
+	p12cred = kmf_get_attr_ptr(KMF_PK12CRED_ATTR, attrlist, numattr);
+	if (p12cred == NULL) {
+		rv = KMF_ERR_BAD_PARAMETER;
+		goto end;
+	}
+
+	rv = local_export_pk12(handle, p12cred, 1, &certdata,
+	    1, &key, filename);
+
+end:
+	if (fullpath)
+		free(fullpath);
+
+	if (gotcert)
+		kmf_free_kmf_cert(handle, &certdata);
+	if (gotkey)
+		kmf_free_kmf_key(handle, &key);
+	return (rv);
+}
+
+/*
+ * Helper function to extract keys and certificates from
+ * a single PEM file.  Typically the file should contain a
+ * private key and an associated public key wrapped in an x509 cert.
+ * However, the file may be just a list of X509 certs with no keys.
+ */
+static KMF_RETURN
+extract_pem(KMF_HANDLE *kmfh,
+	char *issuer, char *subject, KMF_BIGINT *serial,
+	char *filename, CK_UTF8CHAR *pin,
+	CK_ULONG pinlen, EVP_PKEY **priv_key, KMF_DATA **certs,
+	int *numcerts)
+/* ARGSUSED6 */
+{
+	KMF_RETURN rv = KMF_OK;
+	FILE *fp;
+	STACK_OF(X509_INFO) *x509_info_stack = NULL;
+	int i, ncerts = 0, matchcerts = 0;
+	EVP_PKEY *pkey = NULL;
+	X509_INFO *info;
+	X509 *x;
+	X509_INFO **cert_infos = NULL;
+	KMF_DATA *certlist = NULL;
+
+	if (priv_key)
+		*priv_key = NULL;
+	if (certs)
+		*certs = NULL;
+	fp = fopen(filename, "r");
+	if (fp == NULL)
+		return (KMF_ERR_OPEN_FILE);
+
+	x509_info_stack = PEM_X509_INFO_read(fp, NULL, NULL, pin);
+	if (x509_info_stack == NULL) {
+		(void) fclose(fp);
+		return (KMF_ERR_ENCODING);
+	}
+	cert_infos = (X509_INFO **)malloc(sk_X509_INFO_num(x509_info_stack) *
+	    sizeof (X509_INFO *));
+	if (cert_infos == NULL) {
+		(void) fclose(fp);
+		rv = KMF_ERR_MEMORY;
+		goto err;
+	}
+
+	for (i = 0; i < sk_X509_INFO_num(x509_info_stack); i++) {
+		cert_infos[ncerts] = sk_X509_INFO_value(x509_info_stack, i);
+		ncerts++;
+	}
+
+	if (ncerts == 0) {
+		(void) fclose(fp);
+		rv = KMF_ERR_CERT_NOT_FOUND;
+		goto err;
+	}
+
+	if (priv_key != NULL) {
+		rewind(fp);
+		pkey = PEM_read_PrivateKey(fp, NULL, NULL, pin);
+	}
+	(void) fclose(fp);
+
+	x = cert_infos[ncerts - 1]->x509;
+	/*
+	 * Make sure the private key matchs the last cert in the file.
+	 */
+	if (pkey != NULL && !X509_check_private_key(x, pkey)) {
+		EVP_PKEY_free(pkey);
+		rv = KMF_ERR_KEY_MISMATCH;
+		goto err;
+	}
+
+	certlist = (KMF_DATA *)calloc(ncerts, sizeof (KMF_DATA));
+	if (certlist == NULL) {
+		if (pkey != NULL)
+			EVP_PKEY_free(pkey);
+		rv = KMF_ERR_MEMORY;
+		goto err;
+	}
+
+	/*
+	 * Convert all of the certs to DER format.
+	 */
+	matchcerts = 0;
+	for (i = 0; rv == KMF_OK && certs != NULL && i < ncerts; i++) {
+		boolean_t match = FALSE;
+		info =  cert_infos[ncerts - 1 - i];
+
+		rv = check_cert(info->x509, issuer, subject, serial, &match);
+		if (rv != KMF_OK || match != TRUE) {
+			rv = KMF_OK;
+			continue;
+		}
+
+		rv = ssl_cert2KMFDATA(kmfh, info->x509,
+			&certlist[matchcerts++]);
+
+		if (rv != KMF_OK) {
+			int j;
+			for (j = 0; j < matchcerts; j++)
+				kmf_free_data(&certlist[j]);
+			free(certlist);
+			certlist = NULL;
+			ncerts = matchcerts = 0;
+		}
+	}
+
+	if (numcerts != NULL)
+		*numcerts = matchcerts;
+
+	if (certs != NULL)
+		*certs = certlist;
+	else if (certlist != NULL) {
+		for (i = 0; i < ncerts; i++)
+			kmf_free_data(&certlist[i]);
+		free(certlist);
+		certlist = NULL;
+	}
+
+	if (priv_key == NULL && pkey != NULL)
+		EVP_PKEY_free(pkey);
+	else if (priv_key != NULL && pkey != NULL)
+		*priv_key = pkey;
+
+err:
+	/* Cleanup the stack of X509 info records */
+	for (i = 0; i < sk_X509_INFO_num(x509_info_stack); i++) {
+		info = (X509_INFO *)sk_X509_INFO_value(x509_info_stack, i);
+		X509_INFO_free(info);
+	}
+	if (x509_info_stack)
+		sk_X509_INFO_free(x509_info_stack);
+
+	if (cert_infos != NULL)
+		free(cert_infos);
+
+	return (rv);
+}
+
+static KMF_RETURN
+openssl_parse_bags(STACK_OF(PKCS12_SAFEBAG) *bags, char *pin,
+	STACK_OF(EVP_PKEY) *keys, STACK_OF(X509) *certs)
+{
+	KMF_RETURN ret;
+	int i;
+
+	for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) {
+		PKCS12_SAFEBAG *bag = sk_PKCS12_SAFEBAG_value(bags, i);
+		ret = openssl_parse_bag(bag, pin, (pin ? strlen(pin) : 0),
+		    keys, certs);
+
+		if (ret != KMF_OK)
+			return (ret);
+	}
+
+	return (ret);
+}
+
+static KMF_RETURN
+set_pkey_attrib(EVP_PKEY *pkey, ASN1_TYPE *attrib, int nid)
+{
+	X509_ATTRIBUTE *attr = NULL;
+
+	if (pkey == NULL || attrib == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	if (pkey->attributes == NULL) {
+		pkey->attributes = sk_X509_ATTRIBUTE_new_null();
+		if (pkey->attributes == NULL)
+			return (KMF_ERR_MEMORY);
+	}
+	attr = X509_ATTRIBUTE_create(nid, attrib->type, attrib->value.ptr);
+	if (attr != NULL) {
+		int i;
+		X509_ATTRIBUTE *a;
+		for (i = 0;
+		    i < sk_X509_ATTRIBUTE_num(pkey->attributes); i++) {
+			a = sk_X509_ATTRIBUTE_value(pkey->attributes, i);
+			if (OBJ_obj2nid(a->object) == nid) {
+				X509_ATTRIBUTE_free(a);
+				sk_X509_ATTRIBUTE_set(pkey->attributes,
+				    i, attr);
+				return (KMF_OK);
+			}
+		}
+		if (sk_X509_ATTRIBUTE_push(pkey->attributes, attr) == NULL) {
+			X509_ATTRIBUTE_free(attr);
+			return (KMF_ERR_MEMORY);
+		}
+	} else {
+		return (KMF_ERR_MEMORY);
+	}
+
+	return (KMF_OK);
+}
+
+static KMF_RETURN
+openssl_parse_bag(PKCS12_SAFEBAG *bag, char *pass, int passlen,
+	STACK_OF(EVP_PKEY) *keylist, STACK_OF(X509) *certlist)
+{
+	KMF_RETURN ret = KMF_OK;
+	PKCS8_PRIV_KEY_INFO *p8 = NULL;
+	EVP_PKEY *pkey = NULL;
+	X509 *xcert = NULL;
+	ASN1_TYPE *keyid = NULL;
+	ASN1_TYPE *fname = NULL;
+	uchar_t *data = NULL;
+
+	keyid = PKCS12_get_attr(bag, NID_localKeyID);
+	fname = PKCS12_get_attr(bag, NID_friendlyName);
+
+	switch (M_PKCS12_bag_type(bag)) {
+		case NID_keyBag:
+			if (keylist == NULL)
+				goto end;
+			pkey = EVP_PKCS82PKEY(bag->value.keybag);
+			if (pkey == NULL)
+				ret = KMF_ERR_PKCS12_FORMAT;
+
+			break;
+		case NID_pkcs8ShroudedKeyBag:
+			if (keylist == NULL)
+				goto end;
+			p8 = M_PKCS12_decrypt_skey(bag, pass, passlen);
+			if (p8 == NULL)
+				return (KMF_ERR_AUTH_FAILED);
+			pkey = EVP_PKCS82PKEY(p8);
+			PKCS8_PRIV_KEY_INFO_free(p8);
+			if (pkey == NULL)
+				ret = KMF_ERR_PKCS12_FORMAT;
+			break;
+		case NID_certBag:
+			if (certlist == NULL)
+				goto end;
+			if (M_PKCS12_cert_bag_type(bag) != NID_x509Certificate)
+				return (KMF_ERR_PKCS12_FORMAT);
+			xcert = M_PKCS12_certbag2x509(bag);
+			if (xcert == NULL) {
+				ret = KMF_ERR_PKCS12_FORMAT;
+				goto end;
+			}
+			if (keyid != NULL) {
+				if (X509_keyid_set1(xcert,
+				    keyid->value.octet_string->data,
+				    keyid->value.octet_string->length) == 0) {
+					ret = KMF_ERR_PKCS12_FORMAT;
+					goto end;
+				}
+			}
+			if (fname != NULL) {
+				int len, r;
+				len = ASN1_STRING_to_UTF8(&data,
+				    fname->value.asn1_string);
+				if (len > 0 && data != NULL) {
+					r = X509_alias_set1(xcert, data, len);
+					if (r == NULL) {
+						ret = KMF_ERR_PKCS12_FORMAT;
+						goto end;
+					}
+				} else {
+					ret = KMF_ERR_PKCS12_FORMAT;
+					goto end;
+				}
+			}
+			if (sk_X509_push(certlist, xcert) == 0)
+				ret = KMF_ERR_MEMORY;
+			else
+				xcert = NULL;
+			break;
+		case NID_safeContentsBag:
+			return (openssl_parse_bags(bag->value.safes, pass,
+			    keylist, certlist));
+		default:
+			ret = KMF_ERR_PKCS12_FORMAT;
+			break;
+	}
+
+	/*
+	 * Set the ID and/or FriendlyName attributes on the key.
+	 * If converting to PKCS11 objects, these can translate to CKA_ID
+	 * and CKA_LABEL values.
+	 */
+	if (pkey != NULL && ret == KMF_OK) {
+		ASN1_TYPE *attr = NULL;
+		if (keyid != NULL && keyid->type == V_ASN1_OCTET_STRING) {
+			if ((attr = ASN1_TYPE_new()) == NULL)
+				return (KMF_ERR_MEMORY);
+			attr->value.octet_string =
+			    ASN1_STRING_dup(keyid->value.octet_string);
+			attr->type = V_ASN1_OCTET_STRING;
+			attr->value.ptr = (char *)attr->value.octet_string;
+			ret = set_pkey_attrib(pkey, attr, NID_localKeyID);
+			OPENSSL_free(attr);
+		}
+
+		if (ret == KMF_OK && fname != NULL &&
+		    fname->type == V_ASN1_BMPSTRING) {
+			if ((attr = ASN1_TYPE_new()) == NULL)
+				return (KMF_ERR_MEMORY);
+			attr->value.bmpstring =
+			    ASN1_STRING_dup(fname->value.bmpstring);
+			attr->type = V_ASN1_BMPSTRING;
+			attr->value.ptr = (char *)attr->value.bmpstring;
+			ret = set_pkey_attrib(pkey, attr, NID_friendlyName);
+			OPENSSL_free(attr);
+		}
+
+		if (ret == KMF_OK && keylist != NULL &&
+		    sk_EVP_PKEY_push(keylist, pkey) == 0)
+			ret = KMF_ERR_MEMORY;
+	}
+	if (ret == KMF_OK && keylist != NULL)
+		pkey = NULL;
+end:
+	if (pkey != NULL)
+		EVP_PKEY_free(pkey);
+	if (xcert != NULL)
+		X509_free(xcert);
+	if (data != NULL)
+		OPENSSL_free(data);
+
+	return (ret);
+}
+
+static KMF_RETURN
+openssl_pkcs12_parse(PKCS12 *p12, char *pin,
+	STACK_OF(EVP_PKEY) *keys,
+	STACK_OF(X509) *certs,
+	STACK_OF(X509) *ca)
+/* ARGSUSED3 */
+{
+	KMF_RETURN ret = KMF_OK;
+	STACK_OF(PKCS7) *asafes = NULL;
+	STACK_OF(PKCS12_SAFEBAG) *bags = NULL;
+	int i, bagnid;
+	PKCS7 *p7;
+
+	if (p12 == NULL || (keys == NULL && certs == NULL))
+		return (KMF_ERR_BAD_PARAMETER);
+
+	if (pin == NULL || *pin == NULL) {
+		if (PKCS12_verify_mac(p12, NULL, 0)) {
+			pin = NULL;
+		} else if (PKCS12_verify_mac(p12, "", 0)) {
+			pin = "";
+		} else {
+			return (KMF_ERR_AUTH_FAILED);
+		}
+	} else if (!PKCS12_verify_mac(p12, pin, -1)) {
+		return (KMF_ERR_AUTH_FAILED);
+	}
+
+	if ((asafes = PKCS12_unpack_authsafes(p12)) == NULL)
+		return (KMF_ERR_PKCS12_FORMAT);
+
+	for (i = 0; ret == KMF_OK && i < sk_PKCS7_num(asafes); i++) {
+		bags = NULL;
+		p7 = sk_PKCS7_value(asafes, i);
+		bagnid = OBJ_obj2nid(p7->type);
+
+		if (bagnid == NID_pkcs7_data) {
+			bags = PKCS12_unpack_p7data(p7);
+		} else if (bagnid == NID_pkcs7_encrypted) {
+			bags = PKCS12_unpack_p7encdata(p7, pin,
+			    (pin ? strlen(pin) : 0));
+		} else {
+			continue;
+		}
+		if (bags == NULL) {
+			ret = KMF_ERR_PKCS12_FORMAT;
+			goto out;
+		}
+
+		if (openssl_parse_bags(bags, pin, keys, certs) != KMF_OK)
+			ret = KMF_ERR_PKCS12_FORMAT;
+
+		sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
+	}
+out:
+	if (asafes != NULL)
+		sk_PKCS7_pop_free(asafes, PKCS7_free);
+
+	return (ret);
+}
+
+/*
+ * Helper function to decrypt and parse PKCS#12 import file.
+ */
+static KMF_RETURN
+extract_pkcs12(BIO *fbio, CK_UTF8CHAR *pin, CK_ULONG pinlen,
+	STACK_OF(EVP_PKEY) **priv_key, STACK_OF(X509) **certs,
+	STACK_OF(X509) **ca)
+/* ARGSUSED2 */
+{
+	PKCS12			*pk12, *pk12_tmp;
+	STACK_OF(EVP_PKEY)	*pkeylist = NULL;
+	STACK_OF(X509)		*xcertlist = NULL;
+	STACK_OF(X509)		*cacertlist = 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;
+
+	xcertlist = sk_X509_new_null();
+	if (xcertlist == NULL) {
+		PKCS12_free(pk12);
+		return (KMF_ERR_MEMORY);
+	}
+	pkeylist = sk_EVP_PKEY_new_null();
+	if (pkeylist == NULL) {
+		sk_X509_pop_free(xcertlist, X509_free);
+		PKCS12_free(pk12);
+		return (KMF_ERR_MEMORY);
+	}
+
+	if (openssl_pkcs12_parse(pk12, (char *)pin, pkeylist, xcertlist,
+	    cacertlist) != KMF_OK) {
+		sk_X509_pop_free(xcertlist, X509_free);
+		sk_EVP_PKEY_pop_free(pkeylist, EVP_PKEY_free);
+		PKCS12_free(pk12);
+		return (KMF_ERR_PKCS12_FORMAT);
+	}
+
+	if (priv_key && pkeylist)
+		*priv_key = pkeylist;
+	else if (pkeylist)
+		sk_EVP_PKEY_pop_free(pkeylist, EVP_PKEY_free);
+	if (certs && xcertlist)
+		*certs = xcertlist;
+	else if (xcertlist)
+		sk_X509_pop_free(xcertlist, X509_free);
+	if (ca && cacertlist)
+		*ca = cacertlist;
+	else if (cacertlist)
+		sk_X509_pop_free(cacertlist, X509_free);
+
+end_extract_pkcs12:
+
+	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_free_raw_key(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_free_raw_key(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_X509_DER_CERT **certlist, int *ncerts)
+{
+	KMF_RETURN rv = KMF_OK;
+	KMF_X509_DER_CERT *list = (*certlist);
+	KMF_X509_DER_CERT cert;
+	int n = (*ncerts);
+
+	if (list == NULL) {
+		list = (KMF_X509_DER_CERT *)malloc(sizeof (KMF_X509_DER_CERT));
+	} else {
+		list = (KMF_X509_DER_CERT *)realloc(list,
+		    sizeof (KMF_X509_DER_CERT) * (n + 1));
+	}
+
+	if (list == NULL)
+		return (KMF_ERR_MEMORY);
+
+	(void) memset(&cert, 0, sizeof (cert));
+	rv = ssl_cert2KMFDATA(kmfh, sslcert, &cert.certificate);
+	if (rv == KMF_OK) {
+		int len = 0;
+		/* Get the alias name for the cert if there is one */
+		char *a = (char *)X509_alias_get0(sslcert, &len);
+		if (a != NULL)
+			cert.kmf_private.label = strdup(a);
+		cert.kmf_private.keystore_type = KMF_KEYSTORE_OPENSSL;
+
+		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 X509_ATTRIBUTE *
+find_attr(STACK_OF(X509_ATTRIBUTE) *attrs, int nid)
+{
+	X509_ATTRIBUTE *a;
+	int i;
+
+	if (attrs == NULL)
+		return (NULL);
+
+	for (i = 0; i < sk_X509_ATTRIBUTE_num(attrs); i++) {
+		a = sk_X509_ATTRIBUTE_value(attrs, i);
+		if (OBJ_obj2nid(a->object) == nid)
+			return (a);
+	}
+	return (NULL);
+}
+
+static KMF_RETURN
+convertToRawKey(EVP_PKEY *pkey, KMF_RAW_KEY_DATA *key)
+{
+	KMF_RETURN rv = KMF_OK;
+	X509_ATTRIBUTE *attr;
+
+	if (pkey == NULL || key == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+	/* Convert SSL key to raw key */
+	switch (pkey->type) {
+		case EVP_PKEY_RSA:
+			rv = exportRawRSAKey(EVP_PKEY_get1_RSA(pkey),
+			    key);
+			if (rv != KMF_OK)
+				return (rv);
+			break;
+		case EVP_PKEY_DSA:
+			rv = exportRawDSAKey(EVP_PKEY_get1_DSA(pkey),
+			    key);
+			if (rv != KMF_OK)
+				return (rv);
+			break;
+		default:
+			return (KMF_ERR_BAD_PARAMETER);
+	}
+	/*
+	 * If friendlyName, add it to record.
+	 */
+	attr = find_attr(pkey->attributes, NID_friendlyName);
+	if (attr != NULL) {
+		ASN1_TYPE *ty = NULL;
+		int numattr = sk_ASN1_TYPE_num(attr->value.set);
+		if (attr->single == 0 && numattr > 0) {
+			ty = sk_ASN1_TYPE_value(attr->value.set, 0);
+		}
+		if (ty != NULL) {
+#if OPENSSL_VERSION_NUMBER < 0x10000000L
+			key->label = uni2asc(ty->value.bmpstring->data,
+			    ty->value.bmpstring->length);
+#else
+			key->label = OPENSSL_uni2asc(ty->value.bmpstring->data,
+			    ty->value.bmpstring->length);
+#endif
+		}
+	} else {
+		key->label = NULL;
+	}
+
+	/*
+	 * If KeyID, add it to record as a KMF_DATA object.
+	 */
+	attr = find_attr(pkey->attributes, NID_localKeyID);
+	if (attr != NULL) {
+		ASN1_TYPE *ty = NULL;
+		int numattr = sk_ASN1_TYPE_num(attr->value.set);
+		if (attr->single == 0 && numattr > 0) {
+			ty = sk_ASN1_TYPE_value(attr->value.set, 0);
+		}
+		key->id.Data = (uchar_t *)malloc(
+		    ty->value.octet_string->length);
+		if (key->id.Data == NULL)
+			return (KMF_ERR_MEMORY);
+		(void) memcpy(key->id.Data, ty->value.octet_string->data,
+		    ty->value.octet_string->length);
+		key->id.Length = ty->value.octet_string->length;
+	} else {
+		(void) memset(&key->id, 0, sizeof (KMF_DATA));
+	}
+
+	return (rv);
+}
+
+static KMF_RETURN
+convertPK12Objects(
+	KMF_HANDLE *kmfh,
+	STACK_OF(EVP_PKEY) *sslkeys,
+	STACK_OF(X509) *sslcert,
+	STACK_OF(X509) *sslcacerts,
+	KMF_RAW_KEY_DATA **keylist, int *nkeys,
+	KMF_X509_DER_CERT **certlist, int *ncerts)
+{
+	KMF_RETURN rv = KMF_OK;
+	KMF_RAW_KEY_DATA key;
+	int i;
+
+	for (i = 0; sslkeys != NULL && i < sk_EVP_PKEY_num(sslkeys); i++) {
+		EVP_PKEY *pkey = sk_EVP_PKEY_value(sslkeys, i);
+		rv = convertToRawKey(pkey, &key);
+		if (rv == KMF_OK)
+			rv = add_key_to_list(keylist, &key, nkeys);
+
+		if (rv != KMF_OK)
+			return (rv);
+	}
+
+	/* Now add the certificate to the certlist */
+	for (i = 0; sslcert != NULL && i < sk_X509_num(sslcert); i++) {
+		X509 *cert = sk_X509_value(sslcert, i);
+		rv = add_cert_to_list(kmfh, cert, certlist, ncerts);
+		if (rv != KMF_OK)
+			return (rv);
+	}
+
+	/* Also add any included CA certs to the list */
+	for (i = 0; sslcacerts != NULL && 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.
+		 */
+		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_import_objects(KMF_HANDLE *kmfh,
+	char *filename, KMF_CREDENTIAL *cred,
+	KMF_X509_DER_CERT **certlist, int *ncerts,
+	KMF_RAW_KEY_DATA **keylist, int *nkeys)
+{
+	KMF_RETURN	rv = KMF_OK;
+	KMF_ENCODE_FORMAT format;
+	BIO		*bio = NULL;
+	STACK_OF(EVP_PKEY)	*privkeys = NULL;
+	STACK_OF(X509)		*certs = NULL;
+	STACK_OF(X509)		*cacerts = NULL;
+
+	/*
+	 * auto-detect the file format, regardless of what
+	 * the 'format' parameters in the params say.
+	 */
+	rv = kmf_get_file_format(filename, &format);
+	if (rv != KMF_OK) {
+		return (rv);
+	}
+
+	/* This function only works for PEM or PKCS#12 files */
+	if (format != KMF_FORMAT_PEM &&
+	    format != KMF_FORMAT_PEM_KEYPAIR &&
+	    format != KMF_FORMAT_PKCS12)
+		return (KMF_ERR_ENCODING);
+
+	*certlist = NULL;
+	*keylist = NULL;
+	*ncerts = 0;
+	*nkeys = 0;
+
+	if (format == KMF_FORMAT_PKCS12) {
+		bio = BIO_new_file(filename, "rb");
+		if (bio == NULL) {
+			SET_ERROR(kmfh, ERR_get_error());
+			rv = KMF_ERR_OPEN_FILE;
+			goto end;
+		}
+
+		rv = extract_pkcs12(bio, (uchar_t *)cred->cred,
+		    (uint32_t)cred->credlen, &privkeys, &certs, &cacerts);
+
+		if (rv  == KMF_OK)
+			/* Convert keys and certs to exportable format */
+			rv = convertPK12Objects(kmfh, privkeys, certs, cacerts,
+			    keylist, nkeys, certlist, ncerts);
+	} else {
+		EVP_PKEY *pkey;
+		KMF_DATA *certdata = NULL;
+		KMF_X509_DER_CERT *kmfcerts = NULL;
+		int i;
+		rv = extract_pem(kmfh, NULL, NULL, NULL, filename,
+		    (uchar_t *)cred->cred, (uint32_t)cred->credlen,
+		    &pkey, &certdata, ncerts);
+
+		/* Reached end of import file? */
+		if (rv == KMF_OK && pkey != NULL) {
+			privkeys = sk_EVP_PKEY_new_null();
+			if (privkeys == NULL) {
+				rv = KMF_ERR_MEMORY;
+				goto end;
+			}
+			(void) sk_EVP_PKEY_push(privkeys, pkey);
+			/* convert the certificate list here */
+			if (*ncerts > 0 && certlist != NULL) {
+				kmfcerts = (KMF_X509_DER_CERT *)calloc(*ncerts,
+				    sizeof (KMF_X509_DER_CERT));
+				if (kmfcerts == NULL) {
+					rv = KMF_ERR_MEMORY;
+					goto end;
+				}
+				for (i = 0; i < *ncerts; i++) {
+					kmfcerts[i].certificate = certdata[i];
+					kmfcerts[i].kmf_private.keystore_type =
+					    KMF_KEYSTORE_OPENSSL;
+				}
+				*certlist = kmfcerts;
+			}
+			/*
+			 * Convert keys to exportable format, the certs
+			 * are already OK.
+			 */
+			rv = convertPK12Objects(kmfh, privkeys, NULL, NULL,
+			    keylist, nkeys, NULL, NULL);
+		}
+	}
+end:
+	if (bio != NULL)
+		(void) BIO_free(bio);
+
+	if (privkeys)
+		sk_EVP_PKEY_pop_free(privkeys, EVP_PKEY_free);
+	if (certs)
+		sk_X509_pop_free(certs, X509_free);
+	if (cacerts)
+		sk_X509_pop_free(cacerts, X509_free);
+
+	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,
+	int numattr, KMF_ATTRIBUTE *attrlist)
+{
+	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;
+	KMF_KEY_HANDLE *symkey;
+	KMF_KEY_ALG keytype;
+	uint32_t keylen;
+	uint32_t keylen_size = sizeof (keylen);
+	char *dirpath;
+	char *keyfile;
+
+	if (kmfh == NULL)
+		return (KMF_ERR_UNINITIALIZED);
+
+	symkey = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr);
+	if (symkey == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	dirpath = kmf_get_attr_ptr(KMF_DIRPATH_ATTR, attrlist, numattr);
+
+	keyfile = kmf_get_attr_ptr(KMF_KEY_FILENAME_ATTR, attrlist, numattr);
+	if (keyfile == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	ret = kmf_get_attr(KMF_KEYALG_ATTR, attrlist, numattr,
+	    (void *)&keytype, NULL);
+	if (ret != KMF_OK)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	ret = kmf_get_attr(KMF_KEYLENGTH_ATTR, attrlist, numattr,
+	    &keylen, &keylen_size);
+	if (ret == KMF_ERR_ATTR_NOT_FOUND &&
+	    (keytype == KMF_DES || keytype == KMF_DES3))
+		/* keylength is not required for DES and 3DES */
+		ret = KMF_OK;
+	if (ret != KMF_OK)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	fullpath = get_fullpath(dirpath, keyfile);
+	if (fullpath == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	/* If the requested file exists, return an error */
+	if (test_for_file(fullpath, 0400) == 1) {
+		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 (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 (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 (keytype == KMF_AES || keytype == KMF_RC4 ||
+	    keytype == KMF_GENERIC_SECRET) {
+		int bytes;
+
+		if (keylen % 8 != 0) {
+			ret = KMF_ERR_BAD_KEY_SIZE;
+			goto out;
+		}
+
+		if (keytype == KMF_AES) {
+			if (keylen != 128 &&
+			    keylen != 192 &&
+			    keylen != 256) {
+				ret = KMF_ERR_BAD_KEY_SIZE;
+				goto out;
+			}
+		}
+
+		bytes = keylen/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 = 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_free_raw_sym_key(rkey);
+		symkey->keyp = NULL;
+		symkey->keyalg = KMF_KEYALG_NONE;
+	}
+
+	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);
+}
+
+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_read_input_file(handle, symkey->keylabel, &keyvalue);
+		if (rv != KMF_OK)
+			return (rv);
+		rkey->keydata.len = keyvalue.Length;
+		rkey->keydata.val = keyvalue.Data;
+	}
+
+	return (rv);
+}
+
+/*
+ * substitute for the unsafe access(2) function.
+ * If the file in question already exists, return 1.
+ * else 0.  If an error occurs during testing (other
+ * than EEXIST), return -1.
+ */
+static int
+test_for_file(char *filename, mode_t mode)
+{
+	int fd;
+
+	/*
+	 * Try to create the file with the EXCL flag.
+	 * The call should fail if the file exists.
+	 */
+	fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, mode);
+	if (fd == -1 && errno == EEXIST)
+		return (1);
+	else if (fd == -1) /* some other error */
+		return (-1);
+
+	/* The file did NOT exist.  Delete the testcase. */
+	(void) close(fd);
+	(void) unlink(filename);
+	return (0);
+}
+
+KMF_RETURN
+OpenSSL_StoreKey(KMF_HANDLE_T handle, int numattr,
+	KMF_ATTRIBUTE *attrlist)
+{
+	KMF_RETURN rv = KMF_OK;
+	KMF_HANDLE	*kmfh = (KMF_HANDLE *)handle;
+	KMF_KEY_HANDLE *pubkey = NULL, *prikey = NULL;
+	KMF_RAW_KEY_DATA *rawkey;
+	EVP_PKEY *pkey = NULL;
+	KMF_ENCODE_FORMAT format = KMF_FORMAT_PEM;
+	KMF_CREDENTIAL cred = {NULL, 0};
+	BIO *out = NULL;
+	int keys = 0;
+	char *fullpath = NULL;
+	char *keyfile = NULL;
+	char *dirpath = NULL;
+
+	pubkey = kmf_get_attr_ptr(KMF_PUBKEY_HANDLE_ATTR, attrlist, numattr);
+	if (pubkey != NULL)
+		keys++;
+
+	prikey = kmf_get_attr_ptr(KMF_PRIVKEY_HANDLE_ATTR, attrlist, numattr);
+	if (prikey != NULL)
+		keys++;
+
+	rawkey = kmf_get_attr_ptr(KMF_RAW_KEY_ATTR, attrlist, numattr);
+	if (rawkey != NULL)
+		keys++;
+
+	/*
+	 * Exactly 1 type of key must be passed to this function.
+	 */
+	if (keys != 1)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	keyfile = (char *)kmf_get_attr_ptr(KMF_KEY_FILENAME_ATTR, attrlist,
+	    numattr);
+	if (keyfile == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	dirpath = kmf_get_attr_ptr(KMF_DIRPATH_ATTR, attrlist, numattr);
+
+	fullpath = get_fullpath(dirpath, keyfile);
+
+	/* Once we have the full path, we don't need the pieces */
+	if (fullpath == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	/* If the requested file exists, return an error */
+	if (test_for_file(fullpath, 0400) == 1) {
+		free(fullpath);
+		return (KMF_ERR_DUPLICATE_KEYFILE);
+	}
+
+	rv = kmf_get_attr(KMF_ENCODE_FORMAT_ATTR, attrlist, numattr,
+	    &format, NULL);
+	if (rv != KMF_OK)
+		/* format is optional. */
+		rv = KMF_OK;
+
+	/* CRED is not required for OpenSSL files */
+	(void) kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr,
+	    &cred, NULL);
+
+	/* Store the private key to the keyfile */
+	out = BIO_new_file(fullpath, "wb");
+	if (out == NULL) {
+		SET_ERROR(kmfh, ERR_get_error());
+		rv = KMF_ERR_OPEN_FILE;
+		goto end;
+	}
+
+	if (prikey != NULL && prikey->keyp != NULL) {
+		if (prikey->keyalg == KMF_RSA ||
+		    prikey->keyalg == KMF_DSA) {
+			pkey = (EVP_PKEY *)prikey->keyp;
+
+			rv = ssl_write_key(kmfh, format,
+			    out, &cred, pkey, TRUE);
+
+			if (rv == KMF_OK && prikey->keylabel == NULL) {
+				prikey->keylabel = strdup(fullpath);
+				if (prikey->keylabel == NULL)
+					rv = KMF_ERR_MEMORY;
+			}
+		}
+	} else if (pubkey != NULL && pubkey->keyp != NULL) {
+		if (pubkey->keyalg == KMF_RSA ||
+		    pubkey->keyalg == KMF_DSA) {
+			pkey = (EVP_PKEY *)pubkey->keyp;
+
+			rv = ssl_write_key(kmfh, format,
+			    out, &cred, pkey, FALSE);
+
+			if (rv == KMF_OK && pubkey->keylabel == NULL) {
+				pubkey->keylabel = strdup(fullpath);
+				if (pubkey->keylabel == NULL)
+					rv = KMF_ERR_MEMORY;
+			}
+		}
+	} else if (rawkey != NULL) {
+		if (rawkey->keytype == KMF_RSA) {
+			pkey = ImportRawRSAKey(&rawkey->rawdata.rsa);
+		} else if (rawkey->keytype == KMF_DSA) {
+			pkey = ImportRawDSAKey(&rawkey->rawdata.dsa);
+		} else {
+			rv = KMF_ERR_BAD_PARAMETER;
+		}
+		if (pkey != NULL) {
+			KMF_KEY_CLASS kclass = KMF_ASYM_PRI;
+
+			rv = kmf_get_attr(KMF_KEYCLASS_ATTR, attrlist, numattr,
+			    (void *)&kclass, NULL);
+			if (rv != KMF_OK)
+				rv = KMF_OK;
+			rv = ssl_write_key(kmfh, format, out,
+			    &cred, pkey, (kclass == KMF_ASYM_PRI));
+			EVP_PKEY_free(pkey);
+		}
+	}
+
+end:
+
+	if (out)
+		(void) BIO_free(out);
+
+
+	if (rv == KMF_OK)
+		(void) chmod(fullpath, 0400);
+
+	free(fullpath);
+	return (rv);
+}
+
+KMF_RETURN
+OpenSSL_ImportCRL(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
+{
+	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;
+	KMF_ENCODE_FORMAT outformat;
+	boolean_t crlcheck = FALSE;
+	char *certfile, *dirpath, *crlfile, *incrl, *outcrl, *outcrlfile;
+
+	if (numattr == 0 || attrlist == NULL) {
+		return (KMF_ERR_BAD_PARAMETER);
+	}
+
+	/* CRL check is optional */
+	(void) kmf_get_attr(KMF_CRL_CHECK_ATTR, attrlist, numattr,
+	    &crlcheck, NULL);
+
+	certfile = kmf_get_attr_ptr(KMF_CERT_FILENAME_ATTR, attrlist, numattr);
+	if (crlcheck == B_TRUE && certfile == NULL) {
+		return (KMF_ERR_BAD_CERTFILE);
+	}
+
+	dirpath = kmf_get_attr_ptr(KMF_DIRPATH_ATTR, attrlist, numattr);
+	incrl = kmf_get_attr_ptr(KMF_CRL_FILENAME_ATTR, attrlist, numattr);
+	outcrl = kmf_get_attr_ptr(KMF_CRL_OUTFILE_ATTR, attrlist, numattr);
+
+	crlfile = get_fullpath(dirpath, incrl);
+
+	if (crlfile == NULL)
+		return (KMF_ERR_BAD_CRLFILE);
+
+	outcrlfile = get_fullpath(dirpath, outcrl);
+	if (outcrlfile == NULL)
+		return (KMF_ERR_BAD_CRLFILE);
+
+	if (isdir(outcrlfile)) {
+		free(outcrlfile);
+		return (KMF_ERR_BAD_CRLFILE);
+	}
+
+	ret = kmf_is_crl_file(handle, crlfile, &format);
+	if (ret != KMF_OK) {
+		free(outcrlfile);
+		return (ret);
+	}
+
+	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) {
+		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 (crlcheck == B_FALSE)
+		goto output;
+
+	ret = kmf_is_cert_file(handle, certfile, &format);
+	if (ret != KMF_OK)
+		goto end;
+
+	/* Read in the CA cert file and convert to X509 */
+	if (BIO_read_filename(in, 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 == NULL) {
+		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:
+	ret = kmf_get_attr(KMF_ENCODE_FORMAT_ATTR, attrlist, numattr,
+	    &outformat, NULL);
+	if (ret != KMF_OK) {
+		ret = KMF_OK;
+		outformat = KMF_FORMAT_PEM;
+	}
+
+	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, int numattr, KMF_ATTRIBUTE *attrlist)
+{
+	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;
+	char **crldata;
+	char *crlfilename, *dirpath;
+
+	if (numattr == 0 || attrlist == NULL) {
+		return (KMF_ERR_BAD_PARAMETER);
+	}
+	crlfilename = kmf_get_attr_ptr(KMF_CRL_FILENAME_ATTR,
+	    attrlist, numattr);
+	if (crlfilename == NULL)
+		return (KMF_ERR_BAD_CRLFILE);
+
+	crldata = (char **)kmf_get_attr_ptr(KMF_CRL_DATA_ATTR,
+	    attrlist, numattr);
+
+	if (crldata == NULL)
+		return (KMF_ERR_BAD_PARAMETER);
+
+	dirpath = kmf_get_attr_ptr(KMF_DIRPATH_ATTR, attrlist, numattr);
+
+	crlfile = get_fullpath(dirpath, crlfilename);
+
+	if (crlfile == NULL)
+		return (KMF_ERR_BAD_CRLFILE);
+
+	if (isdir(crlfile)) {
+		free(crlfile);
+		return (KMF_ERR_BAD_CRLFILE);
+	}
+
+	ret = kmf_is_crl_file(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, int numattr, KMF_ATTRIBUTE *attrlist)
+{
+	KMF_RETURN ret = KMF_OK;
+	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
+	KMF_ENCODE_FORMAT format;
+	char *crlfile = NULL;
+	BIO *in = NULL;
+	char *crlfilename, *dirpath;
+
+	if (numattr == 0 || attrlist == NULL) {
+		return (KMF_ERR_BAD_PARAMETER);
+	}
+
+	crlfilename = kmf_get_attr_ptr(KMF_CRL_FILENAME_ATTR,
+	    attrlist, numattr);
+
+	if (crlfilename == NULL)
+		return (KMF_ERR_BAD_CRLFILE);
+
+	dirpath = kmf_get_attr_ptr(KMF_DIRPATH_ATTR, attrlist, numattr);
+
+	crlfile = get_fullpath(dirpath, crlfilename);
+
+	if (crlfile == NULL)
+		return (KMF_ERR_BAD_CRLFILE);
+
+	if (isdir(crlfile)) {
+		ret = KMF_ERR_BAD_CRLFILE;
+		goto end;
+	}
+
+	ret = kmf_is_crl_file(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, int numattr, KMF_ATTRIBUTE *attrlist)
+{
+	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;
+	char *crlfilename, *crlfile, *dirpath, *certfile;
+
+	if (numattr == 0 || attrlist == NULL) {
+		return (KMF_ERR_BAD_PARAMETER);
+	}
+
+	crlfilename = kmf_get_attr_ptr(KMF_CRL_FILENAME_ATTR,
+	    attrlist, numattr);
+
+	if (crlfilename == NULL)
+		return (KMF_ERR_BAD_CRLFILE);
+
+	certfile = kmf_get_attr_ptr(KMF_CERT_FILENAME_ATTR, attrlist, numattr);
+	if (certfile == NULL)
+		return (KMF_ERR_BAD_CRLFILE);
+
+	dirpath = kmf_get_attr_ptr(KMF_DIRPATH_ATTR, attrlist, numattr);
+
+	crlfile = get_fullpath(dirpath, crlfilename);
+
+	if (crlfile == NULL)
+		return (KMF_ERR_BAD_CRLFILE);
+
+	if (isdir(crlfile)) {
+		ret = KMF_ERR_BAD_CRLFILE;
+		goto end;
+	}
+
+	ret = kmf_is_crl_file(handle, crlfile, &format);
+	if (ret != KMF_OK)
+		goto end;
+
+	/* Read the CRL file and load it into a X509_CRL structure */
+	in = BIO_new_file(crlfilename, "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_is_cert_file(handle, certfile, &format);
+	if (ret != KMF_OK)
+		goto end;
+
+	in = BIO_new_file(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++) {
+		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_VerifyCRLFile(KMF_HANDLE_T handle, char *crlname, KMF_DATA *tacert)
+{
+	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 (handle == NULL || crlname == NULL || tacert == NULL) {
+		return (KMF_ERR_BAD_PARAMETER);
+	}
+
+	ret = kmf_get_file_format(crlname, &crl_format);
+	if (ret != KMF_OK)
+		return (ret);
+
+	bcrl = BIO_new_file(crlname, "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 = tacert->Data;
+	len = 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 == NULL) {
+		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, char *crlname)
+{
+	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 (handle == NULL || crlname == NULL) {
+		return (KMF_ERR_BAD_PARAMETER);
+	}
+
+	ret = kmf_is_crl_file(handle, crlname, &crl_format);
+	if (ret != KMF_OK)
+		return (ret);
+
+	bcrl = BIO_new_file(crlname, "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);
+}
