view usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c @ 5051:cbbb7c8b40a9

PSARC 2007/426 KMFAPI Interface Taxonomy Change PSARC 2007/465 pktool symmetric key enhancements 6546405 KMF Interfaces need to be extensible 6547894 pktool should be more detailed 6590232 pktool should import and export generic keys
author wyllys
date Fri, 14 Sep 2007 12:13:39 -0700
parents d8be2f0444ab
children 98f4eb09776e
line wrap: on
line source

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * NSS keystore wrapper
 *
 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <synch.h>

#include <kmfapiP.h>
#include <ber_der.h>
/* NSS related headers */

#include <mps/nss.h>
#include <mps/cert.h>
#include <mps/certdb.h>
#include <mps/secoid.h>
#include <mps/secder.h>
#include <mps/secerr.h>
#include <mps/cryptohi.h>
#include <mps/keyhi.h>
#include <mps/keythi.h>
#include <mps/pk11func.h>
#include <mps/pk11pqg.h>
#include <mps/pkcs12.h>
#include <mps/p12plcy.h>
#include <mps/prerror.h>

#define	NSS_OK		0

mutex_t init_lock = DEFAULTMUTEX;
static int nss_initialized = 0;

KMF_RETURN
NSS_ConfigureKeystore(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);

KMF_RETURN
NSS_FindCert(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);

void
NSS_FreeKMFCert(KMF_HANDLE_T, KMF_X509_DER_CERT *);

KMF_RETURN
NSS_StoreCert(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);

KMF_RETURN
NSS_ImportCert(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);

KMF_RETURN
NSS_DeleteCert(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);

KMF_RETURN
NSS_CreateKeypair(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);

KMF_RETURN
NSS_StoreKey(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);

KMF_RETURN
NSS_EncodePubKeyData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_DATA *);

KMF_RETURN
NSS_SignData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *,
	KMF_DATA *, KMF_DATA *);

KMF_RETURN
NSS_ImportCRL(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);

KMF_RETURN
NSS_DeleteCRL(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);

KMF_RETURN
NSS_FindCRL(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);

KMF_RETURN
NSS_FindKey(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);

KMF_RETURN
NSS_FindCertInCRL(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);

KMF_RETURN
NSS_GetErrorString(KMF_HANDLE_T, char **);

KMF_RETURN
NSS_DeleteKey(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);

KMF_RETURN
NSS_FindPrikeyByCert(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);

KMF_RETURN
NSS_DecryptData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *,
	KMF_DATA *, KMF_DATA *);

KMF_RETURN
NSS_ExportPK12(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);

KMF_RETURN
NSS_CreateSymKey(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);

KMF_RETURN
NSS_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_SYM_KEY *);

KMF_RETURN
NSS_SetTokenPin(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);

static
KMF_PLUGIN_FUNCLIST nss_plugin_table =
{
	1,				/* Version */
	NSS_ConfigureKeystore,
	NSS_FindCert,
	NSS_FreeKMFCert,
	NSS_StoreCert,
	NSS_ImportCert,
	NSS_ImportCRL,
	NSS_DeleteCert,
	NSS_DeleteCRL,
	NSS_CreateKeypair,
	NSS_FindKey,
	NSS_EncodePubKeyData,
	NSS_SignData,
	NSS_DeleteKey,
	NULL    /* ListCRL */,
	NSS_FindCRL,
	NSS_FindCertInCRL,
	NSS_GetErrorString,
	NSS_FindPrikeyByCert,
	NSS_DecryptData,
	NSS_ExportPK12,
	NSS_CreateSymKey,
	NSS_GetSymKeyValue,
	NSS_SetTokenPin,
	NULL, /* VerifyData */
	NSS_StoreKey,
	NULL /* Finalize */
};

/* additions for importing and exporting PKCS 12 files */
typedef struct p12uContextStr {
	char		*filename;	/* name of file */
	PRFileDesc	*file;		/* pointer to file */
	PRBool		error;		/* error occurred? */
	int		errorValue;	/* which error occurred? */
} p12uContext;

#define	SET_ERROR(h, c) h->lasterr.kstype = KMF_KEYSTORE_NSS; \
	h->lasterr.errcode = c;

KMF_PLUGIN_FUNCLIST *
KMF_Plugin_Initialize()
{
	SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1);
	SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1);
	SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
	SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1);
	SEC_PKCS12EnableCipher(PKCS12_DES_56, 1);
	SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1);
	SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1);

	return (&nss_plugin_table);
}

static char *
/*ARGSUSED*/
nss_getpassword(PK11SlotInfo *slot, PRBool retry, void *arg)
{
	if (retry)
		return (NULL);
	if (arg != NULL)
		return ((char *)strdup(arg));
	else
		return (NULL);
}

static KMF_RETURN
nss_authenticate(KMF_HANDLE_T handle,
	PK11SlotInfo *nss_slot, KMF_CREDENTIAL *cred)
{

	SECStatus nssrv = SECSuccess;
	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;

	/* If a password was given, try to login to the slot */
	if (cred == NULL || cred->cred == NULL || cred->credlen == 0 ||
	    nss_slot == NULL) {
		return (KMF_ERR_BAD_PARAMETER);
	}

	if (PK11_IsLoggedIn(nss_slot, NULL)) {
		return (KMF_OK);
	}

	PK11_SetPasswordFunc(nss_getpassword);
	nssrv = PK11_Authenticate(nss_slot, PR_TRUE, (void *)cred->cred);

	if (nssrv != SECSuccess) {
		SET_ERROR(kmfh, nssrv);
		PK11_FreeSlot(nss_slot);
		return (KMF_ERR_AUTH_FAILED);
	}

	return (KMF_OK);
}

static SECStatus
Init_NSS_DBs(const char *configdir,
	const char *certPrefix,
	const char *keyPrefix,
	const char *secmodName)
{
	SECStatus rv = NSS_OK;

	(void) mutex_lock(&init_lock);

	/* If another thread already did it, return OK. */
	if (nss_initialized) {
		(void) mutex_unlock(&init_lock);
		return (SECSuccess);
	}

	rv = NSS_Initialize((configdir && strlen(configdir)) ?
	    configdir : "./", certPrefix, keyPrefix,
	    secmodName ? secmodName : "secmod.db", NSS_INIT_COOPERATE);
	if (rv != SECSuccess) {
		goto end;
	}

	nss_initialized++;
end:
	(void) mutex_unlock(&init_lock);
	return (rv);
}

/*
 * When it is called the first time, it will intialize NSS.  Once the NSS
 * is initialized, this function returns KMF_KEYSTORE_ALREADY_INITIALIZED
 * if it is called again.
 */
KMF_RETURN
NSS_ConfigureKeystore(KMF_HANDLE_T handle,
	int numattr, KMF_ATTRIBUTE *attrlist)
{
	KMF_RETURN rv = KMF_OK;
	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
	char    *configdir;
	char    *certPrefix;
	char    *keyPrefix;
	char    *secModName;

	configdir = kmf_get_attr_ptr(KMF_DIRPATH_ATTR, attrlist, numattr);
	certPrefix = kmf_get_attr_ptr(KMF_CERTPREFIX_ATTR, attrlist, numattr);
	keyPrefix = kmf_get_attr_ptr(KMF_KEYPREFIX_ATTR, attrlist, numattr);
	secModName = kmf_get_attr_ptr(KMF_SECMODNAME_ATTR, attrlist, numattr);

	(void) mutex_lock(&init_lock);
	if (nss_initialized == 0) {
		SECStatus err;

		(void) mutex_unlock(&init_lock);
		err = Init_NSS_DBs(configdir, certPrefix,
		    keyPrefix, secModName);
		if (err != SECSuccess) {
			SET_ERROR(kmfh, err);
			return (KMF_ERR_INTERNAL);
		}
	} else {
		rv = KMF_KEYSTORE_ALREADY_INITIALIZED;
		(void) mutex_unlock(&init_lock);
	}

	return (rv);
}

/*
 * This function sets up the slot to be used for other operations.
 * This function is basically called by every NSS SPI function.
 * For those functions that can only be performed in the internal slot, the
 * boolean "internal_slot_only" argument needs to be TRUE.
 * A slot pointer will be returned when this function is executed successfully.
 */
KMF_RETURN
do_nss_init(void *handle, int numattr,
	KMF_ATTRIBUTE *attrlist,
	boolean_t internal_slot_only,
	PK11SlotInfo **nss_slot)
{
	KMF_RETURN rv = KMF_OK;
	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
	char *slotlabel = NULL;

	if (!nss_initialized)
		return (KMF_ERR_PLUGIN_INIT);

	slotlabel = kmf_get_attr_ptr(KMF_TOKEN_LABEL_ATTR, attrlist, numattr);
	/*
	 * NSS Is already initialized, but we need to find
	 * the right slot.
	 */
	if (slotlabel == NULL ||
	    strcmp(slotlabel, "internal") == 0) {
		*nss_slot = PK11_GetInternalKeySlot();
	} else if (internal_slot_only == TRUE)  {
		rv = KMF_ERR_SLOTNAME;
		goto end;
	} else {
		*nss_slot = PK11_FindSlotByName(slotlabel);
	}

	if (*nss_slot == NULL) {
		SET_ERROR(kmfh, PORT_GetError());
		rv = KMF_ERR_SLOTNAME;
		goto end;
	}

	/*
	 * If the token was not yet initialized, return an error.
	 */
	if (PK11_NeedUserInit(*nss_slot)) {
		rv = KMF_ERR_UNINITIALIZED_TOKEN;
	}

end:
	return (rv);
}

static KMF_RETURN
nss2kmf_cert(CERTCertificate *nss_cert, KMF_X509_DER_CERT *kmf_cert)
{
	kmf_cert->kmf_private.keystore_type = KMF_KEYSTORE_NSS;
	kmf_cert->kmf_private.flags = KMF_FLAG_CERT_VALID;

	kmf_cert->certificate.Length = nss_cert->derCert.len;

	if ((kmf_cert->certificate.Data = malloc(nss_cert->derCert.len)) ==
	    NULL) {
		kmf_cert->certificate.Length = 0;
		return (KMF_ERR_MEMORY);
	}
	(void) memcpy(kmf_cert->certificate.Data, nss_cert->derCert.data,
	    nss_cert->derCert.len);
	if (nss_cert->nickname != NULL)
		kmf_cert->kmf_private.label =
		    (char *)strdup(nss_cert->nickname);
	return (KMF_OK);
}

static KMF_RETURN
nss_getcert_by_label(KMF_HANDLE *kmfh,
	char *name, KMF_X509_DER_CERT *kmf_cert,
	uint32_t *num_certs, KMF_CERT_VALIDITY find_criteria)
{
	KMF_RETURN rv = KMF_OK;
	CERTCertificate *nss_cert;
	SECCertTimeValidity validity;

	nss_cert = PK11_FindCertFromNickname(name, NULL);
	if (nss_cert == NULL) {
		*num_certs = 0;
		SET_ERROR(kmfh, PORT_GetError());
		*num_certs = 0;
		return (KMF_ERR_CERT_NOT_FOUND);
	} else {
		*num_certs = 1;
	}

	switch (find_criteria) {
	case KMF_ALL_CERTS:
		break;
	case KMF_NONEXPIRED_CERTS:
		validity = CERT_CheckCertValidTimes(nss_cert, PR_Now(),
		    PR_FALSE);
		if (validity != secCertTimeValid) {
			/* this is an invalid cert, reject it */
			*num_certs = 0;
			CERT_DestroyCertificate(nss_cert);
			return (KMF_OK);
		}
		break;
	case KMF_EXPIRED_CERTS:
		validity = CERT_CheckCertValidTimes(nss_cert, PR_Now(),
		    PR_FALSE);
		if (validity == secCertTimeValid) {
			/* this is a valid cert, reject it in this case. */
			*num_certs = 0;
			CERT_DestroyCertificate(nss_cert);
			return (KMF_OK);
		}
		break;
	default:
		return (KMF_ERR_BAD_PARAMETER);
	}

	if (kmf_cert != NULL)
		rv = nss2kmf_cert(nss_cert, kmf_cert);

	/* We copied the data we need, so cleanup the internal record */
	CERT_DestroyCertificate(nss_cert);

	if (rv != KMF_OK)
		*num_certs = 0;

	return (rv);
}

static KMF_RETURN
nss_find_matching_certs(PK11SlotInfo *slot,
	char *issuer, char *subject, KMF_BIGINT *serial,
	CERTCertList **certlist, KMF_CERT_VALIDITY find_criteria)
{
	KMF_RETURN rv = KMF_OK;
	SECStatus ret;
	CERTCertList *list;
	CERTCertListNode *node;
	KMF_X509_NAME issuerDN, subjectDN;
	boolean_t findIssuer = FALSE;
	boolean_t findSubject = FALSE;
	boolean_t findSerial = FALSE;

	if (issuer != NULL && strlen(issuer)) {
		rv = kmf_dn_parser(issuer,  &issuerDN);
		if (rv != KMF_OK)
			return (rv);
		findIssuer = TRUE;
	}
	if (subject != NULL && strlen(subject)) {
		rv = kmf_dn_parser(subject, &subjectDN);
		if (rv != KMF_OK)
			return (rv);
		findSubject = TRUE;
	}
	if (serial != 0 && serial->val != NULL && serial->len > 0)
		findSerial = TRUE;

	list = PK11_ListCertsInSlot(slot);
	if (list) {
		node = CERT_LIST_HEAD(list);
		while (!CERT_LIST_END(node, list)) {
			KMF_X509_NAME cmpDN;
			KMF_DATA der;
			boolean_t match;
			CERTCertListNode *freenode;

			if (findIssuer) {
				der.Data = node->cert->derIssuer.data;
				der.Length = node->cert->derIssuer.len;
				rv = DerDecodeName(&der, &cmpDN);
				if (rv == KMF_OK) {
					match = !KMF_CompareRDNs(&issuerDN,
					    &cmpDN);
					kmf_free_dn(&cmpDN);
					if (!match)
						goto delete_and_cont;
				} else {
					goto delete_and_cont;
				}
			}
			if (findSubject) {
				der.Data = node->cert->derSubject.data;
				der.Length = node->cert->derSubject.len;
				rv = DerDecodeName(&der, &cmpDN);
				if (rv == KMF_OK) {
					match = !KMF_CompareRDNs(&subjectDN,
					    &cmpDN);
					kmf_free_dn(&cmpDN);
					if (!match)
						goto delete_and_cont;
				} else {
					goto delete_and_cont;
				}
			}
			if (findSerial) {
				SECItem *sernum;

				sernum = &node->cert->serialNumber;

				if (serial->len != sernum->len)
					goto delete_and_cont;

				if (memcmp(sernum->data, serial->val,
				    serial->len))
					goto delete_and_cont;
			}

			/* select the certs using find criteria */
			switch (find_criteria) {
			case KMF_ALL_CERTS:
				break;
			case KMF_NONEXPIRED_CERTS:
				ret = CERT_CertTimesValid(node->cert);
				if (ret == SECFailure) {
					/* this is an invalid cert */
					goto skip;
				}
				break;

			case KMF_EXPIRED_CERTS:
				ret = CERT_CertTimesValid(node->cert);
				if (ret != SECFailure) {
					/* this is a valid cert */
					goto skip;
				}
				break;
			}
skip:
			node = CERT_LIST_NEXT(node);
			continue;
delete_and_cont:
			freenode = node;
			node = CERT_LIST_NEXT(node);
			CERT_RemoveCertListNode(freenode);
		}
	}

	if (rv == KMF_OK && certlist != NULL) {
		*certlist = list;
	} else {
		CERT_DestroyCertList(list);
	}
	return (rv);
}

static KMF_RETURN
convertCertList(void *kmfhandle,
	CERTCertList *nsscerts, KMF_X509_DER_CERT *kmfcerts,
	uint32_t *numcerts)
{
	KMF_RETURN rv = KMF_OK;
	CERTCertListNode *node;
	uint32_t maxcerts = *numcerts;

	maxcerts = *numcerts;
	if (maxcerts == 0)
		maxcerts = 0xFFFFFFFF;

	*numcerts = 0;

	/*
	 * Don't copy more certs than the caller wanted.
	 */
	for (node = CERT_LIST_HEAD(nsscerts);
	    !CERT_LIST_END(node, nsscerts) && rv == KMF_OK &&
	    (*numcerts) < maxcerts;
	    node = CERT_LIST_NEXT(node), (*numcerts)++) {
		if (kmfcerts != NULL)
			rv = nss2kmf_cert(node->cert, &kmfcerts[*numcerts]);
	}

	/*
	 * If we failed, delete any certs allocated so far.
	 */
	if (rv != KMF_OK) {
		int i;
		for (i = 0; i < *numcerts; i++)
			kmf_free_kmf_cert(kmfhandle, &kmfcerts[i]);

		*numcerts = 0;
	}
	return (rv);
}

KMF_RETURN
NSS_FindCert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
	KMF_RETURN rv = KMF_OK;
	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
	PK11SlotInfo *nss_slot = NULL;
	CERTCertList *certlist = NULL;
	uint32_t maxcerts;
	uint32_t *num_certs;
	KMF_X509_DER_CERT *kmfcerts = NULL;
	char *certlabel = NULL;
	char *issuer = NULL;
	char *subject = NULL;
	KMF_BIGINT *serial = NULL;
	KMF_CERT_VALIDITY  validity;

	if (handle == NULL || attrlist == NULL || numattr == 0) {
		return (KMF_ERR_BAD_PARAMETER);
	}
	rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot);
	if (rv != KMF_OK)
		return (rv);

	num_certs = kmf_get_attr_ptr(KMF_COUNT_ATTR, attrlist, numattr);
	if (num_certs == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	maxcerts = *num_certs;
	if (maxcerts == 0)
		maxcerts = 0xFFFFFFFF;
	*num_certs = 0;

	/* Get the optional returned certificate list  */
	kmfcerts = kmf_get_attr_ptr(KMF_X509_DER_CERT_ATTR, attrlist, numattr);

	/* Get optional search criteria attributes */
	certlabel = kmf_get_attr_ptr(KMF_CERT_LABEL_ATTR, attrlist, numattr);
	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 (certlabel != NULL) {
		/* This will only find 1 certificate */
		rv = nss_getcert_by_label(kmfh,	certlabel, kmfcerts, num_certs,
		    validity);
	} else {
		/*
		 * Build a list of matching certs.
		 */
		rv = nss_find_matching_certs(nss_slot, issuer, subject, serial,
		    &certlist, validity);

		/*
		 * If the caller supplied a pointer to storage for
		 * a list of certs, convert up to 'maxcerts' of the
		 * matching certs.
		 */
		if (rv == KMF_OK && certlist != NULL) {
			rv = convertCertList(handle, certlist, kmfcerts,
			    &maxcerts);
			CERT_DestroyCertList(certlist);
			if (rv == KMF_OK)
				*num_certs = maxcerts;
		}
	}

	if (nss_slot != NULL) {
		PK11_FreeSlot(nss_slot);
	}

	if (rv == KMF_OK && *num_certs == 0)
		rv = KMF_ERR_CERT_NOT_FOUND;

	return (rv);
}

void
/*ARGSUSED*/
NSS_FreeKMFCert(KMF_HANDLE_T handle,
	KMF_X509_DER_CERT *kmf_cert)
{
	if (kmf_cert != NULL) {
		if (kmf_cert->certificate.Data != NULL) {
			free(kmf_cert->certificate.Data);
			kmf_cert->certificate.Data = NULL;
			kmf_cert->certificate.Length = 0;
		}
		if (kmf_cert->kmf_private.label != NULL) {
			free(kmf_cert->kmf_private.label);
			kmf_cert->kmf_private.label = NULL;
		}
	}
}


KMF_RETURN
NSS_DeleteCert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
	KMF_RETURN rv = KMF_OK;
	int nssrv;
	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
	CERTCertificate *cert = NULL;
	PK11SlotInfo *nss_slot = NULL;
	char *certlabel = NULL;
	char *issuer = NULL;
	char *subject = NULL;
	KMF_BIGINT *serial = NULL;
	KMF_CERT_VALIDITY  validity;

	if (handle == NULL || attrlist == NULL || numattr == 0) {
		return (KMF_ERR_BAD_PARAMETER);
	}
	rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot);
	if (rv != KMF_OK)
		return (rv);

	/* Get the search criteria attributes.  They are all optional. */
	certlabel = kmf_get_attr_ptr(KMF_CERT_LABEL_ATTR, attrlist, numattr);
	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;
	}

	/* Start finding the matched certificates and delete them. */
	if (certlabel != NULL) {
		cert = PK11_FindCertFromNickname(certlabel, NULL);
		if (cert == NULL) {
			return (KMF_ERR_CERT_NOT_FOUND);
		}

		switch (validity) {
		case KMF_ALL_CERTS:
			break;
		case KMF_NONEXPIRED_CERTS:
			nssrv = CERT_CertTimesValid(cert);
			if (nssrv == SECFailure) {
				/* this is an invalid cert - skip it */
				goto out;
			}
			break;
		case KMF_EXPIRED_CERTS:
			nssrv = CERT_CertTimesValid(cert);
			if (nssrv != SECFailure) {
				/* this is a valid cert - skip it */
				goto out;
			}
			break;
		}
		/* delete it from database */
		nssrv = SEC_DeletePermCertificate(cert);
		if (nssrv) {
			SET_ERROR(kmfh, nssrv);
			rv = KMF_ERR_INTERNAL;
		}
	} else {
		CERTCertListNode *node;
		CERTCertList *certlist = NULL;

		rv = nss_find_matching_certs(nss_slot, issuer, subject, serial,
		    &certlist, validity);

		for (node = CERT_LIST_HEAD(certlist);
		    !CERT_LIST_END(node, certlist) && rv == KMF_OK;
		    node = CERT_LIST_NEXT(node)) {

			nssrv = SEC_DeletePermCertificate(node->cert);
			if (nssrv) {
				SET_ERROR(kmfh, nssrv);
				rv = KMF_ERR_INTERNAL;
			}
		}

		if (rv == KMF_OK && certlist != NULL) {
			CERT_DestroyCertList(certlist);
		} else if (rv == KMF_OK && certlist == NULL) {
			rv = KMF_ERR_CERT_NOT_FOUND;
		}
	}
out:
	if (nss_slot != NULL) {
		PK11_FreeSlot(nss_slot);
	}

	if (cert != NULL) {
		CERT_DestroyCertificate(cert);
	}

	return (rv);
}

static void
InitRandom(char *filename)
{
	char buf[2048];
	int fd;
	PRInt32 count;

	fd = open(filename, O_RDONLY);
	if (!fd)
		return;

	count = read(fd, buf, sizeof (buf));
	if (count > 0) {
		PK11_RandomUpdate(buf, count);
	}

	(void) close(fd);
}

KMF_RETURN
NSS_CreateKeypair(KMF_HANDLE_T handle,
	int numattr, KMF_ATTRIBUTE *attrlist)
{
	KMF_RETURN rv = KMF_OK;
	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
	PK11RSAGenParams rsaparams;
	void *nssparams;
	CK_MECHANISM_TYPE mechanism;
	ulong_t publicExponent = 0x010001;
	PK11SlotInfo *nss_slot = NULL;
	SECKEYPrivateKey *NSSprivkey = NULL;
	SECKEYPublicKey *NSSpubkey = NULL;
	PQGParams *pqgParams = NULL;
	KMF_CREDENTIAL cred;
	boolean_t storekey = TRUE;
	uint32_t keylen = 1024, len;
	uint32_t keylen_size = sizeof (uint32_t);
	KMF_KEY_ALG keytype = KMF_RSA;
	KMF_KEY_HANDLE *pubkey = NULL;
	KMF_KEY_HANDLE *privkey = NULL;
	char *keylabel = NULL;

	if (handle == NULL || attrlist == NULL || numattr == 0) {
		return (KMF_ERR_BAD_PARAMETER);
	}
	rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot);
	if (rv != KMF_OK) {
		return (rv);
	}

	rv = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr,
	    (void *)&cred, NULL);
	if (rv != KMF_OK)
		return (rv);

	rv = nss_authenticate(handle, nss_slot, &cred);
	if (rv != KMF_OK) {
		return (rv);
	}

	/* "storekey" is optional. Default is TRUE */
	(void) kmf_get_attr(KMF_STOREKEY_BOOL_ATTR, attrlist, numattr,
	    &storekey, NULL);

	/* keytype is optional.  KMF_RSA is default */
	(void) kmf_get_attr(KMF_KEYALG_ATTR, attrlist, numattr,
	    (void *)&keytype, NULL);

	rv = kmf_get_attr(KMF_KEYLENGTH_ATTR, attrlist, numattr,
	    &keylen, &keylen_size);
	if (rv == KMF_ERR_ATTR_NOT_FOUND)
		/* Default keylen = 1024 */
		rv = KMF_OK;
	else if (rv != KMF_OK)
		return (KMF_ERR_BAD_PARAMETER);

	pubkey = kmf_get_attr_ptr(KMF_PUBKEY_HANDLE_ATTR, attrlist, numattr);
	privkey = kmf_get_attr_ptr(KMF_PRIVKEY_HANDLE_ATTR, attrlist, numattr);
	if (pubkey == NULL || privkey == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	(void) memset(pubkey, 0, sizeof (KMF_KEY_HANDLE));
	(void) memset(privkey, 0, sizeof (KMF_KEY_HANDLE));

	rv = kmf_get_attr(KMF_KEYLABEL_ATTR, attrlist, numattr,	NULL, &len);
	if (rv == KMF_OK && len > 0) {
		keylabel = malloc(len + 1);
		if (keylabel == NULL)
			return (KMF_ERR_MEMORY);
		/* Now fill in the label value */
		(void) memset(keylabel, 0, len + 1);
		rv = kmf_get_attr(KMF_KEYLABEL_ATTR, attrlist, numattr,
		    keylabel, NULL);
		if (rv != KMF_OK) {
			free(keylabel);
			goto cleanup;
		}
	}

	/* Get some random bits */
	InitRandom("/dev/urandom");
	if (keytype == KMF_RSA) {
		KMF_BIGINT rsaexp;

		rsaparams.keySizeInBits = keylen;
		/*
		 * NSS only allows for a 4 byte exponent.
		 * Ignore the exponent parameter if it is too big.
		 */
		if ((rv = kmf_get_attr(KMF_RSAEXP_ATTR, attrlist, numattr,
		    &rsaexp, NULL)) == KMF_OK) {
			if (rsaexp.len > 0 &&
			    rsaexp.len <= sizeof (publicExponent) &&
			    rsaexp.val != NULL) {
				(void) memcpy(&publicExponent, rsaexp.val,
				    rsaexp.len);
			}
		}
		rsaparams.pe = publicExponent;
		mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
		nssparams = &rsaparams;
	} else if (keytype == KMF_DSA) {
		PQGVerify *pqgVerify = NULL;
		int ks;
		SECStatus	nssrv, passed;

		mechanism = CKM_DSA_KEY_PAIR_GEN;

		ks = PQG_PBITS_TO_INDEX(keylen);
		nssrv = PK11_PQG_ParamGen(ks, &pqgParams, &pqgVerify);
		if (nssrv != SECSuccess) {
			SET_ERROR(kmfh, rv);
			PK11_PQG_DestroyVerify(pqgVerify);
			rv = KMF_ERR_KEYGEN_FAILED;
			goto cleanup;
		}

		nssrv = PK11_PQG_VerifyParams(pqgParams, pqgVerify, &passed);
		if (nssrv != SECSuccess || passed != SECSuccess) {
			SET_ERROR(kmfh, rv);
			rv = KMF_ERR_KEYGEN_FAILED;
		}

		PK11_PQG_DestroyVerify(pqgVerify);

		if (rv != KMF_OK) {
			SET_ERROR(kmfh, PORT_GetError());
			goto cleanup;
		}

		nssparams = pqgParams;
	} else {
		rv = KMF_ERR_BAD_PARAMETER;
		goto cleanup;
	}

	NSSprivkey = PK11_GenerateKeyPair(nss_slot, mechanism, nssparams,
	    &NSSpubkey,
	    storekey, /* isPermanent */
	    PR_TRUE, /* isSensitive */
	    (void *)cred.cred);

	if (NSSprivkey == NULL || NSSpubkey == NULL) {
		SET_ERROR(kmfh, PORT_GetError());
		rv = KMF_ERR_KEYGEN_FAILED;
	} else {
		if (keylabel != NULL && strlen(keylabel)) {
			(void) PK11_SetPrivateKeyNickname(NSSprivkey,
			    keylabel);
			(void) PK11_SetPublicKeyNickname(NSSpubkey, keylabel);
		}
		/* Now, convert it to a KMF_KEY object for the framework */
		privkey->kstype = KMF_KEYSTORE_NSS;
		privkey->keyalg = keytype;
		privkey->keyclass = KMF_ASYM_PRI;
		privkey->keylabel = PK11_GetPrivateKeyNickname(NSSprivkey);
		privkey->keyp = (void *)NSSprivkey;

		pubkey->kstype = KMF_KEYSTORE_NSS;
		pubkey->keyalg = keytype;
		pubkey->keyp = (void *)NSSpubkey;
		pubkey->keyclass = KMF_ASYM_PUB;
		pubkey->keylabel = PK11_GetPublicKeyNickname(NSSpubkey);

		rv = KMF_OK;
	}
cleanup:
	if (rv != KMF_OK) {
		if (NSSpubkey)
			PK11_DeleteTokenPublicKey(NSSpubkey);
		if (NSSprivkey)
			PK11_DeleteTokenPrivateKey(NSSprivkey, PR_TRUE);

		privkey->keyp = NULL;
		pubkey->keyp = NULL;
	}

	if (keylabel)
		free(keylabel);

	if (pqgParams != NULL)
		PK11_PQG_DestroyParams(pqgParams);

	if (nss_slot != NULL)
		PK11_FreeSlot(nss_slot);

	return (rv);
}

KMF_RETURN
NSS_SignData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key,
    KMF_OID *AlgOID, KMF_DATA *tobesigned,
    KMF_DATA *output)
{
	KMF_RETURN		ret = KMF_OK;
	KMF_ALGORITHM_INDEX	AlgId;
	SECOidTag		signAlgTag;
	SECKEYPrivateKey	*NSSprivkey = NULL;
	SECStatus		rv;
	SECItem			signed_data;
	KMF_HANDLE		*kmfh = (KMF_HANDLE *)handle;

	signed_data.data = 0;
	if (key == NULL || AlgOID == NULL ||
	    tobesigned == NULL || output == NULL ||
	    tobesigned->Data == NULL ||
	    output->Data == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	/* Map the OID to a NSS algorithm */
	AlgId = x509_algoid_to_algid(AlgOID);
	if (AlgId == KMF_ALGID_NONE)
		return (KMF_ERR_BAD_PARAMETER);

	NSSprivkey = (SECKEYPrivateKey *)key->keyp;

	if (AlgId == KMF_ALGID_MD5WithRSA)
		signAlgTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
	else if (AlgId == KMF_ALGID_MD2WithRSA)
		signAlgTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
	else if (AlgId == KMF_ALGID_SHA1WithRSA)
		signAlgTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
	else if (AlgId == KMF_ALGID_SHA1WithDSA)
		signAlgTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
	else
		return (KMF_ERR_BAD_PARAMETER);

	rv = SEC_SignData(&signed_data, tobesigned->Data,
	    tobesigned->Length, NSSprivkey, signAlgTag);

	if (rv != 0) {
		SET_ERROR(kmfh, rv);
		return (KMF_ERR_INTERNAL);
	}

	if (signed_data.len <= output->Length) {
		(void) memcpy(output->Data, signed_data.data, signed_data.len);
		output->Length = signed_data.len;
	} else {
		output->Length = 0;
		ret = KMF_ERR_BAD_PARAMETER;
	}
	free(signed_data.data);

	return (ret);
}

KMF_RETURN
NSS_EncodePubKeyData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *keyp,
	KMF_DATA *encoded)
{
	KMF_RETURN ret = KMF_OK;
	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
	SECItem *rvitem;
	CERTSubjectPublicKeyInfo *spki = NULL;

	if (keyp == NULL || encoded == NULL || keyp->keyp == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	spki = SECKEY_CreateSubjectPublicKeyInfo(keyp->keyp);
	if (spki == NULL) {
		SET_ERROR(kmfh, PORT_GetError());
		return (KMF_ERR_MEMORY);
	}

	rvitem = SEC_ASN1EncodeItem(NULL, NULL, spki,
	    CERT_SubjectPublicKeyInfoTemplate);
	if (rvitem != NULL) {
		encoded->Data = malloc(rvitem->len);
		if (encoded->Data == NULL) {
			ret = KMF_ERR_MEMORY;
		} else {
			(void) memcpy(encoded->Data, rvitem->data, rvitem->len);
			encoded->Length = rvitem->len;
		}
		SECITEM_FreeItem(rvitem, TRUE);
	} else {
		SET_ERROR(kmfh, PORT_GetError());
		encoded->Data = NULL;
		encoded->Length = 0;
		ret = KMF_ERR_ENCODING;
	}
	SECKEY_DestroySubjectPublicKeyInfo(spki);

	return (ret);
}

KMF_RETURN
NSS_DeleteKey(KMF_HANDLE_T handle,
	int numattr, KMF_ATTRIBUTE *attrlist)
{
	KMF_RETURN rv = KMF_OK;
	PK11SlotInfo *nss_slot = NULL;
	KMF_KEY_HANDLE *key;
	KMF_CREDENTIAL cred;
	boolean_t delete_token = B_TRUE;

	if (handle == NULL || attrlist == NULL || numattr == 0) {
		return (KMF_ERR_BAD_PARAMETER);
	}
	/*
	 * "delete_token" means to clear it from the token storage as well
	 * as from memory.
	 */
	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 *)&delete_token, NULL);
	if (rv != KMF_OK)
		/* "delete_token" is optional. Default is TRUE */
		rv = KMF_OK;

	if (delete_token) {
		SECStatus nssrv = SECSuccess;
		if (key->keyclass != KMF_ASYM_PUB &&
		    key->keyclass != KMF_ASYM_PRI &&
		    key->keyclass != KMF_SYMMETRIC)
			return (KMF_ERR_BAD_KEY_CLASS);

		rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot);
		if (rv != KMF_OK) {
			return (rv);
		}

		rv = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr,
		    (void *)&cred, NULL);
		if (rv != KMF_OK)
			return (KMF_ERR_BAD_PARAMETER);

		rv = nss_authenticate(handle, nss_slot, &cred);
		if (rv != KMF_OK) {
			return (rv);
		}

		if (key->keyclass == KMF_ASYM_PUB) {
			nssrv = PK11_DeleteTokenPublicKey(
			    (SECKEYPublicKey *)key->keyp);
		} else if (key->keyclass == KMF_ASYM_PRI) {
			nssrv = PK11_DeleteTokenPrivateKey(
			    (SECKEYPrivateKey *)key->keyp, PR_TRUE);
		} else if (key->keyclass == KMF_SYMMETRIC) {
			nssrv = PK11_DeleteTokenSymKey(
			    (PK11SymKey *) key->keyp);
			if (nssrv == SECSuccess)
				PK11_FreeSymKey((PK11SymKey *) key->keyp);
		}
		if (nssrv != SECSuccess) {
			SET_ERROR(handle, PORT_GetError());
			rv = KMF_ERR_INTERNAL;
		}
	} else {
		if (key->keyclass == KMF_ASYM_PUB) {
			SECKEY_DestroyPublicKey((SECKEYPublicKey *)key->keyp);
		} else if (key->keyclass == KMF_ASYM_PRI) {
			SECKEY_DestroyPrivateKey((SECKEYPrivateKey *)key->keyp);
		} else if (key->keyclass == KMF_SYMMETRIC) {
			PK11_FreeSymKey((PK11SymKey *) key->keyp);
		} else {
			return (KMF_ERR_BAD_KEY_CLASS);
		}
	}
	key->keyp = NULL;

	return (rv);
}

KMF_RETURN
NSS_GetErrorString(KMF_HANDLE_T handle, char **msgstr)
{
	KMF_RETURN ret = KMF_OK;
	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
	char *str;

	/* Get the error string in the default language */
	str = (char *)PR_ErrorToName((PRErrorCode)kmfh->lasterr.errcode);

	if (str != NULL) {
		*msgstr = (char *)strdup(str);
		if ((*msgstr) == NULL)
			ret = KMF_ERR_MEMORY;
	} else {
		*msgstr = NULL;
	}

	return (ret);
}

KMF_RETURN
NSS_FindPrikeyByCert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
	KMF_RETURN rv = KMF_OK;
	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
	PK11SlotInfo *nss_slot = NULL;
	KMF_CREDENTIAL cred;
	KMF_KEY_HANDLE *key = NULL;
	KMF_DATA *cert = NULL;
	CERTCertificate *nss_cert = NULL;
	SECKEYPrivateKey* privkey = NULL;

	if (handle == NULL || attrlist == NULL || numattr == 0) {
		return (KMF_ERR_BAD_PARAMETER);
	}

	rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot);
	if (rv != KMF_OK)
		return (rv);

	/* Get the credential */
	rv = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr,
	    (void *)&cred, NULL);
	if (rv != KMF_OK)
		return (KMF_ERR_BAD_PARAMETER);
	rv = nss_authenticate(handle, nss_slot, &cred);
	if (rv != KMF_OK)
		return (rv);

	/* Get the key handle */
	key = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr);
	if (key == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	/* Get the cert data and decode it */
	cert = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist, numattr);
	if (cert == NULL || cert->Data == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	nss_cert = CERT_DecodeCertFromPackage((char *)cert->Data,
	    cert->Length);
	if (nss_cert == NULL) {
		SET_ERROR(kmfh, PORT_GetError());
		return (KMF_ERR_BAD_CERT_FORMAT);
	}

	privkey = PK11_FindPrivateKeyFromCert(nss_slot, nss_cert, NULL);
	if (privkey == NULL) {
		SET_ERROR(kmfh, PORT_GetError());
		return (KMF_ERR_KEY_NOT_FOUND);
	}

	key->kstype = KMF_KEYSTORE_NSS;
	key->keyclass = KMF_ASYM_PRI;
	key->keyp = (void *)privkey;
	key->keylabel = PK11_GetPrivateKeyNickname(privkey);

	CERT_DestroyCertificate(nss_cert);

	return (KMF_OK);
}


KMF_RETURN
NSS_DecryptData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key,
	KMF_OID *AlgOID, KMF_DATA *ciphertext,
	KMF_DATA *output)
{
	KMF_RETURN		ret = KMF_OK;
	SECKEYPrivateKey	*NSSprivkey = NULL;
	SECStatus		rv;
	KMF_HANDLE		*kmfh = (KMF_HANDLE *)handle;
	unsigned int in_len = 0, out_len = 0;
	unsigned int total_decrypted = 0, modulus_len = 0;
	uint8_t *in_data, *out_data;
	int i, blocks;

	if (key == NULL || AlgOID == NULL ||
	    ciphertext == NULL || output == NULL ||
	    ciphertext->Data == NULL ||
	    output->Data == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	NSSprivkey = (SECKEYPrivateKey *)key->keyp;
	modulus_len = PK11_GetPrivateModulusLen(NSSprivkey);

	blocks = ciphertext->Length/modulus_len;
	out_data = output->Data;
	in_data = ciphertext->Data;
	out_len = modulus_len - 11;
	in_len = modulus_len;

	for (i = 0; i < blocks; i++) {
		rv = PK11_PrivDecryptPKCS1(NSSprivkey, out_data,
		    &out_len, ciphertext->Length, in_data, in_len);

		if (rv != 0) {
			SET_ERROR(kmfh, rv);
			return (KMF_ERR_INTERNAL);
		}

		out_data += out_len;
		total_decrypted += out_len;
		in_data += in_len;
	}

	output->Length = total_decrypted;

	return (ret);
}

static KMF_KEY_ALG
pk11keytype2kmf(CK_KEY_TYPE type)
{
	switch (type) {
	case CKK_RSA:
		return (KMF_RSA);
	case CKK_DSA:
		return (KMF_RSA);
	case CKK_AES:
		return (KMF_AES);
	case CKK_RC4:
		return (KMF_RC4);
	case CKK_DES:
		return (KMF_DES);
	case CKK_DES3:
		return (KMF_DES3);
	default:
		/* not supported */
		return (KMF_KEYALG_NONE);
	}
}

KMF_RETURN
NSS_FindKey(KMF_HANDLE_T handle,
	int numattr, KMF_ATTRIBUTE *attrlist)
{
	KMF_RETURN rv;
	SECKEYPrivateKeyList *prilist;
	SECKEYPrivateKeyListNode *prinode;
	SECKEYPublicKeyList *publist;
	SECKEYPublicKeyListNode *pubnode;
	PK11SlotInfo *nss_slot = NULL;
	PK11SymKey *symlist = NULL;
	int count;
	uint32_t maxkeys;
	KMF_KEY_HANDLE *keys;
	uint32_t *numkeys;
	KMF_CREDENTIAL cred;
	KMF_KEY_CLASS keyclass;
	char *findLabel;
	KMF_KEY_ALG keytype = KMF_KEYALG_NONE;

	if (handle == NULL || attrlist == NULL || numattr == 0) {
		return (KMF_ERR_BAD_PARAMETER);
	}

	numkeys = kmf_get_attr_ptr(KMF_COUNT_ATTR, attrlist, numattr);
	if (numkeys == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot);
	if (rv != KMF_OK) {
		return (rv);
	}

	rv = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr,
	    (void *)&cred, NULL);
	if (rv != KMF_OK)
		return (KMF_ERR_BAD_PARAMETER);

	rv = nss_authenticate(handle, nss_slot, &cred);
	if (rv != KMF_OK) {
		return (rv);
	}

	maxkeys = *numkeys;
	if (maxkeys == 0)
		maxkeys = 0xFFFFFFFF;
	*numkeys = 0;

	rv = kmf_get_attr(KMF_KEYCLASS_ATTR, attrlist, numattr,
	    (void *)&keyclass, NULL);
	if (rv != KMF_OK)
		return (KMF_ERR_BAD_PARAMETER);

	findLabel = kmf_get_attr_ptr(KMF_KEYLABEL_ATTR, attrlist, numattr);

	if (keyclass == KMF_ASYM_PUB) {
		publist = PK11_ListPublicKeysInSlot(nss_slot, findLabel);
		if (publist == NULL) {
			rv = KMF_ERR_KEY_NOT_FOUND;
			goto cleanup;
		}
	} else if (keyclass == KMF_ASYM_PRI) {
		prilist = PK11_ListPrivKeysInSlot(nss_slot, findLabel, NULL);
		if (prilist == NULL) {
			rv = KMF_ERR_KEY_NOT_FOUND;
			goto cleanup;
		}
	} else if (keyclass == KMF_SYMMETRIC) {
		symlist = PK11_ListFixedKeysInSlot(nss_slot, findLabel, NULL);
		if (symlist == NULL) {
			rv = KMF_ERR_KEY_NOT_FOUND;
			goto cleanup;
		}
	} else {
		rv = KMF_ERR_BAD_KEY_CLASS;
		goto cleanup;
	}

	keys = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr);
	/* it is okay to have "keys" contains NULL */

	if (keyclass == KMF_ASYM_PUB) {
		for (count = 0, pubnode = PUBKEY_LIST_HEAD(publist);
		    !PUBKEY_LIST_END(pubnode, publist) && count < maxkeys;
		    pubnode = PUBKEY_LIST_NEXT(pubnode), count++) {
			if (keys != NULL) {
				keys[count].kstype = KMF_KEYSTORE_NSS;
				keys[count].keyclass = KMF_ASYM_PUB;
				keys[count].keyp = (void *)pubnode->key;
				keys[count].keylabel =
				    PK11_GetPublicKeyNickname(pubnode->key);

				if (pubnode->key->keyType == rsaKey)
					keys[count].keyalg = KMF_RSA;
				else if (pubnode->key->keyType == dsaKey)
					keys[count].keyalg = KMF_DSA;
			}
		}
		*numkeys = count;
	} else if (keyclass == KMF_ASYM_PRI) {
		for (count = 0, prinode = PRIVKEY_LIST_HEAD(prilist);
		    !PRIVKEY_LIST_END(prinode, prilist) && count < maxkeys;
		    prinode = PRIVKEY_LIST_NEXT(prinode), count++) {
			if (keys != NULL) {
				keys[count].kstype = KMF_KEYSTORE_NSS;
				keys[count].keyclass = KMF_ASYM_PRI;
				keys[count].keyp = (void *)prinode->key;
				keys[count].keylabel =
				    PK11_GetPrivateKeyNickname(prinode->key);

				if (prinode->key->keyType == rsaKey)
					keys[count].keyalg = KMF_RSA;
				else if (prinode->key->keyType == dsaKey)
					keys[count].keyalg = KMF_DSA;
			}
		}
		*numkeys = count;
	} else if (keyclass == KMF_SYMMETRIC) {
		count = 0;
		rv = kmf_get_attr(KMF_KEYALG_ATTR, attrlist, numattr,
		    (void *)&keytype, NULL);
		if (rv != KMF_OK)
			rv = KMF_OK;
		while (symlist && count < maxkeys) {
			PK11SymKey *symkey = symlist;
			CK_KEY_TYPE type;
			KMF_KEY_ALG keyalg;

			type = PK11_GetSymKeyType(symkey);
			keyalg = pk11keytype2kmf(type);

			symlist = PK11_GetNextSymKey(symkey);

			/*
			 * If keytype is specified in the searching parameter,
			 * check the keytype and skip the key if its keytype
			 * doesn't match.
			 */
			if (keytype != KMF_KEYALG_NONE && keytype != keyalg) {
				/* free that key since we arent using it */
				PK11_FreeSymKey(symkey);
				continue;
			}

			if (keys != NULL) {
				keys[count].kstype = KMF_KEYSTORE_NSS;
				keys[count].keyclass = KMF_SYMMETRIC;
				keys[count].keyp = (void *) symkey;
				keys[count].keylabel =
				    PK11_GetSymKeyNickname(symkey);
				keys[count].keyalg = keyalg;
			} else {
				PK11_FreeSymKey(symkey);
			}
			count++;
		}
		/*
		 * Cleanup memory for unused keys.
		 */
		while (symlist != NULL) {
			PK11SymKey *symkey = symlist;

			PK11_FreeSymKey(symkey);
			symlist = PK11_GetNextSymKey(symkey);
		}
		*numkeys = count;
	}

cleanup:
	if (nss_slot != NULL) {
		PK11_FreeSlot(nss_slot);
	}

	return (rv);
}

static SECStatus
p12u_SwapUnicodeBytes(SECItem *uniItem)
{
	unsigned int i;
	unsigned char a;
	if ((uniItem == NULL) || (uniItem->len % 2)) {
		return (SECFailure);
		}
	for (i = 0; i < uniItem->len; i += 2) {
		a = uniItem->data[i];
		uniItem->data[i] = uniItem->data[i+1];
		uniItem->data[i+1] = a;
	}
	return (SECSuccess);
}

static PRBool
p12u_ucs2_ascii_conversion_function(
	PRBool		toUnicode,
	unsigned char	*inBuf,
	unsigned int	inBufLen,
	unsigned char	*outBuf,
	unsigned int	maxOutBufLen,
	unsigned int	*outBufLen,
	PRBool		swapBytes)
{
	SECItem it = { 0 };
	SECItem *dup = NULL;
	PRBool ret;

	it.data = inBuf;
	it.len = inBufLen;
	dup = SECITEM_DupItem(&it);
	/*
	 * If converting Unicode to ASCII, swap bytes before conversion
	 * as neccessary.
	 */
	if (!toUnicode && swapBytes) {
		if (p12u_SwapUnicodeBytes(dup) != SECSuccess) {
			SECITEM_ZfreeItem(dup, PR_TRUE);
			return (PR_FALSE);
		}
	}
	/* Perform the conversion. */
	ret = PORT_UCS2_UTF8Conversion(toUnicode, dup->data, dup->len,
	    outBuf, maxOutBufLen, outBufLen);
	if (dup)
		SECITEM_ZfreeItem(dup, PR_TRUE);

	return (ret);
}

static PRBool
p12u_OpenFile(p12uContext *p12ctx, PRBool fileRead)
{
	if (!p12ctx || !p12ctx->filename) {
		return (PR_FALSE);
	}

	if (fileRead) {
		p12ctx->file = PR_Open(p12ctx->filename, PR_RDONLY, 0400);
	} else {
		p12ctx->file = PR_Open(p12ctx->filename,
		    PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, 0600);
	}

	if (!p12ctx->file) {
		p12ctx->error = PR_TRUE;
		return (PR_FALSE);
	}

	return (PR_TRUE);
}

static void
p12u_DestroyContext(p12uContext **ppCtx, PRBool removeFile)
{
	if (!ppCtx || !(*ppCtx)) {
		return;
	}

	if ((*ppCtx)->file != NULL) {
		PR_Close((*ppCtx)->file);
	}

	if ((*ppCtx)->filename != NULL) {
		if (removeFile) {
			PR_Delete((*ppCtx)->filename);
		}
		free((*ppCtx)->filename);
	}

	free(*ppCtx);
	*ppCtx = NULL;
}

static p12uContext *
p12u_InitContext(PRBool fileImport, char *filename)
{
	p12uContext *p12ctx;

	p12ctx = PORT_ZNew(p12uContext);
	if (!p12ctx) {
		return (NULL);
	}

	p12ctx->error = PR_FALSE;
	p12ctx->errorValue = 0;
	p12ctx->filename = strdup(filename);

	if (!p12u_OpenFile(p12ctx, fileImport)) {
		p12u_DestroyContext(&p12ctx, PR_FALSE);
		return (NULL);
	}

	return (p12ctx);
}

static void
p12u_WriteToExportFile(void *arg, const char *buf, unsigned long len)
{
	p12uContext *p12cxt = arg;
	int writeLen;

	if (!p12cxt || (p12cxt->error == PR_TRUE)) {
		return;
	}

	if (p12cxt->file == NULL) {
		p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
		p12cxt->error = PR_TRUE;
		return;
	}

	writeLen = PR_Write(p12cxt->file, (unsigned char *)buf, (int32)len);

	if (writeLen != (int)len) {
		PR_Close(p12cxt->file);
		free(p12cxt->filename);
		p12cxt->filename = NULL;
		p12cxt->file = NULL;
		p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
		p12cxt->error = PR_TRUE;
	}
}

#define	HANDLE_NSS_ERROR(r) {\
	SET_ERROR(kmfh, PORT_GetError()); \
	rv = r; \
	goto out; }

static KMF_RETURN
add_cert_to_bag(SEC_PKCS12ExportContext *p12ecx,
	CERTCertificate *cert, SECItem *pwitem)
{
	KMF_RETURN rv = KMF_OK;
	SEC_PKCS12SafeInfo *keySafe = NULL, *certSafe = NULL;

	keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx);
	if (PK11_IsFIPS()) {
		certSafe = keySafe;
	} else {
		certSafe = SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem,
		    SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC);
	}

	if (!certSafe || !keySafe) {
		rv = KMF_ERR_INTERNAL;
		goto out;
	}

	if (SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert,
	    CERT_GetDefaultCertDB(), keySafe, NULL, PR_TRUE, pwitem,
	    SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC)
	    != SECSuccess) {
		rv = KMF_ERR_INTERNAL;
	}
out:
	return (rv);
}

KMF_RETURN
NSS_ExportPK12(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
	KMF_RETURN rv;
	KMF_HANDLE *kmfh = (KMF_HANDLE  *)handle;
	SEC_PKCS12ExportContext *p12ecx = NULL;
	p12uContext *p12ctx = NULL;
	CERTCertList *certlist = NULL;
	CERTCertificate *nsscert = NULL;
	CERTCertListNode* node = NULL;
	PK11SlotInfo	*slot = NULL;
	SECItem pwitem = {NULL, 0};
	KMF_CREDENTIAL *cred = NULL;
	KMF_CREDENTIAL *p12cred = NULL;
	char *certlabel = NULL;
	char *issuer = NULL;
	char *subject = NULL;
	KMF_BIGINT *serial = NULL;
	char *filename = NULL;

	if (kmfh == NULL || attrlist == NULL || numattr == 0) {
		return (KMF_ERR_BAD_PARAMETER);
	}

	rv = do_nss_init(handle, numattr, attrlist, FALSE, &slot);
	if (rv != KMF_OK)
		return (rv);

	cred = kmf_get_attr_ptr(KMF_CREDENTIAL_ATTR, attrlist, numattr);
	if (cred == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	rv = nss_authenticate(handle, slot, cred);
	if (rv != KMF_OK)
		return (rv);

	p12cred = kmf_get_attr_ptr(KMF_PK12CRED_ATTR, attrlist, numattr);
	if (p12cred  == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	filename = kmf_get_attr_ptr(KMF_OUTPUT_FILENAME_ATTR, attrlist,
	    numattr);
	if (filename == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	/* Get optional search criteria attributes */
	certlabel = kmf_get_attr_ptr(KMF_CERT_LABEL_ATTR, attrlist, numattr);
	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);

	/*
	 * Find the certificate(s) first.
	 */
	if (certlabel != NULL) {
		nsscert = PK11_FindCertFromNickname(certlabel, NULL);
		if (nsscert == NULL) {
			HANDLE_NSS_ERROR(KMF_ERR_CERT_NOT_FOUND)
		}
	} else {
		rv = nss_find_matching_certs(slot, issuer, subject, serial,
		    &certlist, 0);

		if (rv == KMF_OK && certlist == NULL) {
			return (KMF_ERR_CERT_NOT_FOUND);
		}
		if (rv != KMF_OK)
			return (rv);
	}

	/*
	 * The KMF_CREDENTIAL holds the password to use for
	 * encrypting the PKCS12 key information.
	 */
	pwitem.data = (uchar_t *)p12cred->cred;
	pwitem.len = p12cred->credlen;

	p12ctx = p12u_InitContext(PR_FALSE, filename);
	if (!p12ctx) {
		HANDLE_NSS_ERROR(KMF_ERR_OPEN_FILE)
	}

	PORT_SetUCS2_ASCIIConversionFunction(
	    p12u_ucs2_ascii_conversion_function);

	p12ecx = SEC_PKCS12CreateExportContext(NULL, NULL, slot, NULL);
	if (!p12ecx) {
		HANDLE_NSS_ERROR(KMF_ERR_OPEN_FILE)
	}

	if (SEC_PKCS12AddPasswordIntegrity(p12ecx, &pwitem, SEC_OID_SHA1)
	    != SECSuccess) {
		HANDLE_NSS_ERROR(KMF_ERR_INTERNAL)
	}

	/*
	 * NSS actually supports storing a list of keys and certs
	 * in the PKCS#12 PDU.  Nice feature.
	 */
	if (certlist != NULL) {
		for (node = CERT_LIST_HEAD(certlist);
		    !CERT_LIST_END(node, certlist) && rv == KMF_OK;
		    node = CERT_LIST_NEXT(node)) {
			rv = add_cert_to_bag(p12ecx, node->cert, &pwitem);
		}
	} else if (nsscert != NULL) {
		rv = add_cert_to_bag(p12ecx, nsscert, &pwitem);
	}

	if (SEC_PKCS12Encode(p12ecx, p12u_WriteToExportFile, p12ctx)
	    != SECSuccess) {
		HANDLE_NSS_ERROR(KMF_ERR_ENCODING)
	}
out:
	if (nsscert)
		CERT_DestroyCertificate(nsscert);

	if (certlist)
		CERT_DestroyCertList(certlist);

	if (p12ctx)
		p12u_DestroyContext(&p12ctx, PR_FALSE);

	if (p12ecx)
		SEC_PKCS12DestroyExportContext(p12ecx);

	return (rv);
}

#define	SETATTR(t, n, atype, value, size) \
	t[n].type = atype; \
	t[n].pValue = (CK_BYTE *)value; \
	t[n].ulValueLen = (CK_ULONG)size;

KMF_RETURN
NSS_CreateSymKey(KMF_HANDLE_T handle,
	int numattr, KMF_ATTRIBUTE *attrlist)
{
	KMF_RETURN rv = KMF_OK;
	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
	PK11SlotInfo *nss_slot = NULL;
	PK11SymKey *nsskey = NULL;
	CK_MECHANISM_TYPE keyType;
	SECStatus nssrv;
	int keySize;
	KMF_KEY_HANDLE *symkey;
	KMF_CREDENTIAL cred;
	uint32_t keylen;
	uint32_t keylen_size = sizeof (uint32_t);
	KMF_KEY_ALG keytype;
	char *keylabel = NULL;

	if (kmfh == NULL || attrlist == NULL || numattr == 0) {
		return (KMF_ERR_BAD_PARAMETER);
	}

	symkey = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr);
	if (symkey == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	rv = kmf_get_attr(KMF_KEYALG_ATTR, attrlist, numattr, (void *)&keytype,
	    NULL);
	if (rv != KMF_OK)
		return (KMF_ERR_BAD_PARAMETER);

	rv = kmf_get_attr(KMF_KEYLENGTH_ATTR, attrlist, numattr, &keylen,
	    &keylen_size);
	if (rv == KMF_ERR_ATTR_NOT_FOUND &&
	    (keytype == KMF_DES || keytype == KMF_DES3))
		/* keylength is not required for DES and 3DES */
		rv = KMF_OK;
	if (rv != KMF_OK)
		return (KMF_ERR_BAD_PARAMETER);

	keylabel = kmf_get_attr_ptr(KMF_KEYLABEL_ATTR, attrlist, numattr);
	if (keylabel == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	switch (keytype) {
	case KMF_AES:
		keyType = CKM_AES_KEY_GEN;
		keySize = keylen;
		if (keySize == 0 || (keySize % 8) != 0)
			return (KMF_ERR_BAD_KEY_SIZE);
		break;
	case KMF_RC4:
		keyType = CKM_RC4_KEY_GEN;
		keySize = keylen;
		if (keySize == 0 || (keySize % 8) != 0)
			return (KMF_ERR_BAD_KEY_SIZE);
		break;
	case KMF_DES:
		keyType = CKM_DES_KEY_GEN;
		keySize = 0; /* required by PK11_TokenKeyGen()  */
		break;
	case KMF_DES3:
		keyType = CKM_DES3_KEY_GEN;
		keySize = 0; /* required by PK11_TokenKeyGen() */
		break;
	case KMF_GENERIC_SECRET:
		keyType = CKM_GENERIC_SECRET_KEY_GEN;
		keySize = keylen;
		if (keySize == 0 || (keySize % 8) != 0)
			return (KMF_ERR_BAD_KEY_SIZE);
		break;
	default:
		rv = KMF_ERR_BAD_KEY_TYPE;
		goto out;
	}

	rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot);
	if (rv != KMF_OK) {
		return (rv);
	}

	rv = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr,
	    (void *)&cred, NULL);
	if (rv != KMF_OK)
		return (KMF_ERR_BAD_PARAMETER);

	rv = nss_authenticate(handle, nss_slot, &cred);
	if (rv != KMF_OK) {
		return (rv);
	}

	nsskey = PK11_TokenKeyGen(nss_slot, keyType, NULL, keySize,  NULL,
	    PR_TRUE, (void *)cred.cred);
	if (nsskey == NULL) {
		SET_ERROR(kmfh, PORT_GetError());
		rv = KMF_ERR_KEYGEN_FAILED;
		goto out;
	}

	nssrv = PK11_SetSymKeyNickname(nsskey, keylabel);
	if (nssrv != SECSuccess) {
		SET_ERROR(kmfh, PORT_GetError());
		rv = KMF_ERR_KEYGEN_FAILED;
		goto out;
	}

	symkey->kstype = KMF_KEYSTORE_NSS;
	symkey->keyalg = keytype;
	symkey->keyclass = KMF_SYMMETRIC;
	symkey->israw = FALSE;
	symkey->keyp = (void *)nsskey;

out:
	if (nss_slot != NULL)
		PK11_FreeSlot(nss_slot);

	if (rv != KMF_OK && nsskey != NULL) {
		PK11_DeleteTokenSymKey(nsskey);
		PK11_FreeSymKey(nsskey);
	}
	return (rv);
}

KMF_RETURN
NSS_GetSymKeyValue(KMF_HANDLE_T handle, KMF_KEY_HANDLE *symkey,
	KMF_RAW_SYM_KEY *rkey)
{
	KMF_RETURN rv = KMF_OK;
	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
	SECItem *value = NULL;
	PK11SymKey *nsskey;
	SECStatus nss_rv;

	if (kmfh == NULL)
		return (KMF_ERR_UNINITIALIZED);

	if (symkey == NULL || rkey == NULL)
		return (KMF_ERR_BAD_PARAMETER);
	else if (symkey->keyclass != KMF_SYMMETRIC)
		return (KMF_ERR_BAD_KEY_CLASS);

	if (symkey->israw) {
		KMF_RAW_KEY_DATA *rawkey = (KMF_RAW_KEY_DATA *)symkey->keyp;

		if (rawkey == NULL ||
		    rawkey->rawdata.sym.keydata.val == NULL ||
		    rawkey->rawdata.sym.keydata.len == 0)
			return (KMF_ERR_BAD_KEYHANDLE);

		rkey->keydata.len = rawkey->rawdata.sym.keydata.len;
		if ((rkey->keydata.val = malloc(rkey->keydata.len)) == NULL)
			return (KMF_ERR_MEMORY);
		(void) memcpy(rkey->keydata.val,
		    rawkey->rawdata.sym.keydata.val, rkey->keydata.len);
	} else {
		nsskey = (PK11SymKey *)(symkey->keyp);
		if (nsskey == NULL)
			return (KMF_ERR_BAD_KEYHANDLE);

		nss_rv = PK11_ExtractKeyValue(nsskey);
		if (nss_rv != SECSuccess) {
			SET_ERROR(kmfh, PORT_GetError());
			rv = KMF_ERR_GETKEYVALUE_FAILED;
			goto out;
		}

		value = PK11_GetKeyData(nsskey);
		if (value == NULL) {
			SET_ERROR(kmfh, PORT_GetError());
			rv = KMF_ERR_GETKEYVALUE_FAILED;
			goto out;
		}

		if (value->len == 0 || value->data == NULL) {
			rv = KMF_ERR_GETKEYVALUE_FAILED;
			goto out;
		}

		rkey->keydata.val = malloc(value->len);
		if (rkey->keydata.val == NULL) {
			rv = KMF_ERR_MEMORY;
			goto out;
		}
		(void) memcpy(rkey->keydata.val, value->data, value->len);
		rkey->keydata.len = value->len;
		(void) memset(value->data, 0, value->len);
	}
out:
	if (value != NULL)
		SECITEM_FreeItem(value, PR_TRUE);
	return (rv);
}

KMF_RETURN
NSS_SetTokenPin(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
	KMF_RETURN ret = KMF_OK;
	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
	int rv;
	PK11SlotInfo *nss_slot = NULL;
	KMF_CREDENTIAL oldcred, newcred;

	if (handle == NULL || attrlist == NULL || numattr == 0)
		return (KMF_ERR_BAD_PARAMETER);

	ret = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr,
	    (void *)&oldcred, NULL);
	if (ret != KMF_OK)
		return (KMF_ERR_BAD_PARAMETER);
	ret = kmf_get_attr(KMF_NEWPIN_ATTR, attrlist, numattr,
	    (void *)&newcred, NULL);
	if (ret != KMF_OK)
		return (KMF_ERR_BAD_PARAMETER);

	ret = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot);
	/* If it was uninitialized, set it */
	if (ret == KMF_ERR_UNINITIALIZED_TOKEN) {
		rv = PK11_InitPin(nss_slot, NULL, newcred.cred);
		if (rv != SECSuccess) {
			SET_ERROR(kmfh, PORT_GetError());
			ret = KMF_ERR_AUTH_FAILED;
		} else {
			ret = KMF_OK;
		}
	} else if (ret == KMF_OK) {
		ret = nss_authenticate(handle, nss_slot, &oldcred);
		if (ret != KMF_OK) {
			return (ret);
		}
		rv = PK11_ChangePW(nss_slot, oldcred.cred, newcred.cred);
		if (rv != SECSuccess) {
			SET_ERROR(kmfh, PORT_GetError());
			ret = KMF_ERR_AUTH_FAILED;
		}
	}

	return (ret);
}

KMF_RETURN
NSS_StoreKey(KMF_HANDLE_T handle,
	int numattr, KMF_ATTRIBUTE *attrlist)
{
	KMF_RETURN rv = KMF_OK;
	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
	PK11SlotInfo *nss_slot = NULL;
	KMF_CREDENTIAL cred = {NULL, 0};
	KMF_KEY_HANDLE *pubkey = NULL, *prikey = NULL;
	KMF_RAW_KEY_DATA *rawkey = NULL;
	char *keylabel = NULL;
	SECStatus ckrv = SECSuccess;
	SECItem nickname = {NULL, 0};
	CERTCertificate *nss_cert = NULL;

	if (kmfh == NULL || attrlist == NULL || numattr == 0) {
		return (KMF_ERR_BAD_PARAMETER);
	}

	rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot);
	if (rv != KMF_OK) {
		return (rv);
	}

	rv = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr,
	    (void *)&cred, NULL);
	if (rv != KMF_OK)
		return (KMF_ERR_BAD_PARAMETER);

	rv = nss_authenticate(handle, nss_slot, &cred);
	if (rv != KMF_OK) {
		return (rv);
	}

	pubkey = kmf_get_attr_ptr(KMF_PUBKEY_HANDLE_ATTR, attrlist, numattr);
	if (pubkey == NULL) {
		/* look for private key */
		prikey = kmf_get_attr_ptr(KMF_PRIVKEY_HANDLE_ATTR, attrlist,
		    numattr);
		if (prikey == NULL)
			/* look for raw key */
			rawkey = kmf_get_attr_ptr(KMF_RAW_KEY_ATTR,
			    attrlist, numattr);
	}

	/* If no keys were found, return error */
	if (pubkey == NULL && prikey == NULL && rawkey == NULL)
		return (KMF_ERR_ATTR_NOT_FOUND);

	keylabel = kmf_get_attr_ptr(KMF_KEYLABEL_ATTR, attrlist, numattr);
	if (keylabel != NULL) {
		nickname.data = (uchar_t *)keylabel;
		nickname.len = strlen(keylabel);
	}

	if (rawkey != NULL) {
		uchar_t ver = 0;
		SECKEYPrivateKeyInfo rpk;
		KMF_DATA derkey = {NULL, 0};
		KMF_DATA *cert;

		cert = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist, numattr);
		if (cert == NULL)
			return (rv);
		/*
		 * Decode the cert into an NSS CERT object so we can access the
		 * SPKI and KeyUsage data later.
		 */
		nss_cert = CERT_DecodeCertFromPackage((char *)cert->Data,
		    cert->Length);

		if (nss_cert == NULL) {
			SET_ERROR(kmfh, PORT_GetError());
			rv = KMF_ERR_BAD_CERT_FORMAT;
			goto cleanup;
		}

		(void) memset(&rpk, 0, sizeof (rpk));
		rpk.arena = NULL;
		rpk.version.type = siUnsignedInteger;
		rpk.version.data = &ver;
		rpk.version.len = 1;
		if (rawkey->keytype == KMF_RSA) {
			rv = DerEncodeRSAPrivateKey(&derkey,
			    &rawkey->rawdata.rsa);
			if (rv != KMF_OK)
				goto cleanup;

		} else if (rawkey->keytype == KMF_DSA) {
			rv = DerEncodeDSAPrivateKey(&derkey,
			    &rawkey->rawdata.dsa);
			if (rv != KMF_OK)
				goto cleanup;
		}
		rpk.algorithm = nss_cert->subjectPublicKeyInfo.algorithm;
		rpk.privateKey.data = derkey.Data;
		rpk.privateKey.len = derkey.Length;
		rpk.attributes = NULL;

		ckrv = PK11_ImportPrivateKeyInfo(nss_slot, &rpk, &nickname,
		    &nss_cert->subjectPublicKeyInfo.subjectPublicKey, TRUE,
		    TRUE, nss_cert->keyUsage, NULL);
		if (ckrv != CKR_OK) {
			SET_ERROR(kmfh, PORT_GetError());
			rv = KMF_ERR_INTERNAL;
		}
		kmf_free_data(&derkey);
	} else if (pubkey != NULL && pubkey->kstype == KMF_KEYSTORE_NSS) {
		CK_OBJECT_HANDLE pk;
		SECKEYPublicKey *publicKey = (SECKEYPublicKey *) pubkey->keyp;

		pk = PK11_ImportPublicKey(nss_slot, publicKey, PR_TRUE);
		if (pk == CK_INVALID_HANDLE) {
			SET_ERROR(kmfh, PORT_GetError());
			rv = KMF_ERR_INTERNAL;
		}
	} else if (prikey != NULL && prikey->kstype == KMF_KEYSTORE_NSS) {
		SECKEYPrivateKey *pk;
		SECKEYPrivateKey *privKey = (SECKEYPrivateKey *) prikey->keyp;

		pk = PK11_LoadPrivKey(nss_slot, privKey, NULL, PR_TRUE,
		    PR_TRUE);
		if (pk == CK_INVALID_HANDLE) {
			SET_ERROR(kmfh, PORT_GetError());
			rv = KMF_ERR_INTERNAL;
		}
		/* We stored it, but don't need the handle anymore */
		SECKEY_DestroyPrivateKey(pk);
	}

cleanup:
	if (nss_cert != NULL)
		CERT_DestroyCertificate(nss_cert);
	PK11_FreeSlot(nss_slot);
	return (rv);
}

/*
 * This function is called by NSS_StoreCert() and NSS_ImportCert().
 * The "label" and "trust_flag" arguments can be NULL.
 */
static KMF_RETURN
store_cert(KMF_HANDLE_T handle, PK11SlotInfo *nss_slot, KMF_DATA *cert,
    char *label, char *trust_flag)
{
	KMF_RETURN ret = KMF_OK;
	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
	SECStatus nss_rv;
	CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
	CERTCertificate *nss_cert = NULL;
	CERTCertTrust *nss_trust = NULL;

	if (nss_slot == NULL || cert == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	nss_cert = CERT_DecodeCertFromPackage((char *)cert->Data,
	    cert->Length);
	if (nss_cert == NULL) {
		SET_ERROR(kmfh, PORT_GetError());
		ret = KMF_ERR_BAD_CERT_FORMAT;
		goto out;
	}

	/* Store the cert into the NSS database */
	nss_rv = PK11_ImportCert(nss_slot, nss_cert, CK_INVALID_HANDLE,
	    label, 0);
	if (nss_rv) {
		SET_ERROR(kmfh, nss_rv);
		ret = KMF_ERR_BAD_CERT_FORMAT;
		goto out;
	}

	/* If trust_flag is NULL, then we are done */
	if (trust_flag == NULL)
		goto out;

	nss_trust = (CERTCertTrust *) malloc(sizeof (CERTCertTrust));
	if (nss_trust == NULL) {
		ret = KMF_ERR_MEMORY;
		goto out;
	}

	nss_rv = CERT_DecodeTrustString(nss_trust, trust_flag);
	if (nss_rv) {
		SET_ERROR(kmfh, nss_rv);
		ret = KMF_ERR_BAD_PARAMETER;
		goto out;
	}

	nss_rv = CERT_ChangeCertTrust(certHandle, nss_cert, nss_trust);
	if (nss_rv) {
		SET_ERROR(kmfh, nss_rv);
		ret = KMF_ERR_BAD_PARAMETER;
	}

out:
	if (nss_cert != NULL) {
		CERT_DestroyCertificate(nss_cert);
	}

	if (nss_trust != NULL) {
		free(nss_trust);
	}

	return (ret);
}


KMF_RETURN
NSS_StoreCert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
	KMF_RETURN ret = KMF_OK;
	PK11SlotInfo *nss_slot = NULL;
	KMF_DATA *cert = NULL;
	char *label = NULL;
	char *trust_flag = NULL;

	if (handle == NULL || attrlist == NULL || numattr == 0) {
		return (KMF_ERR_BAD_PARAMETER);
	}

	ret = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot);
	if (ret != KMF_OK)
		return (ret);

	/* 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);

	/* The label attribute is optional */
	label = kmf_get_attr_ptr(KMF_CERT_LABEL_ATTR, attrlist, numattr);

	/* The trustflag attriburte is optional */
	trust_flag = kmf_get_attr_ptr(KMF_TRUSTFLAG_ATTR, attrlist, numattr);

	ret = store_cert(handle, nss_slot, cert, label, trust_flag);

out:
	if (nss_slot != NULL) {
		PK11_FreeSlot(nss_slot);
	}

	return (ret);
}


KMF_RETURN
NSS_ImportCert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
	KMF_RETURN ret = KMF_OK;
	PK11SlotInfo *nss_slot = NULL;
	KMF_DATA cert = {NULL, 0};
	KMF_DATA cert_der = {NULL, 0};
	KMF_DATA *cptr = NULL;
	KMF_ENCODE_FORMAT format;
	char *label = NULL;
	char *trust_flag = NULL;
	char *certfile = NULL;

	if (handle == NULL || attrlist == NULL || numattr == 0) {
		return (KMF_ERR_BAD_PARAMETER);
	}

	ret = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot);
	if (ret != KMF_OK)
		return (ret);

	/* Get the input cert filename attribute */
	certfile = kmf_get_attr_ptr(KMF_CERT_FILENAME_ATTR, attrlist, numattr);
	if (certfile == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	/* Check the cert file and auto-detect the file format of it. */
	ret = kmf_is_cert_file(handle, certfile, &format);
	if (ret != KMF_OK)
		return (ret);

	ret = kmf_read_input_file(handle, certfile, &cert);
	if (ret != KMF_OK) {
		return (ret);
	}

	/*
	 * If the imported cert is in PEM format, convert it to
	 * DER format in order to store it in NSS token.
	 */
	if (format == KMF_FORMAT_PEM) {
		int derlen;
		ret = kmf_pem_to_der(cert.Data, cert.Length,
		    &cert_der.Data, &derlen);
		if (ret != KMF_OK) {
			goto cleanup;
		}
		cert_der.Length = (size_t)derlen;
		cptr = &cert_der;
	} else {
		cptr = &cert;
	}

	label = kmf_get_attr_ptr(KMF_CERT_LABEL_ATTR, attrlist, numattr);
	trust_flag = kmf_get_attr_ptr(KMF_TRUSTFLAG_ATTR, attrlist, numattr);
	ret = store_cert(handle, nss_slot, cptr, label, trust_flag);

cleanup:
	if (format == KMF_FORMAT_PEM) {
		kmf_free_data(&cert_der);
	}

	kmf_free_data(&cert);

	return (ret);
}


KMF_RETURN
NSS_ImportCRL(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
	KMF_RETURN ret = KMF_OK;
	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
	PK11SlotInfo *nss_slot = NULL;
	CERTSignedCrl *nss_crl = NULL;
	KMF_ENCODE_FORMAT format;
	int importOptions;
	SECItem crlDER;
	KMF_DATA crl1;
	KMF_DATA crl2;
	char *crlfilename;
	boolean_t crlcheck = FALSE;

	if (attrlist == NULL || numattr == 0) {
		return (KMF_ERR_BAD_PARAMETER);
	}

	ret = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot);
	if (ret != KMF_OK) {
		return (ret);
	}

	crlfilename = kmf_get_attr_ptr(KMF_CRL_FILENAME_ATTR, attrlist,
	    numattr);
	if (crlfilename == NULL)
		return (KMF_ERR_BAD_CRLFILE);

	/*
	 * Check if the input CRL file is a valid CRL file and auto-detect
	 * the encoded format of the file.
	 */
	ret = kmf_is_crl_file(handle, crlfilename, &format);
	if (ret != KMF_OK)
		return (ret);

	ret = kmf_get_attr(KMF_CRL_CHECK_ATTR, attrlist, numattr,
	    &crlcheck, NULL);
	if (ret != KMF_OK)
		ret = KMF_OK; /* CRL_CHECK is optional */

	/* set importOptions */
	if (crlcheck == B_FALSE) {
		importOptions = CRL_IMPORT_DEFAULT_OPTIONS |
		    CRL_IMPORT_BYPASS_CHECKS;
	} else {
		importOptions = CRL_IMPORT_DEFAULT_OPTIONS;
	}


	/* Read in the CRL file */
	crl1.Data = NULL;
	crl2.Data = NULL;
	ret = kmf_read_input_file(handle, crlfilename, &crl1);
	if (ret != KMF_OK) {
		return (ret);
	}

	/* If the input CRL is in PEM format, convert it to DER first. */
	if (format == KMF_FORMAT_PEM) {
		int len;
		ret = kmf_pem_to_der(crl1.Data, crl1.Length,
		    &crl2.Data, &len);
		if (ret != KMF_OK) {
			goto out;
		}
		crl2.Length = (size_t)len;
	}

	crlDER.data = format == KMF_FORMAT_ASN1 ? crl1.Data : crl2.Data;
	crlDER.len = format == KMF_FORMAT_ASN1 ? crl1.Length : crl2.Length;

	nss_crl = PK11_ImportCRL(nss_slot, &crlDER, NULL, SEC_CRL_TYPE,
	    NULL, importOptions, NULL, CRL_DECODE_DEFAULT_OPTIONS);

	if (nss_crl == NULL) {
		SET_ERROR(kmfh, PORT_GetError());
		ret = KMF_ERR_BAD_CRLFILE;
		goto out;
	}

out:
	if (nss_slot != NULL) {
		PK11_FreeSlot(nss_slot);
	}

	if (crl1.Data != NULL) {
		free(crl1.Data);
	}

	if (crl2.Data != NULL) {
		free(crl2.Data);
	}

	if (nss_crl != NULL) {
		SEC_DestroyCrl(nss_crl);
	}

	return (ret);
}

KMF_RETURN
NSS_DeleteCRL(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
	KMF_RETURN rv = KMF_OK;
	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
	CERTSignedCrl *crl = NULL;
	CERTCertificate *cert = NULL;
	PK11SlotInfo *nss_slot = NULL;
	CERTCrlHeadNode *crlList = NULL;
	CERTCrlNode *crlNode = NULL;
	PRArenaPool *arena = NULL;
	CERTName *name = NULL;
	CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
	char *issuername, *subjectname;

	/* check params */
	if (numattr == 0 || attrlist == NULL) {
		return (KMF_ERR_BAD_PARAMETER);
	}

	rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot);
	if (rv != KMF_OK) {
		return (rv);
	}

	issuername = kmf_get_attr_ptr(KMF_ISSUER_NAME_ATTR, attrlist,
	    numattr);
	subjectname = kmf_get_attr_ptr(KMF_SUBJECT_NAME_ATTR, attrlist,
	    numattr);

	/* Caller must specify issuer or subject but not both */
	if ((issuername == NULL && subjectname == NULL) ||
	    (issuername != NULL && subjectname != NULL))
		return (KMF_ERR_BAD_PARAMETER);

	/* Find the CRL based on the deletion criteria. */
	if (issuername != NULL) {
		/*
		 * If the deletion is based on the issuer's certificate
		 * nickname, we will get the issuer's cert first, then
		 * get the CRL from the cert.
		 */
		cert = CERT_FindCertByNicknameOrEmailAddr(certHandle,
		    issuername);
		if (!cert) {
			SET_ERROR(kmfh, PORT_GetError());
			rv = KMF_ERR_CERT_NOT_FOUND;
			goto out;
		}

		crl = SEC_FindCrlByName(certHandle, &cert->derSubject,
		    SEC_CRL_TYPE);
		if (crl == NULL) {
			SET_ERROR(kmfh, PORT_GetError());
			rv = KMF_ERR_CRL_NOT_FOUND;
			goto out;
		}
	} else {
		/*
		 * If the deletion is based on the CRL's subject name, we will
		 * get all the CRLs from the internal database and search
		 * for the CRL with the same subject name.
		 */
		boolean_t found = B_FALSE;
		int nssrv;

		nssrv = SEC_LookupCrls(certHandle, &crlList, SEC_CRL_TYPE);
		if (nssrv) {
			SET_ERROR(kmfh, nssrv);
			rv = KMF_ERR_CRL_NOT_FOUND;
			goto out;
		}

		if (crlList == NULL) {
			SET_ERROR(kmfh, PORT_GetError());
			rv = KMF_ERR_CRL_NOT_FOUND;
			goto out;
		}

		/* Allocate space for name */
		arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
		if (arena == NULL) {
			rv = KMF_ERR_MEMORY;
			goto out;
		}

		name = PORT_ArenaZAlloc(arena, sizeof (*name));
		if (name == NULL) {
			rv = KMF_ERR_MEMORY;
			goto out;
		}
		name->arena = arena;

		crlNode  = crlList->first;
		while (crlNode && !found) {
			char *asciiname = NULL;
			SECItem* issuer;

			name = &crlNode->crl->crl.name;
			if (!name) {
				SET_ERROR(kmfh, PORT_GetError());
				rv = KMF_ERR_CRL_NOT_FOUND;
				break;
			}

			asciiname = CERT_NameToAscii(name);
			if (asciiname == NULL) {
				SET_ERROR(kmfh, PORT_GetError());
				rv = KMF_ERR_CRL_NOT_FOUND;
				break;
			}

			if (strcmp(subjectname, asciiname) == 0) {
				found = B_TRUE;
				issuer = &crlNode->crl->crl.derName;
				crl = SEC_FindCrlByName(certHandle, issuer,
				    SEC_CRL_TYPE);
				if (crl == NULL) {
					/* We found a cert but no CRL */
					SET_ERROR(kmfh,  PORT_GetError());
					rv = KMF_ERR_CRL_NOT_FOUND;
				}
			}
			PORT_Free(asciiname);
			crlNode = crlNode->next;
		}

		if (rv) {
			goto out;
		}
	}

	if (crl) {
		(void) SEC_DeletePermCRL(crl);
	}

out:
	if (nss_slot != NULL) {
		PK11_FreeSlot(nss_slot);
	}

	if (crlList != NULL) {
		PORT_FreeArena(crlList->arena, PR_FALSE);
	}

	if (arena != NULL) {
		PORT_FreeArena(arena, PR_FALSE);
	}

	if (cert != NULL) {
		CERT_DestroyCertificate(cert);
	}

	if (crl != NULL) {
		SEC_DestroyCrl(crl);
	}

	return (rv);
}

KMF_RETURN
NSS_FindCRL(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
	KMF_RETURN rv = KMF_OK;
	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
	PK11SlotInfo *nss_slot = NULL;
	CERTCrlHeadNode *crlList = NULL;
	CERTCrlNode *crlNode = NULL;
	PRArenaPool *arena = NULL;
	CERTName *name = NULL;
	SECStatus nssrv;
	char *asciiname = NULL;
	int crl_num;
	int i, *CRLCount;
	CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
	char **CRLNameList;

	if (numattr == 0 || attrlist == NULL) {
		return (KMF_ERR_BAD_PARAMETER);
	}

	rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot);
	if (rv != KMF_OK) {
		return (rv);
	}

	CRLCount = kmf_get_attr_ptr(KMF_CRL_COUNT_ATTR,	attrlist, numattr);
	if (CRLCount == NULL)
		return (KMF_ERR_BAD_PARAMETER);

	CRLNameList = (char **)kmf_get_attr_ptr(KMF_CRL_NAMELIST_ATTR,
	    attrlist, numattr);

	/* Look up Crls */
	nssrv = SEC_LookupCrls(certHandle, &crlList, SEC_CRL_TYPE);
	if (nssrv) {
		SET_ERROR(kmfh, rv);
		rv = KMF_ERR_CRL_NOT_FOUND;
		goto out;
	}

	/* Allocate space for name first */
	arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
	if (arena == NULL) {
		rv = KMF_ERR_MEMORY;
		goto out;
	}

	name = PORT_ArenaZAlloc(arena, sizeof (*name));
	if (name == NULL) {
		rv = KMF_ERR_MEMORY;
		goto out;
	}
	name->arena = arena;

	/*
	 * Loop thru the crlList and create a crl list with CRL's subject name.
	 */
	crlNode  = crlList->first;
	crl_num = 0;
	while (crlNode) {
		char *subj_name;

		/* Get the CRL subject name */
		name = &crlNode->crl->crl.name;
		if (!name) {
			SET_ERROR(kmfh, PORT_GetError());
			rv = KMF_ERR_CRL_NOT_FOUND;
			break;
		}


		if (CRLNameList != NULL) {
			asciiname = CERT_NameToAscii(name);
			if (asciiname == NULL) {
				SET_ERROR(kmfh, PORT_GetError());
				rv = KMF_ERR_CRL_NOT_FOUND;
				break;
			}
			subj_name = strdup(asciiname);
			PORT_Free(asciiname);
			if (subj_name == NULL) {
				rv = KMF_ERR_MEMORY;
				break;
			}
			CRLNameList[crl_num] = subj_name;
		}

		crl_num++;
		crlNode = crlNode->next;
	}

	if (rv == KMF_OK) {
		/* success */
		*CRLCount = crl_num;
	}

out:
	if (nss_slot != NULL) {
		PK11_FreeSlot(nss_slot);
	}

	if (crlList != NULL) {
		PORT_FreeArena(crlList->arena, PR_FALSE);
	}

	if (arena != NULL) {
		PORT_FreeArena(arena, PR_FALSE);
	}

	/* If failed, free memory allocated for the returning rlist */
	if (rv && (CRLNameList != NULL)) {
		for (i = 0; i < crl_num; i++) {
			free(CRLNameList[i]);
		}
	}

	return (rv);
}

KMF_RETURN
NSS_FindCertInCRL(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
	KMF_RETURN rv = KMF_OK;
	KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
	PK11SlotInfo *nss_slot = NULL;
	CERTCertificate *cert = NULL;
	CERTSignedCrl *crl = NULL;
	CERTCrlEntry *entry;
	boolean_t match = B_FALSE;
	int i;
	CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
	char *certlabel;
	KMF_DATA *certdata;

	/* check params */
	if (numattr == 0 || attrlist == NULL) {
		return (KMF_ERR_BAD_PARAMETER);
	}

	rv = do_nss_init(handle, numattr, attrlist, FALSE, &nss_slot);
	if (rv != KMF_OK) {
		return (rv);
	}

	certlabel = kmf_get_attr_ptr(KMF_CERT_LABEL_ATTR, attrlist, numattr);

	/* Find the certificate first */
	if (certlabel != NULL) {
		cert = CERT_FindCertByNicknameOrEmailAddr(certHandle,
		    certlabel);
	} else {
		SECItem derCert = { NULL, 0};

		certdata = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR,
		    attrlist, numattr);

		if (certdata == NULL)
			return (KMF_ERR_BAD_PARAMETER);

		derCert.data = certdata->Data;
		derCert.len = certdata->Length;

		cert = CERT_FindCertByDERCert(certHandle, &derCert);
	}

	if (cert == NULL) {
		SET_ERROR(kmfh, PORT_GetError());
		rv = KMF_ERR_CERT_NOT_FOUND;
		goto out;
	}

	/* Find the CRL with the same issuer as the given certificate. */
	crl = SEC_FindCrlByName(certHandle, &cert->derIssuer, SEC_CRL_TYPE);
	if (crl == NULL) {
		/*
		 * Could not find the CRL issued by the same issuer. This
		 * usually means that the CRL is not installed in the DB.
		 */
		SET_ERROR(kmfh, PORT_GetError());
		rv = KMF_ERR_CRL_NOT_FOUND;
		goto out;

	}

	/* Check if the certificate's serialNumber is revoked in the CRL */
	i = 0;
	while ((entry = (crl->crl).entries[i++]) != NULL) {
		if (SECITEM_CompareItem(&(cert->serialNumber),
		    &(entry->serialNumber)) == SECEqual) {
			match = B_TRUE;
			break;
		}
	}

	if (!match) {
		rv = KMF_ERR_NOT_REVOKED;
	}

out:
	if (nss_slot != NULL) {
		PK11_FreeSlot(nss_slot);
	}

	if (cert != NULL) {
		CERT_DestroyCertificate(cert);
	}

	if (crl != NULL) {
		SEC_DestroyCrl(crl);
	}

	return (rv);
}