diff options
author | wyllys <none@none> | 2006-11-10 15:34:56 -0800 |
---|---|---|
committer | wyllys <none@none> | 2006-11-10 15:34:56 -0800 |
commit | 99ebb4ca412cb0a19d77a3899a87c055b9c30fa8 (patch) | |
tree | a972f78468519a4e00234388688f45a506e934ba /usr/src/lib/libkmf/plugins | |
parent | 177fd15c9f814babb60e824f89984cdd8acf7c85 (diff) | |
download | illumos-joyent-99ebb4ca412cb0a19d77a3899a87c055b9c30fa8.tar.gz |
PSARC 2005/074 Solaris Key Management Framework
6224192 Solaris needs unified key management interfaces
--HG--
rename : usr/src/cmd/cmd-crypto/pktool/biginteger.h => deleted_files/usr/src/cmd/cmd-crypto/pktool/biginteger.h
rename : usr/src/cmd/cmd-crypto/pktool/derparse.c => deleted_files/usr/src/cmd/cmd-crypto/pktool/derparse.c
rename : usr/src/cmd/cmd-crypto/pktool/derparse.h => deleted_files/usr/src/cmd/cmd-crypto/pktool/derparse.h
rename : usr/src/cmd/cmd-crypto/pktool/osslcommon.c => deleted_files/usr/src/cmd/cmd-crypto/pktool/osslcommon.c
rename : usr/src/cmd/cmd-crypto/pktool/osslcommon.h => deleted_files/usr/src/cmd/cmd-crypto/pktool/osslcommon.h
rename : usr/src/cmd/cmd-crypto/pktool/p12common.c => deleted_files/usr/src/cmd/cmd-crypto/pktool/p12common.c
rename : usr/src/cmd/cmd-crypto/pktool/p12common.h => deleted_files/usr/src/cmd/cmd-crypto/pktool/p12common.h
Diffstat (limited to 'usr/src/lib/libkmf/plugins')
25 files changed, 10583 insertions, 0 deletions
diff --git a/usr/src/lib/libkmf/plugins/Makefile b/usr/src/lib/libkmf/plugins/Makefile new file mode 100644 index 0000000000..5b27f7e6da --- /dev/null +++ b/usr/src/lib/libkmf/plugins/Makefile @@ -0,0 +1,48 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# KMF Prototype Makefile +# +include ../../Makefile.lib + +SUBDIRS = kmf_nss kmf_openssl kmf_pkcs11 + +HDRS= +HDRDIR= include + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +all clean clobber install lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/Makefile new file mode 100644 index 0000000000..5c60729ece --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_nss/Makefile @@ -0,0 +1,47 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include $(SRC)/lib/Makefile.lib + +SUBDIRS= $(MACH) + +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET= all +check := TARGET= check +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +.KEEP_STATE: + +all clean clobber install lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/Makefile.com b/usr/src/lib/libkmf/plugins/kmf_nss/Makefile.com new file mode 100644 index 0000000000..30209c69f9 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_nss/Makefile.com @@ -0,0 +1,74 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# Makefile for KMF Plugins +# + +LIBRARY= kmf_nss.a +VERS= .1 + +OBJECTS= nss_spi.o + +include $(SRC)/lib/Makefile.lib + +MPSDIR= /usr/lib/mps +KMFINC= -I../../../include -I../../../ber_der/inc +NSSINC= -I/usr/include/mps +BERLIB= -lkmf -lkmfberder +BERLIB64= $(BERLIB) + +NSSLIBS= $(BERLIB) -L$(MPSDIR) -R$(MPSDIR) -lnss3 -lnspr4 -lsmime3 -lc +NSSLIBS64= $(BERLIB64) -L$(MPSDIR)/$(MACH64) -R$(MPSDIR)/$(MACH64) -lnss3 -lnspr4 -lsmime3 -lc + +SRCDIR= ../common +INCDIR= ../../include + +CFLAGS += $(CCVERBOSE) +CPPFLAGS += -D_REENTRANT $(KMFINC) $(NSSINC) \ + -I$(SFWDIR)/include -I$(INCDIR) -I/usr/include/libxml2 + +PICS= $(OBJECTS:%=pics/%) + +lint:= NSSLIBS = $(BERLIB) +lint:= NSSLIBS64 = $(BERLIB64) + +LDLIBS32 += $(NSSLIBS) + +LIBS = $(DYNLIB) + +ROOTLIBDIR= $(ROOT)/usr/lib/security +ROOTLIBDIR64= $(ROOT)/usr/lib/security/$(MACH64) + + +.KEEP_STATE: + +all: $(LIBS) $(LINTLIB) + +lint: lintcheck + +FRC: + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/amd64/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/amd64/Makefile new file mode 100644 index 0000000000..aa52c4aefb --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_nss/amd64/Makefile @@ -0,0 +1,32 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include $(SRC)/lib/Makefile.lib.64 + +LDLIBS64 += $(NSSLIBS64) + +install: $(ROOTLIBS64) diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/common/mapfile-vers b/usr/src/lib/libkmf/plugins/kmf_nss/common/mapfile-vers new file mode 100644 index 0000000000..ed84774842 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_nss/common/mapfile-vers @@ -0,0 +1,56 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SUNWprivate_1.1 { + global: + KMF_Plugin_Initialize; + NSS_FindCert; + NSS_FreeKMFCert; + NSS_StoreCert; + NSS_ImportCert; + NSS_ImportCRL; + NSS_DeleteCert; + NSS_DeleteCRL; + NSS_CreateKeypair; + NSS_FindKey; + NSS_EncodePubKeyData; + NSS_SignData; + NSS_DeleteKey; + NSS_FindCRL; + NSS_FindCertInCRL; + NSS_GetErrorString; + NSS_GetPrikeyByCert; + NSS_DecryptData; + NSS_ExportP12; + NSS_StorePrivateKey; + NSS_CreateSymKey; + NSS_GetSymKeyValue; + NSS_SetTokenPin; + + local: + *; +}; diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c b/usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c new file mode 100644 index 0000000000..b23886aaae --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c @@ -0,0 +1,2508 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * NSS keystore wrapper + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <fcntl.h> +#include <synch.h> + +#include <kmfapiP.h> +#include <ber_der.h> +#include <oidsalg.h> +/* NSS related headers */ + +#include <mps/nss.h> +#include <mps/cert.h> +#include <mps/certdb.h> +#include <mps/secoid.h> +#include <mps/secder.h> +#include <mps/secerr.h> +#include <mps/cryptohi.h> +#include <mps/keyhi.h> +#include <mps/keythi.h> +#include <mps/pk11func.h> +#include <mps/pk11pqg.h> +#include <mps/pkcs12.h> +#include <mps/p12plcy.h> +#include <mps/prerror.h> + +#define NSS_OK 0 + +mutex_t init_lock = DEFAULTMUTEX; +static int nss_initialized = 0; + +KMF_RETURN +NSS_ConfigureKeystore(KMF_HANDLE_T, KMF_CONFIG_PARAMS *); + +KMF_RETURN +NSS_FindCert(KMF_HANDLE_T, + KMF_FINDCERT_PARAMS *params, + KMF_X509_DER_CERT *kmf_cert, + uint32_t *num_certs); + +void +NSS_FreeKMFCert(KMF_HANDLE_T, KMF_X509_DER_CERT *); + +KMF_RETURN +NSS_StoreCert(KMF_HANDLE_T, KMF_STORECERT_PARAMS *params, + KMF_DATA * pcert); + +KMF_RETURN +NSS_ImportCert(KMF_HANDLE_T, KMF_IMPORTCERT_PARAMS *params); + +KMF_RETURN +NSS_DeleteCert(KMF_HANDLE_T, KMF_DELETECERT_PARAMS *params); + +KMF_RETURN +NSS_CreateKeypair(KMF_HANDLE_T, KMF_CREATEKEYPAIR_PARAMS *, + KMF_KEY_HANDLE *, KMF_KEY_HANDLE *); + +KMF_RETURN +NSS_EncodePubKeyData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_DATA *); + +KMF_RETURN +NSS_SignData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *, + KMF_DATA *, KMF_DATA *); + +KMF_RETURN +NSS_ImportCRL(KMF_HANDLE_T, KMF_IMPORTCRL_PARAMS *params); + +KMF_RETURN +NSS_DeleteCRL(KMF_HANDLE_T, KMF_DELETECRL_PARAMS *params); + +KMF_RETURN +NSS_FindCRL(KMF_HANDLE_T, KMF_FINDCRL_PARAMS *params, + char **CRLNameList, int *CRLCount); + +KMF_RETURN +NSS_FindKey(KMF_HANDLE_T, KMF_FINDKEY_PARAMS *, + KMF_KEY_HANDLE *, uint32_t *); + +KMF_RETURN +NSS_FindCertInCRL(KMF_HANDLE_T, KMF_FINDCERTINCRL_PARAMS *params); + +KMF_RETURN +NSS_GetErrorString(KMF_HANDLE_T, char **); + +KMF_RETURN +NSS_DeleteKey(KMF_HANDLE_T, KMF_DELETEKEY_PARAMS *, + KMF_KEY_HANDLE *, boolean_t); + +KMF_RETURN +NSS_GetPrikeyByCert(KMF_HANDLE_T, KMF_CRYPTOWITHCERT_PARAMS *, KMF_DATA *, + KMF_KEY_HANDLE *, KMF_KEY_ALG); + +KMF_RETURN +NSS_DecryptData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *, + KMF_DATA *, KMF_DATA *); + +KMF_RETURN +NSS_ExportP12(KMF_HANDLE_T, + KMF_EXPORTP12_PARAMS *, + int, KMF_X509_DER_CERT *, + int, KMF_KEY_HANDLE *, + char *); + +KMF_RETURN +NSS_StorePrivateKey(KMF_HANDLE_T, KMF_STOREKEY_PARAMS *, KMF_RAW_KEY_DATA *); + +KMF_RETURN +NSS_CreateSymKey(KMF_HANDLE_T, KMF_CREATESYMKEY_PARAMS *, KMF_KEY_HANDLE *); + +KMF_RETURN +NSS_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_SYM_KEY *); + +KMF_RETURN +NSS_SetTokenPin(KMF_HANDLE_T, KMF_SETPIN_PARAMS *, KMF_CREDENTIAL *); + +static +KMF_PLUGIN_FUNCLIST nss_plugin_table = +{ + 1, /* Version */ + NSS_ConfigureKeystore, + NSS_FindCert, + NSS_FreeKMFCert, + NSS_StoreCert, + NSS_ImportCert, + NSS_ImportCRL, + NSS_DeleteCert, + NSS_DeleteCRL, + NSS_CreateKeypair, + NSS_FindKey, + NSS_EncodePubKeyData, + NSS_SignData, + NSS_DeleteKey, + NULL /* ListCRL */, + NSS_FindCRL, + NSS_FindCertInCRL, + NSS_GetErrorString, + NSS_GetPrikeyByCert, + NSS_DecryptData, + NSS_ExportP12, + NSS_StorePrivateKey, + NSS_CreateSymKey, + NSS_GetSymKeyValue, + NSS_SetTokenPin, + NULL /* Finalize */ +}; + +/* additions for importing and exporting PKCS 12 files */ +typedef struct p12uContextStr { + char *filename; /* name of file */ + PRFileDesc *file; /* pointer to file */ + PRBool error; /* error occurred? */ + int errorValue; /* which error occurred? */ +} p12uContext; + +#define SET_ERROR(h, c) h->lasterr.kstype = KMF_KEYSTORE_NSS; \ + h->lasterr.errcode = c; + +KMF_PLUGIN_FUNCLIST * +KMF_Plugin_Initialize() +{ + SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1); + SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1); + SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1); + SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1); + SEC_PKCS12EnableCipher(PKCS12_DES_56, 1); + SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1); + SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1); + + return (&nss_plugin_table); +} + +static char * +/*ARGSUSED*/ +nss_getpassword(PK11SlotInfo *slot, PRBool retry, void *arg) +{ + if (retry) + return (NULL); + if (arg != NULL) + return ((char *)strdup(arg)); + else + return (NULL); +} + +static KMF_RETURN +nss_authenticate(KMF_HANDLE_T handle, + PK11SlotInfo *nss_slot, KMF_CREDENTIAL *cred) +{ + + SECStatus nssrv = SECSuccess; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + /* If a password was given, try to login to the slot */ + if (cred == NULL || cred->cred == NULL || cred->credlen == 0 || + nss_slot == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + if (PK11_IsLoggedIn(nss_slot, NULL)) { + return (KMF_OK); + } + + PK11_SetPasswordFunc(nss_getpassword); + nssrv = PK11_Authenticate(nss_slot, PR_TRUE, + (void *)cred->cred); + + if (nssrv != SECSuccess) { + SET_ERROR(kmfh, nssrv); + PK11_FreeSlot(nss_slot); + return (KMF_ERR_AUTH_FAILED); + } + + return (KMF_OK); +} + +static SECStatus +Init_NSS_DBs(const char *configdir, + const char *certPrefix, + const char *keyPrefix, + const char *secmodName) +{ + SECStatus rv = NSS_OK; + + (void) mutex_lock(&init_lock); + + /* If another thread already did it, return OK. */ + if (nss_initialized) { + (void) mutex_unlock(&init_lock); + return (SECSuccess); + } + + rv = NSS_Initialize((configdir && strlen(configdir)) ? + configdir : "./", certPrefix, + keyPrefix, secmodName ? secmodName : "secmod.db", + NSS_INIT_COOPERATE); + if (rv != SECSuccess) { + goto end; + } + + nss_initialized++; +end: + (void) mutex_unlock(&init_lock); + return (rv); +} + +/* + * When it is called the first time, it will intialize NSS. Once the NSS + * is initialized, this function returns KMF_KEYSTORE_ALREADY_INITIALIZED + * if it is called again. + */ +KMF_RETURN +NSS_ConfigureKeystore(KMF_HANDLE_T handle, KMF_CONFIG_PARAMS *params) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + if (params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) mutex_lock(&init_lock); + if (nss_initialized == 0) { + SECStatus err; + + (void) mutex_unlock(&init_lock); + err = Init_NSS_DBs(params->nssconfig.configdir, + params->nssconfig.certPrefix, + params->nssconfig.keyPrefix, + params->nssconfig.secModName); + if (err != SECSuccess) { + SET_ERROR(kmfh, err); + return (KMF_ERR_INTERNAL); + } + } else { + rv = KMF_KEYSTORE_ALREADY_INITIALIZED; + (void) mutex_unlock(&init_lock); + } + + return (rv); +} + + +/* + * This function sets up the slot to be used for other operations. + * This function is basically called by every NSS SPI function. + * For those functions that can only be performed in the internal slot, the + * boolean "internal_slot_only" argument needs to be TRUE. + * A slot pointer will be returned when this function is executed successfully. + */ +static KMF_RETURN +Do_NSS_Init( + void *handle, + KMF_NSS_PARAMS nss_opts, + boolean_t internal_slot_only, + PK11SlotInfo **nss_slot) +{ + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + if (!nss_initialized) + return (KMF_ERR_PLUGIN_INIT); + + /* + * NSS Is already initialized, but we need to find + * the right slot. + */ + if (nss_opts.slotlabel == NULL || + strcmp(nss_opts.slotlabel, "internal") == 0) { + *nss_slot = PK11_GetInternalKeySlot(); + } else if (internal_slot_only == TRUE) { + return (KMF_ERR_SLOTNAME); + } else { + *nss_slot = PK11_FindSlotByName(nss_opts.slotlabel); + } + + if (*nss_slot == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + return (KMF_ERR_SLOTNAME); + } + + /* + * If the token was not yet initialized, return an error. + */ + if (PK11_NeedUserInit(*nss_slot)) { + return (KMF_ERR_UNINITIALIZED_TOKEN); + } + + return (KMF_OK); +} + +static KMF_RETURN +nss2kmf_cert(CERTCertificate *nss_cert, KMF_X509_DER_CERT *kmf_cert) +{ + kmf_cert->kmf_private.keystore_type = KMF_KEYSTORE_NSS; + kmf_cert->kmf_private.flags = KMF_FLAG_CERT_VALID; + + kmf_cert->certificate.Length = nss_cert->derCert.len; + + if ((kmf_cert->certificate.Data = malloc(nss_cert->derCert.len)) == + NULL) { + kmf_cert->certificate.Length = 0; + return (KMF_ERR_MEMORY); + } + (void) memcpy(kmf_cert->certificate.Data, nss_cert->derCert.data, + nss_cert->derCert.len); + if (nss_cert->nickname != NULL) + kmf_cert->kmf_private.label = + (char *)strdup(nss_cert->nickname); + return (KMF_OK); +} + +static KMF_RETURN +nss_getcert_by_label(KMF_HANDLE *kmfh, + char *name, KMF_X509_DER_CERT *kmf_cert, + uint32_t *num_certs, KMF_CERT_VALIDITY find_criteria) +{ + KMF_RETURN rv = KMF_OK; + CERTCertificate *nss_cert; + SECCertTimeValidity validity; + + nss_cert = PK11_FindCertFromNickname(name, NULL); + if (nss_cert == NULL) { + *num_certs = 0; + SET_ERROR(kmfh, PORT_GetError()); + *num_certs = 0; + return (KMF_ERR_CERT_NOT_FOUND); + } else { + *num_certs = 1; + } + + switch (find_criteria) { + case KMF_ALL_CERTS: + break; + case KMF_NONEXPIRED_CERTS: + validity = CERT_CheckCertValidTimes(nss_cert, PR_Now(), + PR_FALSE); + if (validity != secCertTimeValid) { + /* this is an invalid cert, reject it */ + *num_certs = 0; + CERT_DestroyCertificate(nss_cert); + return (KMF_OK); + } + break; + case KMF_EXPIRED_CERTS: + validity = CERT_CheckCertValidTimes(nss_cert, PR_Now(), + PR_FALSE); + if (validity == secCertTimeValid) { + /* this is a valid cert, reject it in this case. */ + *num_certs = 0; + CERT_DestroyCertificate(nss_cert); + return (KMF_OK); + } + break; + default: + return (KMF_ERR_BAD_PARAMETER); + } + + if (kmf_cert != NULL) + rv = nss2kmf_cert(nss_cert, kmf_cert); + + /* We copied the data we need, so cleanup the internal record */ + CERT_DestroyCertificate(nss_cert); + + if (rv != KMF_OK) + *num_certs = 0; + + return (rv); +} + +static KMF_RETURN +nss_find_matching_certs(PK11SlotInfo *slot, + char *issuer, char *subject, KMF_BIGINT *serial, + CERTCertList **certlist, KMF_CERT_VALIDITY find_criteria) +{ + KMF_RETURN rv = KMF_OK; + SECStatus ret; + CERTCertList *list; + CERTCertListNode *node; + KMF_X509_NAME issuerDN, subjectDN; + boolean_t findIssuer = FALSE; + boolean_t findSubject = FALSE; + boolean_t findSerial = FALSE; + + if (issuer != NULL && strlen(issuer)) { + rv = KMF_DNParser(issuer, &issuerDN); + if (rv != KMF_OK) + return (rv); + findIssuer = TRUE; + } + if (subject != NULL && strlen(subject)) { + rv = KMF_DNParser(subject, &subjectDN); + if (rv != KMF_OK) + return (rv); + findSubject = TRUE; + } + if (serial != 0 && serial->val != NULL && serial->len > 0) + findSerial = TRUE; + + list = PK11_ListCertsInSlot(slot); + if (list) { + node = CERT_LIST_HEAD(list); + while (!CERT_LIST_END(node, list)) { + KMF_X509_NAME cmpDN; + KMF_DATA der; + boolean_t match; + CERTCertListNode *freenode; + + if (findIssuer) { + der.Data = node->cert->derIssuer.data; + der.Length = node->cert->derIssuer.len; + rv = DerDecodeName(&der, &cmpDN); + if (rv == KMF_OK) { + match = !KMF_CompareRDNs(&issuerDN, + &cmpDN); + KMF_FreeDN(&cmpDN); + if (!match) + goto delete_and_cont; + } else { + goto delete_and_cont; + } + } + if (findSubject) { + der.Data = node->cert->derSubject.data; + der.Length = node->cert->derSubject.len; + rv = DerDecodeName(&der, &cmpDN); + if (rv == KMF_OK) { + match = !KMF_CompareRDNs(&subjectDN, + &cmpDN); + KMF_FreeDN(&cmpDN); + if (!match) + goto delete_and_cont; + } else { + goto delete_and_cont; + } + } + if (findSerial) { + SECItem *sernum; + + sernum = &node->cert->serialNumber; + + if (serial->len != sernum->len) + goto delete_and_cont; + + if (memcmp(sernum->data, serial->val, + serial->len)) + goto delete_and_cont; + } + + /* select the certs using find criteria */ + switch (find_criteria) { + case KMF_ALL_CERTS: + break; + case KMF_NONEXPIRED_CERTS: + ret = CERT_CertTimesValid(node->cert); + if (ret == SECFailure) { + /* this is an invalid cert */ + goto skip; + } + break; + + case KMF_EXPIRED_CERTS: + ret = CERT_CertTimesValid(node->cert); + if (ret != SECFailure) { + /* this is a valid cert */ + goto skip; + } + break; + } +skip: + node = CERT_LIST_NEXT(node); + continue; +delete_and_cont: + freenode = node; + node = CERT_LIST_NEXT(node); + CERT_RemoveCertListNode(freenode); + } + } + + if (rv == KMF_OK && certlist != NULL) { + *certlist = list; + } else { + CERT_DestroyCertList(list); + } + return (rv); +} + +static KMF_RETURN +convertCertList(void *kmfhandle, + CERTCertList *nsscerts, KMF_X509_DER_CERT *kmfcerts, + uint32_t *numcerts) +{ + KMF_RETURN rv = KMF_OK; + CERTCertListNode *node; + + *numcerts = 0; + + for (node = CERT_LIST_HEAD(nsscerts); + !CERT_LIST_END(node, nsscerts) && rv == KMF_OK; + node = CERT_LIST_NEXT(node), (*numcerts)++) { + if (kmfcerts != NULL) + rv = nss2kmf_cert(node->cert, &kmfcerts[*numcerts]); + } + + /* + * If we failed, delete any certs allocated so far. + */ + if (rv != KMF_OK) { + int i; + for (i = 0; i < *numcerts; i++) + KMF_FreeKMFCert(kmfhandle, &kmfcerts[i]); + } + return (rv); +} + +KMF_RETURN +NSS_FindCert(KMF_HANDLE_T handle, KMF_FINDCERT_PARAMS *params, + KMF_X509_DER_CERT *kmfcerts, + uint32_t *num_certs) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + PK11SlotInfo *nss_slot = NULL; + CERTCertList *certlist = NULL; + + rv = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, FALSE, &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + + *num_certs = 0; + if (params->certLabel) { + rv = nss_getcert_by_label(kmfh, + params->certLabel, + kmfcerts, num_certs, params->find_cert_validity); + } else { + rv = nss_find_matching_certs(nss_slot, + params->issuer, params->subject, params->serial, + &certlist, params->find_cert_validity); + + if (rv == KMF_OK && certlist != NULL) { + rv = convertCertList(handle, + certlist, kmfcerts, num_certs); + CERT_DestroyCertList(certlist); + } + } + + if (nss_slot != NULL) { + PK11_FreeSlot(nss_slot); + } + + if (rv == KMF_OK && *num_certs == 0) + rv = KMF_ERR_CERT_NOT_FOUND; + + return (rv); +} + +void +/*ARGSUSED*/ +NSS_FreeKMFCert(KMF_HANDLE_T handle, + KMF_X509_DER_CERT *kmf_cert) +{ + if (kmf_cert != NULL) { + if (kmf_cert->certificate.Data != NULL) { + free(kmf_cert->certificate.Data); + kmf_cert->certificate.Data = NULL; + kmf_cert->certificate.Length = 0; + } + if (kmf_cert->kmf_private.label != NULL) { + free(kmf_cert->kmf_private.label); + kmf_cert->kmf_private.label = NULL; + } + } +} + +KMF_RETURN +NSS_StoreCert(KMF_HANDLE_T handle, KMF_STORECERT_PARAMS *params, + KMF_DATA *pcert) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + SECStatus nss_rv; + CERTCertificate *nss_cert = NULL; + CERTCertTrust *nss_trust = NULL; + PK11SlotInfo *nss_slot = NULL; + CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB(); + + if (pcert == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* NSS only support DER format */ + if (params == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + ret = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, FALSE, &nss_slot); + if (ret != KMF_OK) { + return (ret); + } + + nss_cert = CERT_DecodeCertFromPackage((char *)pcert->Data, + pcert->Length); + if (nss_cert == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + ret = KMF_ERR_BAD_CERT_FORMAT; + goto out; + } + + nss_rv = PK11_ImportCert(nss_slot, nss_cert, CK_INVALID_HANDLE, + params->certLabel, 0); + if (nss_rv) { + SET_ERROR(kmfh, nss_rv); + ret = KMF_ERR_BAD_CERT_FORMAT; + goto out; + } + + if (params->ks_opt_u.nss_opts.trustflag != NULL && + strlen(params->ks_opt_u.nss_opts.trustflag)) { + nss_trust = (CERTCertTrust *) malloc(sizeof (CERTCertTrust)); + if (nss_trust == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + nss_rv = CERT_DecodeTrustString(nss_trust, + params->ks_opt_u.nss_opts.trustflag); + if (nss_rv) { + SET_ERROR(kmfh, nss_rv); + ret = KMF_ERR_BAD_PARAMETER; + goto out; + } + + nss_rv = CERT_ChangeCertTrust(certHandle, nss_cert, nss_trust); + if (nss_rv) { + SET_ERROR(kmfh, nss_rv); + ret = KMF_ERR_BAD_PARAMETER; + } + } + +out: + if (nss_trust != NULL) { + free(nss_trust); + } + + if (nss_cert != NULL) { + CERT_DestroyCertificate(nss_cert); + } + + if (nss_slot != NULL) { + PK11_FreeSlot(nss_slot); + } + + return (ret); +} + + +KMF_RETURN +NSS_ImportCert(KMF_HANDLE_T handle, KMF_IMPORTCERT_PARAMS *params) +{ + KMF_RETURN ret = KMF_OK; + KMF_STORECERT_PARAMS scparams; + KMF_DATA cert = {NULL, 0}; + KMF_DATA cert_der = {NULL, 0}; + KMF_DATA *cptr = NULL; + KMF_ENCODE_FORMAT format; + + if (params == NULL || params->certfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* + * Check if the input cert file is a valid certificate and + * auto-detect the file format of it. + */ + ret = KMF_IsCertFile(handle, params->certfile, &format); + if (ret != KMF_OK) + return (ret); + + ret = KMF_ReadInputFile(handle, params->certfile, &cert); + if (ret != KMF_OK) { + return (ret); + } + + /* + * If the imported cert is in PEM format, convert it to + * DER format in order to store it in NSS token. + */ + if (format == KMF_FORMAT_PEM) { + int derlen; + ret = KMF_Pem2Der(cert.Data, cert.Length, + &cert_der.Data, &derlen); + if (ret != KMF_OK) { + goto cleanup; + } + cert_der.Length = (size_t)derlen; + cptr = &cert_der; + } else { + cptr = &cert; + } + + (void) memset(&scparams, 0, sizeof (scparams)); + scparams.kstype = params->kstype; + scparams.certLabel = params->certLabel; + scparams.nssparms = params->nssparms; + + ret = NSS_StoreCert(handle, &scparams, cptr); + + if (format == KMF_FORMAT_PEM) { + KMF_FreeData(&cert_der); + } + +cleanup: + KMF_FreeData(&cert); + + return (ret); +} + +KMF_RETURN +NSS_DeleteCert(KMF_HANDLE_T handle, KMF_DELETECERT_PARAMS *params) +{ + KMF_RETURN rv = KMF_OK; + int nssrv; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CERTCertificate *cert = NULL; + PK11SlotInfo *nss_slot = NULL; + + /* check params */ + if (params == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + rv = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, + FALSE, &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + + if (params->certLabel) { + cert = PK11_FindCertFromNickname(params->certLabel, NULL); + if (cert == NULL) { + return (KMF_ERR_CERT_NOT_FOUND); + } + + switch (params->find_cert_validity) { + case KMF_ALL_CERTS: + break; + case KMF_NONEXPIRED_CERTS: + nssrv = CERT_CertTimesValid(cert); + if (nssrv == SECFailure) { + /* this is an invalid cert - skip it */ + goto out; + } + break; + case KMF_EXPIRED_CERTS: + nssrv = CERT_CertTimesValid(cert); + if (nssrv != SECFailure) { + /* this is a valid cert - skip it */ + goto out; + } + break; + } + /* delete it from database */ + nssrv = SEC_DeletePermCertificate(cert); + if (nssrv) { + SET_ERROR(kmfh, nssrv); + rv = KMF_ERR_INTERNAL; + } + } else { + CERTCertListNode *node; + CERTCertList *certlist = NULL; + + rv = nss_find_matching_certs(nss_slot, + params->issuer, params->subject, params->serial, + &certlist, params->find_cert_validity); + + for (node = CERT_LIST_HEAD(certlist); + !CERT_LIST_END(node, certlist) && rv == KMF_OK; + node = CERT_LIST_NEXT(node)) { + + nssrv = SEC_DeletePermCertificate(node->cert); + if (nssrv) { + SET_ERROR(kmfh, nssrv); + rv = KMF_ERR_INTERNAL; + } + } + + if (rv == KMF_OK && certlist != NULL) { + CERT_DestroyCertList(certlist); + } else if (rv == KMF_OK && certlist == NULL) { + rv = KMF_ERR_CERT_NOT_FOUND; + } + } +out: + if (nss_slot != NULL) { + PK11_FreeSlot(nss_slot); + } + + if (cert != NULL) { + CERT_DestroyCertificate(cert); + } + + return (rv); +} + +static void +InitRandom(char *filename) +{ + char buf[2048]; + int fd; + PRInt32 count; + + fd = open(filename, O_RDONLY); + if (!fd) + return; + + count = read(fd, buf, sizeof (buf)); + if (count > 0) { + PK11_RandomUpdate(buf, count); + } + + (void) close(fd); +} + +KMF_RETURN +NSS_CreateKeypair(KMF_HANDLE_T handle, + KMF_CREATEKEYPAIR_PARAMS *params, + KMF_KEY_HANDLE *privkey, + KMF_KEY_HANDLE *pubkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + PK11RSAGenParams rsaparams; + void *nssparams; + CK_MECHANISM_TYPE mechanism; + ulong_t publicExponent = 0x010001; + PK11SlotInfo *nss_slot = NULL; + SECKEYPrivateKey *NSSprivkey = NULL; + SECKEYPublicKey *NSSpubkey = NULL; + PQGParams *pqgParams = NULL; + + + if (params == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + rv = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, FALSE, &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + + rv = nss_authenticate(handle, nss_slot, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + /* Get some random bits */ + InitRandom("/dev/urandom"); + if (params->keytype == KMF_RSA) { + rsaparams.keySizeInBits = params->keylength; + /* + * NSS only allows for a 4 byte exponent. + * Ignore the exponent parameter if it is too big. + */ + if (params->rsa_exponent.len > 0 && + params->rsa_exponent.len <= sizeof (publicExponent) && + params->rsa_exponent.val != NULL) { + (void) memcpy(&publicExponent, + params->rsa_exponent.val, + params->rsa_exponent.len); + } + rsaparams.pe = publicExponent; + mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + nssparams = &rsaparams; + } else if (params->keytype == KMF_DSA) { + PQGVerify *pqgVerify = NULL; + int ks; + SECStatus nssrv, passed; + + mechanism = CKM_DSA_KEY_PAIR_GEN; + + ks = PQG_PBITS_TO_INDEX(params->keylength); + nssrv = PK11_PQG_ParamGen(ks, &pqgParams, &pqgVerify); + if (nssrv != SECSuccess) { + SET_ERROR(kmfh, rv); + PK11_PQG_DestroyVerify(pqgVerify); + rv = KMF_ERR_KEYGEN_FAILED; + goto cleanup; + } + + nssrv = PK11_PQG_VerifyParams(pqgParams, pqgVerify, &passed); + if (nssrv != SECSuccess || passed != SECSuccess) { + SET_ERROR(kmfh, rv); + rv = KMF_ERR_KEYGEN_FAILED; + } + + PK11_PQG_DestroyVerify(pqgVerify); + + if (rv != KMF_OK) { + SET_ERROR(kmfh, PORT_GetError()); + goto cleanup; + } + + nssparams = pqgParams; + } else { + rv = KMF_ERR_BAD_PARAMETER; + goto cleanup; + } + + NSSprivkey = PK11_GenerateKeyPair(nss_slot, + mechanism, nssparams, &NSSpubkey, + PR_TRUE, /* isPermanent */ + PR_TRUE, /* isSensitive */ + (void *)params->cred.cred); + + if (NSSprivkey == NULL || NSSpubkey == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_KEYGEN_FAILED; + } else { + if (params->keylabel != NULL && + strlen(params->keylabel)) { + (void) PK11_SetPrivateKeyNickname(NSSprivkey, + params->keylabel); + (void) PK11_SetPublicKeyNickname(NSSpubkey, + params->keylabel); + } + /* Now, convert it to a KMF_KEY object for the framework */ + if (privkey != NULL) { + privkey->kstype = KMF_KEYSTORE_NSS; + privkey->keyalg = params->keytype; + privkey->keyclass = KMF_ASYM_PRI; + privkey->keylabel = + PK11_GetPrivateKeyNickname(NSSprivkey); + privkey->keyp = (void *)NSSprivkey; + } + if (pubkey != NULL) { + pubkey->kstype = KMF_KEYSTORE_NSS; + pubkey->keyalg = params->keytype; + pubkey->keyp = (void *)NSSpubkey; + pubkey->keyclass = KMF_ASYM_PUB; + pubkey->keylabel = + PK11_GetPublicKeyNickname(NSSpubkey); + } + rv = KMF_OK; + } +cleanup: + if (rv != KMF_OK) { + if (NSSpubkey) + PK11_DeleteTokenPublicKey(NSSpubkey); + if (NSSprivkey) + PK11_DeleteTokenPrivateKey(NSSprivkey, PR_TRUE); + + privkey->keyp = NULL; + pubkey->keyp = NULL; + } + + if (pqgParams != NULL) + PK11_PQG_DestroyParams(pqgParams); + + + if (nss_slot != NULL) + PK11_FreeSlot(nss_slot); + + return (rv); +} + +KMF_RETURN +NSS_SignData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key, + KMF_OID *AlgOID, KMF_DATA *tobesigned, + KMF_DATA *output) +{ + KMF_RETURN ret = KMF_OK; + KMF_ALGORITHM_INDEX AlgId; + SECOidTag signAlgTag; + SECKEYPrivateKey *NSSprivkey = NULL; + SECStatus rv; + SECItem signed_data; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + signed_data.data = 0; + if (key == NULL || AlgOID == NULL || + tobesigned == NULL || output == NULL || + tobesigned->Data == NULL || + output->Data == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* Map the OID to a NSS algorithm */ + AlgId = X509_AlgorithmOidToAlgId(AlgOID); + if (AlgId == KMF_ALGID_NONE) + return (KMF_ERR_BAD_PARAMETER); + + NSSprivkey = (SECKEYPrivateKey *)key->keyp; + + if (AlgId == KMF_ALGID_MD5WithRSA) + signAlgTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; + else if (AlgId == KMF_ALGID_MD2WithRSA) + signAlgTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION; + else if (AlgId == KMF_ALGID_SHA1WithRSA) + signAlgTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; + else if (AlgId == KMF_ALGID_SHA1WithDSA) + signAlgTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; + else + return (KMF_ERR_BAD_PARAMETER); + + rv = SEC_SignData(&signed_data, tobesigned->Data, + tobesigned->Length, NSSprivkey, signAlgTag); + + if (rv != 0) { + SET_ERROR(kmfh, rv); + return (KMF_ERR_INTERNAL); + } + + if (signed_data.len <= output->Length) { + (void) memcpy(output->Data, signed_data.data, signed_data.len); + output->Length = signed_data.len; + } else { + output->Length = 0; + ret = KMF_ERR_BAD_PARAMETER; + } + free(signed_data.data); + + return (ret); +} + +KMF_RETURN +NSS_EncodePubKeyData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *keyp, + KMF_DATA *encoded) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + SECItem *rvitem; + CERTSubjectPublicKeyInfo *spki = NULL; + + if (keyp == NULL || encoded == NULL || keyp->keyp == NULL) + return (KMF_ERR_BAD_PARAMETER); + + spki = SECKEY_CreateSubjectPublicKeyInfo(keyp->keyp); + if (spki == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + return (KMF_ERR_MEMORY); + } + + rvitem = SEC_ASN1EncodeItem(NULL, NULL, spki, + CERT_SubjectPublicKeyInfoTemplate); + + if (rvitem != NULL) { + encoded->Data = malloc(rvitem->len); + if (encoded->Data == NULL) { + ret = KMF_ERR_MEMORY; + } else { + (void) memcpy(encoded->Data, rvitem->data, rvitem->len); + encoded->Length = rvitem->len; + } + SECITEM_FreeItem(rvitem, TRUE); + } else { + SET_ERROR(kmfh, PORT_GetError()); + encoded->Data = NULL; + encoded->Length = 0; + ret = KMF_ERR_ENCODING; + } + SECKEY_DestroySubjectPublicKeyInfo(spki); + + return (ret); +} + +KMF_RETURN +NSS_DeleteKey(KMF_HANDLE_T handle, KMF_DELETEKEY_PARAMS *params, + KMF_KEY_HANDLE *key, boolean_t delete_token) +{ + KMF_RETURN rv = KMF_OK; + PK11SlotInfo *nss_slot = NULL; + + /* + * "delete_token" means to clear it from the token storage as well + * as from memory. + */ + if (key == NULL || key->keyp == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (delete_token) { + SECStatus nssrv = SECSuccess; + if (key->keyclass != KMF_ASYM_PUB && + key->keyclass != KMF_ASYM_PRI && + key->keyclass != KMF_SYMMETRIC) + return (KMF_ERR_BAD_KEY_CLASS); + + if (params == NULL) + return (KMF_ERR_BAD_PARAMETER); + rv = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, FALSE, &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + rv = nss_authenticate(handle, nss_slot, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + if (key->keyclass == KMF_ASYM_PUB) { + nssrv = PK11_DeleteTokenPublicKey( + (SECKEYPublicKey *)key->keyp); + } else if (key->keyclass == KMF_ASYM_PRI) { + nssrv = PK11_DeleteTokenPrivateKey( + (SECKEYPrivateKey *)key->keyp, PR_TRUE); + } else if (key->keyclass == KMF_SYMMETRIC) { + nssrv = PK11_DeleteTokenSymKey( + (PK11SymKey *) key->keyp); + if (nssrv == SECSuccess) + PK11_FreeSymKey( + (PK11SymKey *) key->keyp); + } + if (nssrv != SECSuccess) { + SET_ERROR(handle, PORT_GetError()); + rv = KMF_ERR_INTERNAL; + } + } else { + if (key->keyclass == KMF_ASYM_PUB) { + SECKEY_DestroyPublicKey((SECKEYPublicKey *)key->keyp); + } else if (key->keyclass == KMF_ASYM_PRI) { + SECKEY_DestroyPrivateKey((SECKEYPrivateKey *)key->keyp); + } else if (key->keyclass == KMF_SYMMETRIC) { + PK11_FreeSymKey((PK11SymKey *) key->keyp); + } else { + return (KMF_ERR_BAD_KEY_CLASS); + } + } + key->keyp = NULL; + + return (rv); +} + +KMF_RETURN +NSS_ImportCRL(KMF_HANDLE_T handle, KMF_IMPORTCRL_PARAMS *params) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + PK11SlotInfo *nss_slot = NULL; + CERTSignedCrl *nss_crl = NULL; + KMF_ENCODE_FORMAT format; + int importOptions; + SECItem crlDER; + KMF_DATA crl1; + KMF_DATA crl2; + + if (params == NULL || params->ks_opt_u.nss_opts.crlfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* + * Check if the input CRL file is a valid CRL file and auto-detect + * the encoded format of the file. + */ + ret = KMF_IsCRLFile(handle, params->ks_opt_u.nss_opts.crlfile, + &format); + if (ret != KMF_OK) + return (ret); + + ret = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, TRUE, &nss_slot); + if (ret != KMF_OK) { + return (ret); + } + + /* set importOptions */ + if (params->ks_opt_u.nss_opts.crl_check == B_FALSE) { + importOptions = CRL_IMPORT_DEFAULT_OPTIONS | + CRL_IMPORT_BYPASS_CHECKS; + } else { + importOptions = CRL_IMPORT_DEFAULT_OPTIONS; + } + + + /* Read in the CRL file */ + crl1.Data = NULL; + crl2.Data = NULL; + ret = KMF_ReadInputFile(handle, params->ks_opt_u.nss_opts.crlfile, + &crl1); + if (ret != KMF_OK) { + return (ret); + } + + /* If the input CRL is in PEM format, convert it to DER first. */ + if (format == KMF_FORMAT_PEM) { + int len; + ret = KMF_Pem2Der(crl1.Data, crl1.Length, + &crl2.Data, &len); + if (ret != KMF_OK) { + goto out; + } + crl2.Length = (size_t)len; + } + + crlDER.data = format == KMF_FORMAT_ASN1 ? crl1.Data : crl2.Data; + crlDER.len = format == KMF_FORMAT_ASN1 ? crl1.Length : crl2.Length; + + nss_crl = PK11_ImportCRL(nss_slot, &crlDER, NULL, SEC_CRL_TYPE, + NULL, importOptions, NULL, CRL_DECODE_DEFAULT_OPTIONS); + + if (nss_crl == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + ret = KMF_ERR_BAD_CRLFILE; + goto out; + } + +out: + if (nss_slot != NULL) { + PK11_FreeSlot(nss_slot); + } + + if (crl1.Data != NULL) { + free(crl1.Data); + } + + if (crl2.Data != NULL) { + free(crl2.Data); + } + + if (nss_crl != NULL) { + SEC_DestroyCrl(nss_crl); + } + + return (ret); +} + +KMF_RETURN +NSS_DeleteCRL(KMF_HANDLE_T handle, KMF_DELETECRL_PARAMS *params) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CERTSignedCrl *crl = NULL; + CERTCertificate *cert = NULL; + PK11SlotInfo *nss_slot = NULL; + CERTCrlHeadNode *crlList = NULL; + CERTCrlNode *crlNode = NULL; + PRArenaPool *arena = NULL; + CERTName *name = NULL; + CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB(); + + /* check params */ + if (params == NULL || + (params->ks_opt_u.nss_opts.crl_issuerName == NULL && + params->ks_opt_u.nss_opts.crl_subjName == NULL) || + (params->ks_opt_u.nss_opts.crl_issuerName != NULL && + params->ks_opt_u.nss_opts.crl_subjName != NULL)) { + return (KMF_ERR_BAD_PARAMETER); + } + + rv = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, TRUE, + &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + + /* Find the CRL based on the deletion criteria. */ + if (params->ks_opt_u.nss_opts.crl_issuerName != NULL) { + /* + * If the deletion is based on the issuer's certificate + * nickname, we will get the issuer's cert first, then + * get the CRL from the cert. + */ + cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, + params->ks_opt_u.nss_opts.crl_issuerName); + if (!cert) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CERT_NOT_FOUND; + goto out; + } + + crl = SEC_FindCrlByName(certHandle, &cert->derSubject, + SEC_CRL_TYPE); + if (crl == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CRL_NOT_FOUND; + goto out; + } + } else { + /* + * If the deletion is based on the CRL's subject name, we will + * get all the CRLs from the internal database and search + * for the CRL with the same subject name. + */ + boolean_t found = B_FALSE; + int nssrv; + + nssrv = SEC_LookupCrls(certHandle, &crlList, SEC_CRL_TYPE); + if (nssrv) { + SET_ERROR(kmfh, nssrv); + rv = KMF_ERR_CRL_NOT_FOUND; + goto out; + } + + if (crlList == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CRL_NOT_FOUND; + goto out; + } + + /* Allocate space for name */ + arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); + if (arena == NULL) { + rv = KMF_ERR_MEMORY; + goto out; + } + + name = PORT_ArenaZAlloc(arena, sizeof (*name)); + if (name == NULL) { + rv = KMF_ERR_MEMORY; + goto out; + } + name->arena = arena; + + crlNode = crlList->first; + while (crlNode && !found) { + char *asciiname = NULL; + SECItem* issuer; + + name = &crlNode->crl->crl.name; + if (!name) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CRL_NOT_FOUND; + break; + } + + asciiname = CERT_NameToAscii(name); + if (asciiname == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CRL_NOT_FOUND; + break; + } + + if (strcmp(params->ks_opt_u.nss_opts.crl_subjName, + asciiname) == 0) { + found = B_TRUE; + issuer = &crlNode->crl->crl.derName; + crl = SEC_FindCrlByName(certHandle, issuer, + SEC_CRL_TYPE); + if (crl == NULL) { + /* We found a cert but no CRL */ + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CRL_NOT_FOUND; + } + } + PORT_Free(asciiname); + crlNode = crlNode->next; + } + + if (rv) { + goto out; + } + } + + if (crl) { + (void) SEC_DeletePermCRL(crl); + } + +out: + if (nss_slot != NULL) { + PK11_FreeSlot(nss_slot); + } + + if (crlList != NULL) { + PORT_FreeArena(crlList->arena, PR_FALSE); + } + + if (arena != NULL) { + PORT_FreeArena(arena, PR_FALSE); + } + + if (cert != NULL) { + CERT_DestroyCertificate(cert); + } + + if (crl != NULL) { + SEC_DestroyCrl(crl); + } + + return (rv); +} + + +KMF_RETURN +NSS_FindCRL(KMF_HANDLE_T handle, KMF_FINDCRL_PARAMS *params, + char **CRLNameList, int *CRLCount) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + PK11SlotInfo *nss_slot = NULL; + CERTCrlHeadNode *crlList = NULL; + CERTCrlNode *crlNode = NULL; + PRArenaPool *arena = NULL; + CERTName *name = NULL; + SECStatus nssrv; + char *asciiname = NULL; + int crl_num; + int i; + CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB(); + + if (CRLCount == NULL || params == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + *CRLCount = 0; + + rv = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, TRUE, &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + + /* Look up Crls */ + nssrv = SEC_LookupCrls(certHandle, &crlList, SEC_CRL_TYPE); + if (nssrv) { + SET_ERROR(kmfh, rv); + rv = KMF_ERR_CRL_NOT_FOUND; + goto out; + } + + /* Allocate space for name first */ + arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); + if (arena == NULL) { + rv = KMF_ERR_MEMORY; + goto out; + } + + name = PORT_ArenaZAlloc(arena, sizeof (*name)); + if (name == NULL) { + rv = KMF_ERR_MEMORY; + goto out; + } + name->arena = arena; + + /* + * Loop thru the crlList and create a crl list with CRL's subject name. + */ + crlNode = crlList->first; + crl_num = 0; + while (crlNode) { + char *subj_name; + + /* Get the CRL subject name */ + name = &crlNode->crl->crl.name; + if (!name) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CRL_NOT_FOUND; + break; + } + + + if (CRLNameList != NULL) { + asciiname = CERT_NameToAscii(name); + if (asciiname == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CRL_NOT_FOUND; + break; + } + subj_name = strdup(asciiname); + PORT_Free(asciiname); + if (subj_name == NULL) { + rv = KMF_ERR_MEMORY; + break; + } + CRLNameList[crl_num] = subj_name; + } + + crl_num++; + crlNode = crlNode->next; + } + + if (rv == KMF_OK) { + /* success */ + *CRLCount = crl_num; + } + +out: + if (nss_slot != NULL) { + PK11_FreeSlot(nss_slot); + } + + if (crlList != NULL) { + PORT_FreeArena(crlList->arena, PR_FALSE); + } + + if (arena != NULL) { + PORT_FreeArena(arena, PR_FALSE); + } + + /* If failed, free memory allocated for the returning rlist */ + if (rv && (CRLNameList != NULL)) { + for (i = 0; i < crl_num; i++) { + free(CRLNameList[i]); + } + } + + return (rv); +} + + +KMF_RETURN +NSS_FindCertInCRL(KMF_HANDLE_T handle, KMF_FINDCERTINCRL_PARAMS *params) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + PK11SlotInfo *nss_slot = NULL; + CERTCertificate *cert = NULL; + CERTSignedCrl *crl = NULL; + CERTCrlEntry *entry; + boolean_t match = B_FALSE; + int i; + CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB(); + + /* check params */ + if (params == NULL || params->certLabel == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + rv = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, TRUE, &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + + cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, + params->certLabel); + if (!cert) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CERT_NOT_FOUND; + goto out; + } + + /* Find the CRL with the same issuer as the given certificate. */ + crl = SEC_FindCrlByName(certHandle, &cert->derIssuer, SEC_CRL_TYPE); + if (crl == NULL) { + /* + * Could not find the CRL issued by the same issuer. This + * usually means that the CRL is not installed in the DB. + */ + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CRL_NOT_FOUND; + goto out; + + } + + /* Check if the certificate's serialNumber is revoked in the CRL */ + i = 0; + while ((entry = (crl->crl).entries[i++]) != NULL) { + if (SECITEM_CompareItem(&(cert->serialNumber), + &(entry->serialNumber)) == SECEqual) { + match = B_TRUE; + break; + } + } + + if (!match) { + rv = KMF_ERR_NOT_REVOKED; + } + +out: + if (nss_slot != NULL) { + PK11_FreeSlot(nss_slot); + } + + if (cert != NULL) { + CERT_DestroyCertificate(cert); + } + + if (crl != NULL) { + SEC_DestroyCrl(crl); + } + + return (rv); +} + +KMF_RETURN +NSS_GetErrorString(KMF_HANDLE_T handle, char **msgstr) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + char *str; + + /* Get the error string in the default language */ + str = (char *)PR_ErrorToName((PRErrorCode)kmfh->lasterr.errcode); + + if (str != NULL) { + *msgstr = (char *)strdup(str); + if ((*msgstr) == NULL) + ret = KMF_ERR_MEMORY; + } else { + *msgstr = NULL; + } + + return (ret); +} + +KMF_RETURN +NSS_GetPrikeyByCert(KMF_HANDLE_T handle, KMF_CRYPTOWITHCERT_PARAMS *params, + KMF_DATA *SignerCertData, KMF_KEY_HANDLE *key, + KMF_KEY_ALG keytype) +{ + CERTCertificate *nss_cert = NULL; + SECKEYPrivateKey* privkey = NULL; + PK11SlotInfo *nss_slot = NULL; + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + rv = Do_NSS_Init(handle, + params->nssparms, FALSE, &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + + rv = nss_authenticate(handle, nss_slot, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + nss_cert = CERT_DecodeCertFromPackage((char *)SignerCertData->Data, + SignerCertData->Length); + + if (nss_cert == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + return (KMF_ERR_BAD_CERT_FORMAT); + } + + privkey = PK11_FindPrivateKeyFromCert(nss_slot, nss_cert, NULL); + if (privkey == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + return (KMF_ERR_KEY_NOT_FOUND); + } + + key->kstype = KMF_KEYSTORE_NSS; + key->keyclass = KMF_ASYM_PRI; + key->keyalg = keytype; + key->keyp = (void *)privkey; + key->keylabel = PK11_GetPrivateKeyNickname(privkey); + + CERT_DestroyCertificate(nss_cert); + + return (KMF_OK); + +} + +KMF_RETURN +NSS_DecryptData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key, + KMF_OID *AlgOID, KMF_DATA *ciphertext, + KMF_DATA *output) +{ + KMF_RETURN ret = KMF_OK; + SECKEYPrivateKey *NSSprivkey = NULL; + SECStatus rv; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + unsigned int in_len = 0, out_len = 0; + unsigned int total_decrypted = 0, modulus_len = 0; + uint8_t *in_data, *out_data; + int i, blocks; + + + if (key == NULL || AlgOID == NULL || + ciphertext == NULL || output == NULL || + ciphertext->Data == NULL || + output->Data == NULL) + return (KMF_ERR_BAD_PARAMETER); + + NSSprivkey = (SECKEYPrivateKey *)key->keyp; + modulus_len = PK11_GetPrivateModulusLen(NSSprivkey); + + blocks = ciphertext->Length/modulus_len; + out_data = output->Data; + in_data = ciphertext->Data; + out_len = modulus_len - 11; + in_len = modulus_len; + + for (i = 0; i < blocks; i++) { + rv = PK11_PrivDecryptPKCS1(NSSprivkey, out_data, + &out_len, ciphertext->Length, in_data, in_len); + + if (rv != 0) { + SET_ERROR(kmfh, rv); + return (KMF_ERR_INTERNAL); + } + + out_data += out_len; + total_decrypted += out_len; + in_data += in_len; + } + + output->Length = total_decrypted; + + return (ret); +} + +static KMF_KEY_ALG +pk11keytype2kmf(CK_KEY_TYPE type) +{ + switch (type) { + case CKK_RSA: + return (KMF_RSA); + case CKK_DSA: + return (KMF_RSA); + case CKK_AES: + return (KMF_AES); + case CKK_RC4: + return (KMF_RC4); + case CKK_DES: + return (KMF_DES); + case CKK_DES3: + return (KMF_DES3); + default: + /* not supported */ + return (KMF_KEYALG_NONE); + } +} + +KMF_RETURN +NSS_FindKey(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS *parms, + KMF_KEY_HANDLE *keys, uint32_t *numkeys) +{ + KMF_RETURN rv; + SECKEYPrivateKeyList *prilist; + SECKEYPrivateKeyListNode *prinode; + SECKEYPublicKeyList *publist; + SECKEYPublicKeyListNode *pubnode; + PK11SlotInfo *nss_slot = NULL; + PK11SymKey *symlist; + int count; + + if (handle == NULL || parms == NULL || numkeys == NULL) + return (KMF_ERR_BAD_PARAMETER); + + rv = Do_NSS_Init(handle, + parms->ks_opt_u.nss_opts, FALSE, &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + + rv = nss_authenticate(handle, nss_slot, &parms->cred); + if (rv != KMF_OK) { + return (rv); + } + + *numkeys = 0; + if (parms->keyclass == KMF_ASYM_PUB) { + publist = PK11_ListPublicKeysInSlot(nss_slot, parms->findLabel); + if (publist == NULL) { + rv = KMF_ERR_KEY_NOT_FOUND; + goto cleanup; + } + } else if (parms->keyclass == KMF_ASYM_PRI) { + prilist = PK11_ListPrivKeysInSlot(nss_slot, + parms->findLabel, NULL); + if (prilist == NULL) { + rv = KMF_ERR_KEY_NOT_FOUND; + goto cleanup; + } + } else if (parms->keyclass == KMF_SYMMETRIC) { + symlist = PK11_ListFixedKeysInSlot(nss_slot, parms->findLabel, + NULL); + if (symlist == NULL) { + rv = KMF_ERR_KEY_NOT_FOUND; + goto cleanup; + } + } else { + rv = KMF_ERR_BAD_KEY_CLASS; + goto cleanup; + } + + if (parms->keyclass == KMF_ASYM_PUB) { + for (count = 0, pubnode = PUBKEY_LIST_HEAD(publist); + !PUBKEY_LIST_END(pubnode, publist); + pubnode = PUBKEY_LIST_NEXT(pubnode), count++) { + if (keys != NULL) { + keys[count].kstype = KMF_KEYSTORE_NSS; + keys[count].keyclass = KMF_ASYM_PUB; + keys[count].keyp = (void *)pubnode->key; + keys[count].keylabel = + PK11_GetPublicKeyNickname( + pubnode->key); + + if (pubnode->key->keyType == rsaKey) + keys[count].keyalg = KMF_RSA; + else if (pubnode->key->keyType == dsaKey) + keys[count].keyalg = KMF_DSA; + } + } + *numkeys = count; + } else if (parms->keyclass == KMF_ASYM_PRI) { + for (count = 0, prinode = PRIVKEY_LIST_HEAD(prilist); + !PRIVKEY_LIST_END(prinode, prilist); + prinode = PRIVKEY_LIST_NEXT(prinode), count++) { + if (keys != NULL) { + keys[count].kstype = KMF_KEYSTORE_NSS; + keys[count].keyclass = KMF_ASYM_PRI; + keys[count].keyp = (void *)prinode->key; + keys[count].keylabel = + PK11_GetPrivateKeyNickname( + prinode->key); + + if (prinode->key->keyType == rsaKey) + keys[count].keyalg = KMF_RSA; + else if (prinode->key->keyType == dsaKey) + keys[count].keyalg = KMF_DSA; + } + } + *numkeys = count; + } else if (parms->keyclass == KMF_SYMMETRIC) { + count = 0; + while (symlist) { + PK11SymKey *symkey = symlist; + CK_KEY_TYPE type; + KMF_KEY_ALG keyalg; + + type = PK11_GetSymKeyType(symkey); + keyalg = pk11keytype2kmf(type); + + /* + * If keytype is specified in the searching parameter, + * check the keytype and skip the key if its keytype + * doesn't match. + */ + symlist = PK11_GetNextSymKey(symkey); + if (parms->keytype != KMF_KEYALG_NONE && + parms->keytype != keyalg) { + continue; + } + + if (keys != NULL) { + keys[count].kstype = KMF_KEYSTORE_NSS; + keys[count].keyclass = KMF_SYMMETRIC; + keys[count].keyp = (void *) symkey; + keys[count].keylabel = + PK11_GetSymKeyNickname(symkey); + keys[count].keyalg = keyalg; + } else { + PK11_FreeSymKey(symkey); + } + count++; + } + *numkeys = count; + } + +cleanup: + if (nss_slot != NULL) { + PK11_FreeSlot(nss_slot); + } + + return (rv); +} + +static SECStatus +p12u_SwapUnicodeBytes(SECItem *uniItem) +{ + unsigned int i; + unsigned char a; + if ((uniItem == NULL) || (uniItem->len % 2)) { + return (SECFailure); + } + for (i = 0; i < uniItem->len; i += 2) { + a = uniItem->data[i]; + uniItem->data[i] = uniItem->data[i+1]; + uniItem->data[i+1] = a; + } + return (SECSuccess); +} + +static PRBool +p12u_ucs2_ascii_conversion_function( + PRBool toUnicode, + unsigned char *inBuf, + unsigned int inBufLen, + unsigned char *outBuf, + unsigned int maxOutBufLen, + unsigned int *outBufLen, + PRBool swapBytes) +{ + SECItem it = { 0 }; + SECItem *dup = NULL; + PRBool ret; + + it.data = inBuf; + it.len = inBufLen; + dup = SECITEM_DupItem(&it); + /* + * If converting Unicode to ASCII, swap bytes before conversion + * as neccessary. + */ + if (!toUnicode && swapBytes) { + if (p12u_SwapUnicodeBytes(dup) != SECSuccess) { + SECITEM_ZfreeItem(dup, PR_TRUE); + return (PR_FALSE); + } + } + /* Perform the conversion. */ + ret = PORT_UCS2_UTF8Conversion(toUnicode, dup->data, dup->len, + outBuf, maxOutBufLen, outBufLen); + if (dup) + SECITEM_ZfreeItem(dup, PR_TRUE); + + return (ret); +} + +static PRBool +p12u_OpenFile(p12uContext *p12ctx, PRBool fileRead) +{ + if (!p12ctx || !p12ctx->filename) { + return (PR_FALSE); + } + + if (fileRead) { + p12ctx->file = PR_Open(p12ctx->filename, + PR_RDONLY, 0400); + } else { + p12ctx->file = PR_Open(p12ctx->filename, + PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, 0600); + } + + if (!p12ctx->file) { + p12ctx->error = PR_TRUE; + return (PR_FALSE); + } + + return (PR_TRUE); +} + +static void +p12u_DestroyContext(p12uContext **ppCtx, PRBool removeFile) +{ + if (!ppCtx || !(*ppCtx)) { + return; + } + + if ((*ppCtx)->file != NULL) { + PR_Close((*ppCtx)->file); + } + + if ((*ppCtx)->filename != NULL) { + if (removeFile) { + PR_Delete((*ppCtx)->filename); + } + free((*ppCtx)->filename); + } + + free(*ppCtx); + *ppCtx = NULL; +} + +static p12uContext * +p12u_InitContext(PRBool fileImport, char *filename) +{ + p12uContext *p12ctx; + + p12ctx = PORT_ZNew(p12uContext); + if (!p12ctx) { + return (NULL); + } + + p12ctx->error = PR_FALSE; + p12ctx->errorValue = 0; + p12ctx->filename = strdup(filename); + + if (!p12u_OpenFile(p12ctx, fileImport)) { + p12u_DestroyContext(&p12ctx, PR_FALSE); + return (NULL); + } + + return (p12ctx); +} + +static void +p12u_WriteToExportFile(void *arg, const char *buf, unsigned long len) +{ + p12uContext *p12cxt = arg; + int writeLen; + + if (!p12cxt || (p12cxt->error == PR_TRUE)) { + return; + } + + if (p12cxt->file == NULL) { + p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE; + p12cxt->error = PR_TRUE; + return; + } + + writeLen = PR_Write(p12cxt->file, (unsigned char *)buf, (int32)len); + + if (writeLen != (int)len) { + PR_Close(p12cxt->file); + free(p12cxt->filename); + p12cxt->filename = NULL; + p12cxt->file = NULL; + p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE; + p12cxt->error = PR_TRUE; + } +} + +#define HANDLE_NSS_ERROR(r) {\ + SET_ERROR(kmfh, PORT_GetError()); \ + rv = r; \ + goto out; } + +static KMF_RETURN +add_cert_to_bag(SEC_PKCS12ExportContext *p12ecx, + CERTCertificate *cert, SECItem *pwitem) +{ + KMF_RETURN rv = KMF_OK; + SEC_PKCS12SafeInfo *keySafe = NULL, *certSafe = NULL; + + keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx); + if (PK11_IsFIPS()) { + certSafe = keySafe; + } else { + certSafe = SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC); + } + + if (!certSafe || !keySafe) { + rv = KMF_ERR_INTERNAL; + goto out; + } + + if (SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert, + CERT_GetDefaultCertDB(), keySafe, NULL, PR_TRUE, pwitem, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC) + != SECSuccess) { + rv = KMF_ERR_INTERNAL; + } +out: + return (rv); +} + +/*ARGSUSED*/ +KMF_RETURN +NSS_ExportP12(KMF_HANDLE_T handle, + KMF_EXPORTP12_PARAMS *params, + int numcerts, KMF_X509_DER_CERT *certs, + int numkeys, KMF_KEY_HANDLE *keylist, + char *filename) +{ + KMF_RETURN rv; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + SEC_PKCS12ExportContext *p12ecx = NULL; + p12uContext *p12ctx = NULL; + CERTCertList *certlist = NULL; + CERTCertificate *nsscert = NULL; + CERTCertListNode* node = NULL; + PK11SlotInfo *slot = NULL; + SECItem pwitem = {NULL, 0}; + + rv = Do_NSS_Init(handle, + params->nssparms, FALSE, &slot); + if (rv != KMF_OK) { + return (rv); + } + + rv = nss_authenticate(handle, slot, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + /* + * Find the certificate(s) first. + */ + if (params->certLabel) { + nsscert = PK11_FindCertFromNickname(params->certLabel, + NULL); + if (nsscert == NULL) { + HANDLE_NSS_ERROR(KMF_ERR_CERT_NOT_FOUND) + } + } else { + rv = nss_find_matching_certs(slot, + params->issuer, + params->subject, + params->serial, + &certlist, 0); + + if (rv == KMF_OK && certlist == NULL) { + return (KMF_ERR_CERT_NOT_FOUND); + } + if (rv != KMF_OK) + return (rv); + } + + /* + * The KMF_CREDENTIAL holds the password to use for + * encrypting the PKCS12 key information. + */ + pwitem.data = (uchar_t *)params->p12cred.cred; + pwitem.len = params->p12cred.credlen; + + p12ctx = p12u_InitContext(PR_FALSE, filename); + if (!p12ctx) { + HANDLE_NSS_ERROR(KMF_ERR_OPEN_FILE) + } + + PORT_SetUCS2_ASCIIConversionFunction( + p12u_ucs2_ascii_conversion_function); + + p12ecx = SEC_PKCS12CreateExportContext(NULL, NULL, + slot, NULL); + if (!p12ecx) { + HANDLE_NSS_ERROR(KMF_ERR_OPEN_FILE) + } + + if (SEC_PKCS12AddPasswordIntegrity(p12ecx, &pwitem, SEC_OID_SHA1) + != SECSuccess) { + HANDLE_NSS_ERROR(KMF_ERR_INTERNAL) + } + + /* + * NSS actually supports storing a list of keys and certs + * in the PKCS#12 PDU. Nice feature. + */ + if (certlist != NULL) { + for (node = CERT_LIST_HEAD(certlist); + !CERT_LIST_END(node, certlist) && rv == KMF_OK; + node = CERT_LIST_NEXT(node)) { + + rv = add_cert_to_bag(p12ecx, node->cert, &pwitem); + } + } else if (nsscert != NULL) { + rv = add_cert_to_bag(p12ecx, nsscert, &pwitem); + } + + if (SEC_PKCS12Encode(p12ecx, p12u_WriteToExportFile, p12ctx) + != SECSuccess) { + HANDLE_NSS_ERROR(KMF_ERR_ENCODING) + } +out: + if (nsscert) + CERT_DestroyCertificate(nsscert); + + if (certlist) + CERT_DestroyCertList(certlist); + + if (p12ctx) + p12u_DestroyContext(&p12ctx, PR_FALSE); + + if (p12ecx) + SEC_PKCS12DestroyExportContext(p12ecx); + + return (rv); +} + +#define SETATTR(t, n, atype, value, size) \ + t[n].type = atype; \ + t[n].pValue = (CK_BYTE *)value; \ + t[n].ulValueLen = (CK_ULONG)size; + +KMF_RETURN +NSS_StorePrivateKey(KMF_HANDLE_T handle, KMF_STOREKEY_PARAMS *params, + KMF_RAW_KEY_DATA *rawkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + SECStatus ckrv = SECSuccess; + PK11SlotInfo *slot = NULL; + CERTCertificate *nss_cert = NULL; + SECKEYPrivateKeyInfo rpk; + SECItem nickname; + KMF_DATA derkey = { NULL, 0 }; + uchar_t ver = 0; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (params == NULL || params->certificate == NULL || rawkey == NULL) + return (KMF_ERR_BAD_PARAMETER); + + rv = Do_NSS_Init(handle, + params->nssparms, FALSE, &slot); + + if (rv != KMF_OK) + return (rv); + + rv = nss_authenticate(handle, slot, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + /* + * Decode the cert into an NSS CERT object so we can access the + * SPKI and KeyUsage data later. + */ + nss_cert = CERT_DecodeCertFromPackage((char *)params->certificate->Data, + params->certificate->Length); + + if (nss_cert == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + (void) memset(&rpk, 0, sizeof (rpk)); + + rpk.arena = NULL; + rpk.version.type = siUnsignedInteger; + rpk.version.data = &ver; + rpk.version.len = 1; + if (rawkey->keytype == KMF_RSA) { + + rv = DerEncodeRSAPrivateKey(&derkey, &rawkey->rawdata.rsa); + if (rv != KMF_OK) + goto cleanup; + + rpk.algorithm = nss_cert->subjectPublicKeyInfo.algorithm; + rpk.privateKey.data = derkey.Data; + rpk.privateKey.len = derkey.Length; + rpk.attributes = NULL; + + + } else if (rawkey->keytype == KMF_DSA) { + rv = DerEncodeDSAPrivateKey(&derkey, &rawkey->rawdata.dsa); + if (rv != KMF_OK) + goto cleanup; + + rpk.algorithm = nss_cert->subjectPublicKeyInfo.algorithm; + rpk.privateKey.data = derkey.Data; + rpk.privateKey.len = derkey.Length; + rpk.attributes = NULL; + + } else { + return (KMF_ERR_BAD_PARAMETER); + } + + nickname.data = (uchar_t *)params->label; + nickname.len = (params->label ? strlen(params->label) : 0); + + ckrv = PK11_ImportPrivateKeyInfo(slot, &rpk, + &nickname, &nss_cert->subjectPublicKeyInfo.subjectPublicKey, + TRUE, TRUE, nss_cert->keyUsage, NULL); + + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_INTERNAL; + } + +cleanup: + if (nss_cert != NULL) { + CERT_DestroyCertificate(nss_cert); + } + KMF_FreeData(&derkey); + return (rv); +} + +KMF_RETURN +NSS_CreateSymKey(KMF_HANDLE_T handle, + KMF_CREATESYMKEY_PARAMS *params, + KMF_KEY_HANDLE *symkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + PK11SlotInfo *nss_slot = NULL; + PK11SymKey *nsskey = NULL; + CK_MECHANISM_TYPE keyType; + SECStatus nssrv; + int keySize; + + if (params == NULL || symkey == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + switch (params->keytype) { + case KMF_AES: + keyType = CKM_AES_KEY_GEN; + keySize = params->keylength; + if (keySize == 0 || (keySize % 8) != 0) + return (KMF_ERR_BAD_KEY_SIZE); + break; + case KMF_RC4: + keyType = CKM_RC4_KEY_GEN; + keySize = params->keylength; + if (keySize == 0 || (keySize % 8) != 0) + return (KMF_ERR_BAD_KEY_SIZE); + break; + case KMF_DES: + keyType = CKM_DES_KEY_GEN; + keySize = 0; /* required by PK11_TokenKeyGen() */ + break; + case KMF_DES3: + keyType = CKM_DES3_KEY_GEN; + keySize = 0; /* required by PK11_TokenKeyGen() */ + break; + default: + rv = KMF_ERR_BAD_KEY_TYPE; + goto out; + } + + rv = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, FALSE, &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + + rv = nss_authenticate(handle, nss_slot, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + nsskey = PK11_TokenKeyGen(nss_slot, keyType, NULL, keySize, NULL, + PR_TRUE, (void *)params->cred.cred); + if (nsskey == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_KEYGEN_FAILED; + goto out; + } + + nssrv = PK11_SetSymKeyNickname(nsskey, params->keylabel); + if (nssrv != SECSuccess) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_KEYGEN_FAILED; + goto out; + } + + symkey->kstype = KMF_KEYSTORE_NSS; + symkey->keyalg = params->keytype; + symkey->keyclass = KMF_SYMMETRIC; + symkey->israw = FALSE; + symkey->keyp = (void *)nsskey; + +out: + if (nss_slot != NULL) + PK11_FreeSlot(nss_slot); + + if (rv != KMF_OK && nsskey != NULL) { + PK11_DeleteTokenSymKey(nsskey); + PK11_FreeSymKey(nsskey); + } + return (rv); +} + +KMF_RETURN +NSS_GetSymKeyValue(KMF_HANDLE_T handle, KMF_KEY_HANDLE *symkey, + KMF_RAW_SYM_KEY *rkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + SECItem *value = NULL; + PK11SymKey *nsskey; + SECStatus nss_rv; + + if (kmfh == NULL) + return (KMF_ERR_UNINITIALIZED); + + if (symkey == NULL || rkey == NULL) + return (KMF_ERR_BAD_PARAMETER); + else if (symkey->keyclass != KMF_SYMMETRIC) + return (KMF_ERR_BAD_KEY_CLASS); + + if (symkey->israw) { + KMF_RAW_KEY_DATA *rawkey = (KMF_RAW_KEY_DATA *)symkey->keyp; + + if (rawkey == NULL || + rawkey->rawdata.sym.keydata.val == NULL || + rawkey->rawdata.sym.keydata.len == 0) + return (KMF_ERR_BAD_KEYHANDLE); + + rkey->keydata.len = rawkey->rawdata.sym.keydata.len; + if ((rkey->keydata.val = malloc(rkey->keydata.len)) == NULL) + return (KMF_ERR_MEMORY); + (void) memcpy(rkey->keydata.val, + rawkey->rawdata.sym.keydata.val, rkey->keydata.len); + } else { + nsskey = (PK11SymKey *)(symkey->keyp); + if (nsskey == NULL) + return (KMF_ERR_BAD_KEYHANDLE); + + nss_rv = PK11_ExtractKeyValue(nsskey); + if (nss_rv != SECSuccess) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_GETKEYVALUE_FAILED; + goto out; + } + + value = PK11_GetKeyData(nsskey); + if (value == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_GETKEYVALUE_FAILED; + goto out; + } + + if (value->len == 0 || value->data == NULL) { + rv = KMF_ERR_GETKEYVALUE_FAILED; + goto out; + } + + rkey->keydata.val = malloc(value->len); + if (rkey->keydata.val == NULL) { + rv = KMF_ERR_MEMORY; + goto out; + } + (void) memcpy(rkey->keydata.val, value->data, value->len); + rkey->keydata.len = value->len; + (void) memset(value->data, 0, value->len); + } +out: + if (value != NULL) + SECITEM_FreeItem(value, PR_TRUE); + return (rv); +} + +KMF_RETURN +NSS_SetTokenPin(KMF_HANDLE_T handle, KMF_SETPIN_PARAMS *params, + KMF_CREDENTIAL *newpin) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + int rv; + PK11SlotInfo *nss_slot = NULL; + + if (handle == NULL || params == NULL || newpin == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + ret = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, + FALSE, &nss_slot); + /* If it was uninitialized, set it */ + if (ret == KMF_ERR_UNINITIALIZED_TOKEN) { + rv = PK11_InitPin(nss_slot, NULL, newpin->cred); + if (rv != SECSuccess) { + SET_ERROR(kmfh, PORT_GetError()); + ret = KMF_ERR_AUTH_FAILED; + } else { + ret = KMF_OK; + } + } else if (ret == KMF_OK) { + ret = nss_authenticate(handle, nss_slot, ¶ms->cred); + if (ret != KMF_OK) { + return (ret); + } + rv = PK11_ChangePW(nss_slot, + params->cred.cred, newpin->cred); + if (rv != SECSuccess) { + SET_ERROR(kmfh, PORT_GetError()); + ret = KMF_ERR_AUTH_FAILED; + } + } + + return (ret); +} diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/i386/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/i386/Makefile new file mode 100644 index 0000000000..443f78537a --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_nss/i386/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: $(ROOTLIBS) diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/sparc/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/sparc/Makefile new file mode 100644 index 0000000000..472ac90a9a --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_nss/sparc/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: $(ROOTLIBS) diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/sparcv9/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/sparcv9/Makefile new file mode 100644 index 0000000000..fe1e843387 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_nss/sparcv9/Makefile @@ -0,0 +1,32 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../../../Makefile.lib.64 + +LDLIBS += $(NSSLIBS64) + +install: $(ROOTLIBS64) diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile new file mode 100644 index 0000000000..ba73e41d2e --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile @@ -0,0 +1,46 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include $(SRC)/lib/Makefile.lib + +SUBDIRS= $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET= all +check := TARGET= check +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +.KEEP_STATE: + +all clean clobber install lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com b/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com new file mode 100644 index 0000000000..3ae32a00da --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com @@ -0,0 +1,78 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# Makefile for KMF Plugins +# + +LIBRARY= kmf_openssl.a +VERS= .1 + +OBJECTS= openssl_spi.o + +include $(SRC)/lib/Makefile.lib + +LIBLINKS= $(DYNLIB:.so.1=.so) +SFWDIR= /usr/sfw +KMFINC= -I../../../include -I../../../ber_der/inc +BERLIB= -lkmf -lkmfberder +BERLIB64= $(BERLIB) + +OPENSSLLIBS= $(BERLIB) -R$(SFWDIR)/lib -L$(ROOT)/$(SFWDIR)/lib -lcrypto -lcryptoutil -lc +OPENSSLLIBS64= $(BERLIB64) -R$(SFWDIR)/lib/$(MACH64) -L$(ROOT)/$(SFWDIR)/lib/$(MACH64) \ + -lcrypto -lcryptoutil -lc + +LINTSSLLIBS = $(BERLIB) -L$(ROOT)/$(SFWDIR)/lib -lcrypto -lcryptoutil -lc +LINTSSLLIBS64= $(BERLIB64) -L$(ROOT)/$(SFWDIR)/lib/$(MACH64) \ + -lcrypto -lcryptoutil -lc + +SRCDIR= ../common +INCDIR= ../../include + +CFLAGS += $(CCVERBOSE) +CPPFLAGS += -D_REENTRANT $(KMFINC) -I$(ROOT)/$(SFWDIR)/include \ + -I$(INCDIR) -I/usr/include/libxml2 + +PICS= $(OBJECTS:%=pics/%) +SONAME= $(DYNLIB) + +lint:= OPENSSLLIBS= $(LINTSSLLIBS) +lint:= OPENSSLLIBS64= $(LINTSSLLIBS64) + +LDLIBS32 += $(OPENSSLLIBS) + +ROOTLIBDIR= $(ROOT)/usr/lib/security +ROOTLIBDIR64= $(ROOT)/usr/lib/security/$(MACH64) + +.KEEP_STATE: + +LIBS = $(DYNLIB) +all: $(DYNLIB) $(LINTLIB) + +lint: lintcheck + +FRC: + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/amd64/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/amd64/Makefile new file mode 100644 index 0000000000..d73321747a --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_openssl/amd64/Makefile @@ -0,0 +1,32 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include $(SRC)/lib/Makefile.lib.64 + +LDLIBS += $(OPENSSLLIBS64) + +install: $(ROOTLIBS64) diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers b/usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers new file mode 100644 index 0000000000..cd910effa4 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers @@ -0,0 +1,61 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SUNWprivate_1.1 { + global: + KMF_Plugin_Initialize; + OpenSSL_CertGetPrintable; + OpenSSL_CheckCRLDate; + OpenSSL_CreateKeypair; + OpenSSL_CreateOCSPRequest; + OpenSSL_CreateSymKey; + OpenSSL_DecryptData; + OpenSSL_DeleteCRL; + OpenSSL_DeleteCert; + OpenSSL_DeleteKey; + OpenSSL_EncodePubKeyData; + OpenSSL_ExportP12; + OpenSSL_FindCert; + OpenSSL_FindCertInCRL; + OpenSSL_FindKey; + OpenSSL_FreeKMFCert; + OpenSSL_GetErrorString; + OpenSSL_GetOCSPStatusForCert; + OpenSSL_GetPrikeyByCert; + OpenSSL_GetSymKeyValue; + OpenSSL_ImportCRL; + OpenSSL_IsCRLFile; + OpenSSL_IsCertFile; + OpenSSL_ListCRL; + OpenSSL_SignData; + OpenSSL_StoreCert; + OpenSSL_StorePrivateKey; + OpenSSL_VerifyCRLFile; + openssl_read_pkcs12; + local: + *; +}; diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c b/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c new file mode 100644 index 0000000000..e088341f01 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c @@ -0,0 +1,4198 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * OpenSSL keystore wrapper + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <kmfapiP.h> +#include <ber_der.h> +#include <oidsalg.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <dirent.h> +#include <cryptoutil.h> +#include <synch.h> +#include <thread.h> + +/* OPENSSL related headers */ +#include <openssl/bio.h> +#include <openssl/bn.h> +#include <openssl/asn1.h> +#include <openssl/err.h> +#include <openssl/bn.h> +#include <openssl/x509.h> +#include <openssl/rsa.h> +#include <openssl/dsa.h> +#include <openssl/x509v3.h> +#include <openssl/objects.h> +#include <openssl/pem.h> +#include <openssl/pkcs12.h> +#include <openssl/ocsp.h> +#include <openssl/des.h> +#include <openssl/rand.h> + +#define PRINT_ANY_EXTENSION (\ + KMF_X509_EXT_KEY_USAGE |\ + KMF_X509_EXT_CERT_POLICIES |\ + KMF_X509_EXT_SUBJALTNAME |\ + KMF_X509_EXT_BASIC_CONSTRAINTS |\ + KMF_X509_EXT_NAME_CONSTRAINTS |\ + KMF_X509_EXT_POLICY_CONSTRAINTS |\ + KMF_X509_EXT_EXT_KEY_USAGE |\ + KMF_X509_EXT_INHIBIT_ANY_POLICY |\ + KMF_X509_EXT_AUTH_KEY_ID |\ + KMF_X509_EXT_SUBJ_KEY_ID |\ + KMF_X509_EXT_POLICY_MAPPING) + +static BIO *bio_err = NULL; +static uchar_t P[] = { 0x00, 0x8d, 0xf2, 0xa4, 0x94, 0x49, 0x22, 0x76, + 0xaa, 0x3d, 0x25, 0x75, 0x9b, 0xb0, 0x68, 0x69, + 0xcb, 0xea, 0xc0, 0xd8, 0x3a, 0xfb, 0x8d, 0x0c, + 0xf7, 0xcb, 0xb8, 0x32, 0x4f, 0x0d, 0x78, 0x82, + 0xe5, 0xd0, 0x76, 0x2f, 0xc5, 0xb7, 0x21, 0x0e, + 0xaf, 0xc2, 0xe9, 0xad, 0xac, 0x32, 0xab, 0x7a, + 0xac, 0x49, 0x69, 0x3d, 0xfb, 0xf8, 0x37, 0x24, + 0xc2, 0xec, 0x07, 0x36, 0xee, 0x31, 0xc8, 0x02, + 0x91 }; + +static uchar_t Q[] = { 0x00, 0xc7, 0x73, 0x21, 0x8c, 0x73, 0x7e, 0xc8, + 0xee, 0x99, 0x3b, 0x4f, 0x2d, 0xed, 0x30, 0xf4, + 0x8e, 0xda, 0xce, 0x91, 0x5f }; + +static uchar_t G[] = { 0x00, 0x62, 0x6d, 0x02, 0x78, 0x39, 0xea, 0x0a, + 0x13, 0x41, 0x31, 0x63, 0xa5, 0x5b, 0x4c, 0xb5, + 0x00, 0x29, 0x9d, 0x55, 0x22, 0x95, 0x6c, 0xef, + 0xcb, 0x3b, 0xff, 0x10, 0xf3, 0x99, 0xce, 0x2c, + 0x2e, 0x71, 0xcb, 0x9d, 0xe5, 0xfa, 0x24, 0xba, + 0xbf, 0x58, 0xe5, 0xb7, 0x95, 0x21, 0x92, 0x5c, + 0x9c, 0xc4, 0x2e, 0x9f, 0x6f, 0x46, 0x4b, 0x08, + 0x8c, 0xc5, 0x72, 0xaf, 0x53, 0xe6, 0xd7, 0x88, + 0x02 }; + +#define SET_ERROR(h, c) h->lasterr.kstype = KMF_KEYSTORE_OPENSSL; \ + h->lasterr.errcode = c; + +#define SET_SYS_ERROR(h, c) h->lasterr.kstype = -1; h->lasterr.errcode = c; + +mutex_t init_lock = DEFAULTMUTEX; +static int ssl_initialized = 0; + +KMF_RETURN +OpenSSL_FindCert(KMF_HANDLE_T, + KMF_FINDCERT_PARAMS *, + KMF_X509_DER_CERT *, + uint32_t *); + +void +OpenSSL_FreeKMFCert(KMF_HANDLE_T, KMF_X509_DER_CERT *); + +KMF_RETURN +OpenSSL_StoreCert(KMF_HANDLE_T handle, KMF_STORECERT_PARAMS *, KMF_DATA *); + +KMF_RETURN +OpenSSL_DeleteCert(KMF_HANDLE_T handle, KMF_DELETECERT_PARAMS *); + +KMF_RETURN +OpenSSL_CreateKeypair(KMF_HANDLE_T, KMF_CREATEKEYPAIR_PARAMS *, + KMF_KEY_HANDLE *, KMF_KEY_HANDLE *); + +KMF_RETURN +OpenSSL_EncodePubKeyData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_DATA *); + +KMF_RETURN +OpenSSL_SignData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *, + KMF_DATA *, KMF_DATA *); + +KMF_RETURN +OpenSSL_DeleteKey(KMF_HANDLE_T, KMF_DELETEKEY_PARAMS *, + KMF_KEY_HANDLE *, boolean_t); + +KMF_RETURN +OpenSSL_ImportCRL(KMF_HANDLE_T, KMF_IMPORTCRL_PARAMS *); + +KMF_RETURN +OpenSSL_DeleteCRL(KMF_HANDLE_T, KMF_DELETECRL_PARAMS *); + +KMF_RETURN +OpenSSL_ListCRL(KMF_HANDLE_T, KMF_LISTCRL_PARAMS *, char **); + +KMF_RETURN +OpenSSL_FindCertInCRL(KMF_HANDLE_T, KMF_FINDCERTINCRL_PARAMS *); + +KMF_RETURN +OpenSSL_CertGetPrintable(KMF_HANDLE_T, const KMF_DATA *, + KMF_PRINTABLE_ITEM, char *); + +KMF_RETURN +OpenSSL_GetErrorString(KMF_HANDLE_T, char **); + +KMF_RETURN +OpenSSL_GetPrikeyByCert(KMF_HANDLE_T, KMF_CRYPTOWITHCERT_PARAMS *, KMF_DATA *, + KMF_KEY_HANDLE *, KMF_KEY_ALG); + +KMF_RETURN +OpenSSL_DecryptData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *, + KMF_DATA *, KMF_DATA *); + +KMF_RETURN +OpenSSL_CreateOCSPRequest(KMF_HANDLE_T, KMF_OCSPREQUEST_PARAMS *, + char *reqfile); + +KMF_RETURN +OpenSSL_GetOCSPStatusForCert(KMF_HANDLE_T, KMF_OCSPRESPONSE_PARAMS_INPUT *, + KMF_OCSPRESPONSE_PARAMS_OUTPUT *); + +KMF_RETURN +OpenSSL_FindKey(KMF_HANDLE_T, KMF_FINDKEY_PARAMS *, + KMF_KEY_HANDLE *, uint32_t *); + +KMF_RETURN +OpenSSL_ExportP12(KMF_HANDLE_T, + KMF_EXPORTP12_PARAMS *, + int, KMF_X509_DER_CERT *, + int, KMF_KEY_HANDLE *, + char *); + +KMF_RETURN +OpenSSL_StorePrivateKey(KMF_HANDLE_T, KMF_STOREKEY_PARAMS *, + KMF_RAW_KEY_DATA *); + +KMF_RETURN +OpenSSL_CreateSymKey(KMF_HANDLE_T, KMF_CREATESYMKEY_PARAMS *, + KMF_KEY_HANDLE *); + +KMF_RETURN +OpenSSL_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_SYM_KEY *); + +KMF_RETURN +OpenSSL_VerifyCRLFile(KMF_HANDLE_T, KMF_VERIFYCRL_PARAMS *); + +KMF_RETURN +OpenSSL_CheckCRLDate(KMF_HANDLE_T, KMF_CHECKCRLDATE_PARAMS *); + +static +KMF_PLUGIN_FUNCLIST openssl_plugin_table = +{ + 1, /* Version */ + NULL, /* ConfigureKeystore */ + OpenSSL_FindCert, + OpenSSL_FreeKMFCert, + OpenSSL_StoreCert, + NULL, /* ImportCert */ + OpenSSL_ImportCRL, + OpenSSL_DeleteCert, + OpenSSL_DeleteCRL, + OpenSSL_CreateKeypair, + OpenSSL_FindKey, + OpenSSL_EncodePubKeyData, + OpenSSL_SignData, + OpenSSL_DeleteKey, + OpenSSL_ListCRL, + NULL, /* FindCRL */ + OpenSSL_FindCertInCRL, + OpenSSL_GetErrorString, + OpenSSL_GetPrikeyByCert, + OpenSSL_DecryptData, + OpenSSL_ExportP12, + OpenSSL_StorePrivateKey, + OpenSSL_CreateSymKey, + OpenSSL_GetSymKeyValue, + NULL, /* SetTokenPin */ + NULL /* Finalize */ +}; + +static mutex_t *lock_cs; +static long *lock_count; + +static void +/*ARGSUSED*/ +locking_cb(int mode, int type, char *file, int line) +{ + if (mode & CRYPTO_LOCK) { + (void) mutex_lock(&(lock_cs[type])); + lock_count[type]++; + } else { + (void) mutex_unlock(&(lock_cs[type])); + } +} + +static unsigned long +thread_id() +{ + return ((unsigned long)thr_self()); +} + +KMF_PLUGIN_FUNCLIST * +KMF_Plugin_Initialize() +{ + int i; + + (void) mutex_lock(&init_lock); + if (!ssl_initialized) { + OpenSSL_add_all_algorithms(); + + /* Enable error strings for reporting */ + ERR_load_crypto_strings(); + + /* + * Add support for extension OIDs that are not yet in the + * openssl default set. + */ + (void) OBJ_create("2.5.29.30", "nameConstraints", + "X509v3 Name Constraints"); + (void) OBJ_create("2.5.29.33", "policyMappings", + "X509v3 Policy Mappings"); + (void) OBJ_create("2.5.29.36", "policyConstraints", + "X509v3 Policy Constraints"); + (void) OBJ_create("2.5.29.46", "freshestCRL", + "X509v3 Freshest CRL"); + (void) OBJ_create("2.5.29.54", "inhibitAnyPolicy", + "X509v3 Inhibit Any-Policy"); + /* + * Set up for thread-safe operation. + */ + lock_cs = OPENSSL_malloc(CRYPTO_num_locks() * sizeof (mutex_t)); + if (lock_cs == NULL) { + (void) mutex_unlock(&init_lock); + return (NULL); + } + + lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof (long)); + if (lock_count == NULL) { + OPENSSL_free(lock_cs); + (void) mutex_unlock(&init_lock); + return (NULL); + } + + for (i = 0; i < CRYPTO_num_locks(); i++) { + lock_count[i] = 0; + (void) mutex_init(&lock_cs[i], USYNC_THREAD, NULL); + } + + CRYPTO_set_id_callback((unsigned long (*)())thread_id); + CRYPTO_set_locking_callback((void (*)())locking_cb); + ssl_initialized = 1; + } + (void) mutex_unlock(&init_lock); + + return (&openssl_plugin_table); +} +/* + * Convert an SSL DN to a KMF DN. + */ +static KMF_RETURN +get_x509_dn(X509_NAME *sslDN, KMF_X509_NAME *kmfDN) +{ + KMF_DATA derdata; + KMF_RETURN rv = KMF_OK; + uchar_t *tmp; + + /* Convert to raw DER format */ + derdata.Length = i2d_X509_NAME(sslDN, NULL); + if ((tmp = derdata.Data = (uchar_t *)OPENSSL_malloc(derdata.Length)) + == NULL) { + return (KMF_ERR_MEMORY); + } + (void) i2d_X509_NAME(sslDN, &tmp); + + /* Decode to KMF format */ + rv = DerDecodeName(&derdata, kmfDN); + if (rv != KMF_OK) { + rv = KMF_ERR_BAD_CERT_FORMAT; + } + OPENSSL_free(derdata.Data); + + return (rv); +} + +static int +isdir(char *path) +{ + struct stat s; + + if (stat(path, &s) == -1) + return (0); + + return (s.st_mode & S_IFDIR); +} + +static KMF_RETURN +ssl_cert2KMFDATA(KMF_HANDLE *kmfh, X509 *x509cert, KMF_DATA *cert) +{ + KMF_RETURN rv = KMF_OK; + unsigned char *buf = NULL, *p; + int len; + + /* + * Convert the X509 internal struct to DER encoded data + */ + if ((len = i2d_X509(x509cert, NULL)) < 0) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + if ((buf = malloc(len)) == NULL) { + SET_SYS_ERROR(kmfh, errno); + rv = KMF_ERR_MEMORY; + goto cleanup; + } + + /* + * i2d_X509 will increment the buf pointer so that we need to + * save it. + */ + p = buf; + if ((len = i2d_X509(x509cert, &p)) < 0) { + SET_ERROR(kmfh, ERR_get_error()); + free(buf); + rv = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + /* caller's responsibility to free it */ + cert->Data = buf; + cert->Length = len; + +cleanup: + if (rv != KMF_OK) { + if (buf) + free(buf); + cert->Data = NULL; + cert->Length = 0; + } + + return (rv); +} + +static KMF_RETURN +check_cert(X509 *xcert, KMF_FINDCERT_PARAMS *params, boolean_t *match) +{ + KMF_RETURN rv = KMF_OK; + boolean_t findIssuer = FALSE; + boolean_t findSubject = FALSE; + boolean_t findSerial = FALSE; + KMF_X509_NAME issuerDN, subjectDN; + KMF_X509_NAME certIssuerDN, certSubjectDN; + + *match = FALSE; + if (xcert == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + (void) memset(&issuerDN, 0, sizeof (KMF_X509_NAME)); + (void) memset(&subjectDN, 0, sizeof (KMF_X509_NAME)); + (void) memset(&certIssuerDN, 0, sizeof (KMF_X509_NAME)); + (void) memset(&certSubjectDN, 0, sizeof (KMF_X509_NAME)); + + if (params->issuer != NULL && strlen(params->issuer)) { + rv = KMF_DNParser(params->issuer, &issuerDN); + if (rv != KMF_OK) + return (KMF_ERR_BAD_PARAMETER); + + rv = get_x509_dn(xcert->cert_info->issuer, &certIssuerDN); + if (rv != KMF_OK) { + KMF_FreeDN(&issuerDN); + return (KMF_ERR_BAD_PARAMETER); + } + + findIssuer = TRUE; + } + if (params->subject != NULL && strlen(params->subject)) { + rv = KMF_DNParser(params->subject, &subjectDN); + if (rv != KMF_OK) { + rv = KMF_ERR_BAD_PARAMETER; + goto cleanup; + } + + rv = get_x509_dn(xcert->cert_info->subject, &certSubjectDN); + if (rv != KMF_OK) { + rv = KMF_ERR_BAD_PARAMETER; + goto cleanup; + } + findSubject = TRUE; + } + if (params->serial != NULL && params->serial->val != NULL) + findSerial = TRUE; + + if (findSerial) { + BIGNUM *bn; + + /* Comparing BIGNUMs is a pain! */ + bn = ASN1_INTEGER_to_BN(xcert->cert_info->serialNumber, NULL); + if (bn != NULL) { + int bnlen = BN_num_bytes(bn); + + if (bnlen == params->serial->len) { + uchar_t *a = malloc(bnlen); + if (a == NULL) { + rv = KMF_ERR_MEMORY; + BN_free(bn); + goto cleanup; + } + bnlen = BN_bn2bin(bn, a); + *match = !memcmp(a, + params->serial->val, + params->serial->len); + rv = KMF_OK; + free(a); + } + BN_free(bn); + if (!(*match)) + goto cleanup; + } else { + rv = KMF_OK; + goto cleanup; + } + } + if (findIssuer) { + *match = !KMF_CompareRDNs(&issuerDN, &certIssuerDN); + if (!(*match)) { + rv = KMF_OK; + goto cleanup; + } + } + if (findSubject) { + *match = !KMF_CompareRDNs(&subjectDN, &certSubjectDN); + if (!(*match)) { + rv = KMF_OK; + goto cleanup; + } + } + + *match = TRUE; +cleanup: + if (findIssuer) { + KMF_FreeDN(&issuerDN); + KMF_FreeDN(&certIssuerDN); + } + if (findSubject) { + KMF_FreeDN(&subjectDN); + KMF_FreeDN(&certSubjectDN); + } + + return (rv); +} + +static KMF_RETURN +load_X509cert(KMF_HANDLE *kmfh, + KMF_FINDCERT_PARAMS *params, + char *pathname, + X509 **outcert) +{ + KMF_RETURN rv = KMF_OK; + X509 *xcert = NULL; + BIO *bcert = NULL; + boolean_t match = FALSE; + KMF_ENCODE_FORMAT format; + + /* + * auto-detect the file format, regardless of what + * the 'format' parameters in the params say. + */ + rv = KMF_GetFileFormat(pathname, &format); + if (rv != KMF_OK) { + if (rv == KMF_ERR_OPEN_FILE) + rv = KMF_ERR_CERT_NOT_FOUND; + return (rv); + } + + /* Not ASN1(DER) format */ + if ((bcert = BIO_new_file(pathname, "rb")) == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_OPEN_FILE; + goto cleanup; + } + + if (format == KMF_FORMAT_PEM) + xcert = PEM_read_bio_X509_AUX(bcert, NULL, NULL, NULL); + else if (format == KMF_FORMAT_ASN1) + xcert = d2i_X509_bio(bcert, NULL); + else if (format == KMF_FORMAT_PKCS12) { + PKCS12 *p12 = d2i_PKCS12_bio(bcert, NULL); + if (p12 != NULL) { + (void) PKCS12_parse(p12, NULL, NULL, &xcert, NULL); + PKCS12_free(p12); + p12 = NULL; + } else { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_BAD_CERT_FORMAT; + } + } else { + rv = KMF_ERR_BAD_PARAMETER; + goto cleanup; + } + + if (xcert == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + if (check_cert(xcert, params, &match) != KMF_OK || match == FALSE) { + rv = KMF_ERR_CERT_NOT_FOUND; + goto cleanup; + } + + if (outcert != NULL) { + *outcert = xcert; + } + +cleanup: + if (bcert != NULL) (void) BIO_free(bcert); + if (rv != KMF_OK && xcert != NULL) + X509_free(xcert); + + return (rv); +} + +static KMF_RETURN +kmf_load_cert(KMF_HANDLE *kmfh, + KMF_FINDCERT_PARAMS *params, + char *pathname, + KMF_DATA *cert) +{ + KMF_RETURN rv = KMF_OK; + X509 *x509cert = NULL; + + rv = load_X509cert(kmfh, params, pathname, &x509cert); + if (rv == KMF_OK && x509cert != NULL && cert != NULL) { + rv = ssl_cert2KMFDATA(kmfh, x509cert, cert); + if (rv != KMF_OK) { + goto cleanup; + } + if (params->find_cert_validity == KMF_NONEXPIRED_CERTS) { + rv = KMF_CheckCertDate(kmfh, cert); + } else if (params->find_cert_validity == KMF_EXPIRED_CERTS) { + rv = KMF_CheckCertDate(kmfh, cert); + if (rv == KMF_OK) { + /* + * This is a valid cert so skip it. + */ + rv = KMF_ERR_CERT_NOT_FOUND; + } + if (rv == KMF_ERR_VALIDITY_PERIOD) { + /* + * We want to return success when we + * find an invalid cert. + */ + rv = KMF_OK; + goto cleanup; + } + } + } +cleanup: + if (x509cert != NULL) + X509_free(x509cert); + + return (rv); +} + +static EVP_PKEY * +openssl_load_key(KMF_HANDLE_T handle, const char *file) +{ + BIO *keyfile = NULL; + EVP_PKEY *pkey = NULL; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_ENCODE_FORMAT format; + + if (file == NULL) { + return (NULL); + } + + if (KMF_GetFileFormat((char *)file, &format) != KMF_OK) + return (NULL); + + keyfile = BIO_new_file(file, "rb"); + if (keyfile == NULL) { + goto end; + } + + if (format == KMF_FORMAT_ASN1) + pkey = d2i_PrivateKey_bio(keyfile, NULL); + else if (format == KMF_FORMAT_PEM) + pkey = PEM_read_bio_PrivateKey(keyfile, NULL, NULL, NULL); + +end: + if (pkey == NULL) + SET_ERROR(kmfh, ERR_get_error()); + + if (keyfile != NULL) + (void) BIO_free(keyfile); + + return (pkey); +} + +KMF_RETURN +OpenSSL_FindCert(KMF_HANDLE_T handle, + KMF_FINDCERT_PARAMS *params, + KMF_X509_DER_CERT *kmf_cert, + uint32_t *num_certs) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_DATA certdata = {NULL, 0}; + char *fullpath; + + if (num_certs == NULL || params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + *num_certs = 0; + + fullpath = get_fullpath(params->sslparms.dirpath, + params->sslparms.certfile); + + if (fullpath == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (isdir(fullpath)) { + DIR *dirp; + struct dirent *dp; + int n = 0; + + /* open all files in the directory and attempt to read them */ + if ((dirp = opendir(fullpath)) == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + while ((dp = readdir(dirp)) != NULL) { + char *fname; + if (strcmp(dp->d_name, ".") == 0 || + strcmp(dp->d_name, "..") == 0) + continue; + + fname = get_fullpath(fullpath, + (char *)&dp->d_name); + + rv = kmf_load_cert(kmfh, params, fname, + &certdata); + + if (rv != KMF_OK) { + free(fname); + KMF_FreeData(&certdata); + continue; + } + + /* If load succeeds, add certdata to the list */ + if (kmf_cert != NULL) { + kmf_cert[n].certificate.Data = certdata.Data; + kmf_cert[n].certificate.Length = + certdata.Length; + + kmf_cert[n].kmf_private.keystore_type = + KMF_KEYSTORE_OPENSSL; + kmf_cert[n].kmf_private.flags = + KMF_FLAG_CERT_VALID; + kmf_cert[n].kmf_private.label = fname; + } else { + free(fname); + KMF_FreeData(&certdata); + } + n++; + } + (*num_certs) = n; + if (*num_certs == 0) + rv = KMF_ERR_CERT_NOT_FOUND; + if (*num_certs > 0) + rv = KMF_OK; +exit: + (void) closedir(dirp); + } else { + /* Just try to load a single certificate */ + rv = kmf_load_cert(kmfh, params, fullpath, &certdata); + if (rv != KMF_OK) { + free(fullpath); + KMF_FreeData(&certdata); + return (rv); + } + + if (kmf_cert != NULL) { + kmf_cert->certificate.Data = certdata.Data; + kmf_cert->certificate.Length = certdata.Length; + kmf_cert->kmf_private.keystore_type = + KMF_KEYSTORE_OPENSSL; + kmf_cert->kmf_private.flags = KMF_FLAG_CERT_VALID; + kmf_cert->kmf_private.label = fullpath; + } else { + KMF_FreeData(&certdata); + } + + *num_certs = 1; + } + + if (kmf_cert == NULL || rv != KMF_OK) + free(fullpath); + + return (rv); + +} + +void +/*ARGSUSED*/ +OpenSSL_FreeKMFCert(KMF_HANDLE_T handle, + KMF_X509_DER_CERT *kmf_cert) +{ + if (kmf_cert != NULL) { + if (kmf_cert->certificate.Data != NULL) { + free(kmf_cert->certificate.Data); + kmf_cert->certificate.Data = NULL; + kmf_cert->certificate.Length = 0; + } + if (kmf_cert->kmf_private.label) + free(kmf_cert->kmf_private.label); + } +} + +KMF_RETURN +OpenSSL_StoreCert(KMF_HANDLE_T handle, KMF_STORECERT_PARAMS *params, + KMF_DATA * pcert) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + X509 *xcert = NULL; + FILE *fp; + unsigned char *outbuf; + unsigned char *outbuf_p; + char *fullpath; + int outbuflen; + int len; + KMF_ENCODE_FORMAT format; + + if (params == NULL || params->ks_opt_u.openssl_opts.certfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* + * check if the cert output format is supported by OPENSSL. + * however, since the keystore for OPENSSL is just a file, we have + * no way to store the format along with the file. + */ + format = params->sslparms.format; + if (format != KMF_FORMAT_ASN1 && format != KMF_FORMAT_PEM) + return (KMF_ERR_BAD_CERT_FORMAT); + + + fullpath = get_fullpath(params->sslparms.dirpath, + params->sslparms.certfile); + if (fullpath == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * When storing a certificate, you must specify a filename. + */ + if (isdir(fullpath)) { + free(fullpath); + return (KMF_ERR_BAD_PARAMETER); + } + + /* copy cert data to outbuf */ + outbuflen = pcert->Length; + outbuf = malloc(outbuflen); + if (outbuf == NULL) { + free(fullpath); + return (KMF_ERR_MEMORY); + } + (void) memcpy(outbuf, pcert->Data, pcert->Length); + + if ((fp = fopen(fullpath, "w")) == + NULL) { + SET_SYS_ERROR(kmfh, errno); + ret = KMF_ERR_INTERNAL; + goto out; + } + + if (format == KMF_FORMAT_ASN1) { + len = fwrite(outbuf, 1, outbuflen, fp); + if (len != outbuflen) { + SET_SYS_ERROR(kmfh, errno); + ret = KMF_ERR_WRITE_FILE; + } else { + ret = KMF_OK; + } + goto out; + } + + /* + * The output format is not KMF_FORMAT_ASN1, so we will + * Convert the cert data to OpenSSL internal X509 first. + */ + outbuf_p = outbuf; /* use a temp pointer; required by openssl */ + xcert = d2i_X509(NULL, (const uchar_t **)&outbuf_p, outbuflen); + if (xcert == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_ENCODING; + goto out; + } + + if (format == KMF_FORMAT_PEM) { + /* Convert to the PEM format and write it out */ + if (!PEM_write_X509(fp, xcert)) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_ENCODING; + } else { + ret = KMF_OK; + } + goto out; + } + +out: + if (fullpath != NULL) + free(fullpath); + + if (outbuf != NULL) { + free(outbuf); + } + if (fp != NULL) { + (void) fclose(fp); + } + + if (xcert != NULL) { + X509_free(xcert); + } + + return (ret); +} + +KMF_RETURN +OpenSSL_DeleteCert(KMF_HANDLE_T handle, KMF_DELETECERT_PARAMS *params) +{ + KMF_RETURN rv; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + char *fullpath = NULL; + KMF_DATA certdata = {NULL, 0}; + + if (params == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + fullpath = get_fullpath(params->sslparms.dirpath, + params->sslparms.certfile); + + if (fullpath == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (isdir(fullpath)) { + DIR *dirp; + struct dirent *dp; + + /* open all files in the directory and attempt to read them */ + if ((dirp = opendir(fullpath)) == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + while ((dp = readdir(dirp)) != NULL) { + if (strcmp(dp->d_name, ".") != 0 && + strcmp(dp->d_name, "..") != 0) { + char *fname; + + fname = get_fullpath(fullpath, + (char *)&dp->d_name); + + if (fname == NULL) { + rv = KMF_ERR_MEMORY; + break; + } + + rv = kmf_load_cert(kmfh, params, fname, + &certdata); + + if (rv == KMF_ERR_CERT_NOT_FOUND) { + free(fname); + if (certdata.Data) + free(certdata.Data); + rv = KMF_OK; + continue; + } else if (rv != KMF_OK) { + free(fname); + break; + } + + if (unlink(fname) != 0) { + SET_SYS_ERROR(kmfh, errno); + rv = KMF_ERR_INTERNAL; + free(fname); + break; + } + free(fname); + if (certdata.Data) + free(certdata.Data); + } + } + (void) closedir(dirp); + } else { + /* Just try to load a single certificate */ + rv = kmf_load_cert(kmfh, params, fullpath, &certdata); + if (rv == KMF_OK) { + if (unlink(fullpath) != 0) { + SET_SYS_ERROR(kmfh, errno); + rv = KMF_ERR_INTERNAL; + } + } + } + +out: + if (fullpath != NULL) + free(fullpath); + + if (certdata.Data) + free(certdata.Data); + + return (rv); +} + +KMF_RETURN +OpenSSL_EncodePubKeyData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key, + KMF_DATA *keydata) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + int n; + + if (key == NULL || keydata == NULL || + key->keyp == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (key->keyalg == KMF_RSA) { + RSA *pubkey = EVP_PKEY_get1_RSA(key->keyp); + + if (!(n = i2d_RSA_PUBKEY(pubkey, &keydata->Data))) { + SET_ERROR(kmfh, ERR_get_error()); + return (KMF_ERR_ENCODING); + } + RSA_free(pubkey); + } else if (key->keyalg == KMF_DSA) { + DSA *pubkey = EVP_PKEY_get1_DSA(key->keyp); + + if (!(n = i2d_DSA_PUBKEY(pubkey, &keydata->Data))) { + SET_ERROR(kmfh, ERR_get_error()); + return (KMF_ERR_ENCODING); + } + DSA_free(pubkey); + } else { + return (KMF_ERR_BAD_PARAMETER); + } + keydata->Length = n; + +cleanup: + if (rv != KMF_OK) { + if (keydata->Data) + free(keydata->Data); + keydata->Data = NULL; + keydata->Length = 0; + } + + return (rv); +} + +static KMF_RETURN +ssl_write_private_key(KMF_HANDLE *kmfh, KMF_ENCODE_FORMAT format, BIO *out, + KMF_CREDENTIAL *cred, EVP_PKEY *pkey) +{ + int rv = 0; + RSA *rsa; + DSA *dsa; + + switch (format) { + case KMF_FORMAT_ASN1: + if (pkey->type == EVP_PKEY_RSA) { + rsa = EVP_PKEY_get1_RSA(pkey); + rv = i2d_RSAPrivateKey_bio(out, rsa); + RSA_free(rsa); + } else if (pkey->type == EVP_PKEY_DSA) { + dsa = EVP_PKEY_get1_DSA(pkey); + rv = i2d_DSAPrivateKey_bio(out, dsa); + DSA_free(dsa); + } + if (rv == 1) { + rv = KMF_OK; + } else { + SET_ERROR(kmfh, rv); + } + break; + case KMF_FORMAT_PEM: + if (pkey->type == EVP_PKEY_RSA) { + rsa = EVP_PKEY_get1_RSA(pkey); + rv = PEM_write_bio_RSAPrivateKey(out, + rsa, + NULL /* encryption type */, + NULL, 0, NULL, + cred->cred); + RSA_free(rsa); + } else if (pkey->type == EVP_PKEY_DSA) { + dsa = EVP_PKEY_get1_DSA(pkey); + rv = PEM_write_bio_DSAPrivateKey(out, + dsa, + NULL /* encryption type */, + NULL, 0, NULL, + cred->cred); + DSA_free(dsa); + } + + if (rv == 1) { + rv = KMF_OK; + } else { + SET_ERROR(kmfh, rv); + } + break; + + default: + rv = KMF_ERR_BAD_PARAMETER; + } + + return (rv); +} + +KMF_RETURN +OpenSSL_CreateKeypair(KMF_HANDLE_T handle, KMF_CREATEKEYPAIR_PARAMS *params, + KMF_KEY_HANDLE *privkey, KMF_KEY_HANDLE *pubkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + int format; + uint32_t eValue = 0x010001; + RSA *sslPrivKey = NULL; + DSA *sslDSAKey = NULL; + EVP_PKEY *eprikey = NULL; + EVP_PKEY *epubkey = NULL; + BIO *out = NULL; + char *fullpath = NULL; + + if (params == NULL || params->sslparms.keyfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + fullpath = get_fullpath(params->sslparms.dirpath, + params->sslparms.keyfile); + + if (fullpath == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* If the requested file exists, return an error */ + if (access(fullpath, F_OK) == 0) { + free(fullpath); + return (KMF_ERR_DUPLICATE_KEYFILE); + } + + eprikey = EVP_PKEY_new(); + if (eprikey == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_KEYGEN_FAILED; + goto cleanup; + } + epubkey = EVP_PKEY_new(); + if (epubkey == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_KEYGEN_FAILED; + goto cleanup; + } + if (params->keytype == KMF_RSA) { + if (params->rsa_exponent.len > 0 && + params->rsa_exponent.len <= sizeof (eValue) && + params->rsa_exponent.val != NULL) + /*LINTED*/ + eValue = *(uint32_t *)params->rsa_exponent.val; + + sslPrivKey = RSA_generate_key(params->keylength, eValue, + NULL, NULL); + if (sslPrivKey == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_KEYGEN_FAILED; + } else { + if (privkey != NULL && + EVP_PKEY_set1_RSA(eprikey, sslPrivKey)) { + privkey->kstype = KMF_KEYSTORE_OPENSSL; + privkey->keyalg = KMF_RSA; + privkey->keyclass = KMF_ASYM_PRI; + privkey->israw = FALSE; + privkey->keylabel = (char *)strdup(fullpath); + privkey->keyp = (void *)eprikey; + } + /* OpenSSL derives the public key from the private */ + if (pubkey != NULL && + EVP_PKEY_set1_RSA(epubkey, sslPrivKey)) { + pubkey->kstype = KMF_KEYSTORE_OPENSSL; + pubkey->keyalg = KMF_RSA; + pubkey->israw = FALSE; + pubkey->keyclass = KMF_ASYM_PUB; + pubkey->keylabel = (char *)strdup(fullpath); + pubkey->keyp = (void *)epubkey; + } + } + } else if (params->keytype == KMF_DSA) { + sslDSAKey = DSA_new(); + if (sslDSAKey == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + return (KMF_ERR_MEMORY); + } + + if ((sslDSAKey->p = BN_bin2bn(P, sizeof (P), sslDSAKey->p)) == + NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_KEYGEN_FAILED; + goto cleanup; + } + if ((sslDSAKey->q = BN_bin2bn(Q, sizeof (Q), sslDSAKey->q)) == + NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_KEYGEN_FAILED; + goto cleanup; + } + if ((sslDSAKey->g = BN_bin2bn(G, sizeof (G), sslDSAKey->g)) == + NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_KEYGEN_FAILED; + goto cleanup; + } + + if (!DSA_generate_key(sslDSAKey)) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_KEYGEN_FAILED; + goto cleanup; + } + + if (privkey != NULL) { + privkey->kstype = KMF_KEYSTORE_OPENSSL; + privkey->keyalg = KMF_DSA; + privkey->keyclass = KMF_ASYM_PRI; + privkey->israw = FALSE; + privkey->keylabel = (char *)strdup(fullpath); + if (EVP_PKEY_set1_DSA(eprikey, sslDSAKey)) { + privkey->keyp = (void *)eprikey; + } else { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_KEYGEN_FAILED; + goto cleanup; + } + } + if (pubkey != NULL) { + DSA *dp = DSA_new(); + /* Make a copy for the public key */ + if (dp != NULL) { + if ((dp->p = BN_new()) == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_MEMORY; + DSA_free(dp); + goto cleanup; + } + if ((dp->q = BN_new()) == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_MEMORY; + BN_free(dp->p); + DSA_free(dp); + goto cleanup; + } + if ((dp->g = BN_new()) == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_MEMORY; + BN_free(dp->q); + BN_free(dp->p); + DSA_free(dp); + goto cleanup; + } + if ((dp->pub_key = BN_new()) == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_MEMORY; + BN_free(dp->q); + BN_free(dp->p); + BN_free(dp->g); + DSA_free(dp); + goto cleanup; + } + (void) BN_copy(dp->p, sslDSAKey->p); + (void) BN_copy(dp->q, sslDSAKey->q); + (void) BN_copy(dp->g, sslDSAKey->g); + (void) BN_copy(dp->pub_key, sslDSAKey->pub_key); + + pubkey->kstype = KMF_KEYSTORE_OPENSSL; + pubkey->keyalg = KMF_DSA; + pubkey->keyclass = KMF_ASYM_PUB; + pubkey->israw = FALSE; + pubkey->keylabel = (char *)strdup(fullpath); + + if (EVP_PKEY_set1_DSA(epubkey, sslDSAKey)) { + pubkey->keyp = (void *)epubkey; + } else { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_KEYGEN_FAILED; + goto cleanup; + } + } + } + } + + if (rv != KMF_OK) { + goto cleanup; + } + + /* Store the private key to the keyfile */ + format = params->sslparms.format; + out = BIO_new_file(fullpath, "wb"); + if (out == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_OPEN_FILE; + goto cleanup; + } + rv = ssl_write_private_key(kmfh, format, out, ¶ms->cred, eprikey); + +cleanup: + if (rv != KMF_OK) { + if (eprikey != NULL) + EVP_PKEY_free(eprikey); + + if (epubkey != NULL) + EVP_PKEY_free(epubkey); + + if (pubkey->keylabel) { + free(pubkey->keylabel); + pubkey->keylabel = NULL; + } + + if (privkey->keylabel) { + free(privkey->keylabel); + privkey->keylabel = NULL; + } + + pubkey->keyp = NULL; + privkey->keyp = NULL; + } + + if (sslPrivKey) + RSA_free(sslPrivKey); + + if (sslDSAKey) + DSA_free(sslDSAKey); + + + if (out != NULL) + (void) BIO_free(out); + + if (fullpath) + free(fullpath); + + /* Protect the file by making it read-only */ + if (rv == KMF_OK) { + (void) chmod(fullpath, 0400); + } + return (rv); +} + +KMF_RETURN +OpenSSL_SignData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key, + KMF_OID *AlgOID, KMF_DATA *tobesigned, KMF_DATA *output) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_ALGORITHM_INDEX AlgId; + EVP_MD_CTX ctx; + const EVP_MD *md; + if (key == NULL || AlgOID == NULL || + tobesigned == NULL || output == NULL || + tobesigned->Data == NULL || + output->Data == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* Map the OID to an OpenSSL algorithm */ + AlgId = X509_AlgorithmOidToAlgId(AlgOID); + if (AlgId == KMF_ALGID_NONE) + return (KMF_ERR_BAD_PARAMETER); + + if (key->keyalg == KMF_RSA) { + EVP_PKEY *pkey = (EVP_PKEY *)key->keyp; + uchar_t *p; + uint32_t len; + if (AlgId == KMF_ALGID_MD5WithRSA) + md = EVP_md5(); + else if (AlgId == KMF_ALGID_MD2WithRSA) + md = EVP_md2(); + else if (AlgId == KMF_ALGID_SHA1WithRSA) + md = EVP_sha1(); + else + return (KMF_ERR_BAD_PARAMETER); + + if (md == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + return (KMF_ERR_MEMORY); + } + + (void) EVP_MD_CTX_init(&ctx); + (void) EVP_SignInit_ex(&ctx, md, NULL); + (void) EVP_SignUpdate(&ctx, tobesigned->Data, + (uint32_t)tobesigned->Length); + len = (uint32_t)output->Length; + p = output->Data; + if (!EVP_SignFinal(&ctx, p, &len, pkey)) { + SET_ERROR(kmfh, ERR_get_error()); + output->Length = 0; + } + output->Length = len; + (void) EVP_MD_CTX_cleanup(&ctx); + } else if (key->keyalg == KMF_DSA) { + DSA *dsa = EVP_PKEY_get1_DSA(key->keyp); + + uchar_t hash[EVP_MAX_MD_SIZE]; + uint32_t hashlen; + DSA_SIG *dsasig; + + /* + * OpenSSL EVP_Sign operation automatically converts to + * ASN.1 output so we do the operations separately so we + * are assured of NOT getting ASN.1 output returned. + * KMF does not want ASN.1 encoded results because + * not all mechanisms return ASN.1 encodings (PKCS#11 + * and NSS return raw signature data). + */ + md = EVP_sha1(); + EVP_MD_CTX_init(&ctx); + (void) EVP_DigestInit_ex(&ctx, md, NULL); + (void) EVP_DigestUpdate(&ctx, tobesigned->Data, + tobesigned->Length); + (void) EVP_DigestFinal_ex(&ctx, hash, &hashlen); + (void) EVP_MD_CTX_cleanup(&ctx); + + dsasig = DSA_do_sign(hash, hashlen, dsa); + if (dsasig != NULL) { + int i; + output->Length = i = BN_bn2bin(dsasig->r, output->Data); + output->Length += BN_bn2bin(dsasig->s, + &output->Data[i]); + DSA_SIG_free(dsasig); + } else { + SET_ERROR(kmfh, ERR_get_error()); + } + } else { + return (KMF_ERR_BAD_PARAMETER); + } +cleanup: + return (ret); +} + +KMF_RETURN +/*ARGSUSED*/ +OpenSSL_DeleteKey(KMF_HANDLE_T handle, KMF_DELETEKEY_PARAMS *params, + KMF_KEY_HANDLE *key, boolean_t destroy) +{ + KMF_RETURN rv = KMF_OK; + if (key == NULL || key->keyp == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (key->keyclass != KMF_ASYM_PUB && + key->keyclass != KMF_ASYM_PRI && + key->keyclass != KMF_SYMMETRIC) + return (KMF_ERR_BAD_KEY_CLASS); + + if (key->keyclass == KMF_SYMMETRIC) { + KMF_FreeRawSymKey((KMF_RAW_SYM_KEY *)key->keyp); + key->keyp = NULL; + } else { + if (key->keyp != NULL) { + EVP_PKEY_free(key->keyp); + key->keyp = NULL; + } + } + + if (key->keylabel != NULL) { + EVP_PKEY *pkey = NULL; + /* If the file exists, make sure it is a proper key. */ + pkey = openssl_load_key(handle, key->keylabel); + if (pkey == NULL) { + free(key->keylabel); + key->keylabel = NULL; + return (KMF_ERR_KEY_NOT_FOUND); + } + EVP_PKEY_free(pkey); + + if (destroy) { + if (unlink(key->keylabel) != 0) { + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + SET_SYS_ERROR(kmfh, errno); + rv = KMF_ERR_INTERNAL; + } + } + if (key->keylabel != NULL) { + free(key->keylabel); + key->keylabel = NULL; + } + } + return (rv); +} + +KMF_RETURN +OpenSSL_ImportCRL(KMF_HANDLE_T handle, KMF_IMPORTCRL_PARAMS *params) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + X509_CRL *xcrl = NULL; + X509 *xcert = NULL; + EVP_PKEY *pkey; + KMF_ENCODE_FORMAT format; + BIO *in = NULL, *out = NULL; + int openssl_ret = 0; + char *outcrlfile = NULL; + KMF_ENCODE_FORMAT outformat; + + if (params == NULL || params->sslparms.crlfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + if (params->sslparms.crl_check == B_TRUE && + params->sslparms.certfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + outcrlfile = get_fullpath(params->sslparms.dirpath, + params->sslparms.outcrlfile); + + if (outcrlfile == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (isdir(outcrlfile)) { + free(outcrlfile); + return (KMF_ERR_BAD_PARAMETER); + } + + ret = KMF_IsCRLFile(handle, params->sslparms.crlfile, &format); + if (ret != KMF_OK) { + free(outcrlfile); + return (ret); + } + + in = BIO_new_file(params->sslparms.crlfile, "rb"); + if (in == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto end; + } + + if (format == KMF_FORMAT_ASN1) { + xcrl = d2i_X509_CRL_bio(in, NULL); + } else if (format == KMF_FORMAT_PEM) { + xcrl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); + } + + if (xcrl == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CRLFILE; + goto end; + } + + /* If bypasscheck is specified, no need to verify. */ + if (params->sslparms.crl_check == B_FALSE) { + goto output; + } + + ret = KMF_IsCertFile(handle, params->sslparms.certfile, &format); + if (ret != KMF_OK) + goto end; + + /* Read in the CA cert file and convert to X509 */ + if (BIO_read_filename(in, params->sslparms.certfile) <= 0) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto end; + } + + if (format == KMF_FORMAT_ASN1) { + xcert = d2i_X509_bio(in, NULL); + } else if (format == KMF_FORMAT_PEM) { + xcert = PEM_read_bio_X509(in, NULL, NULL, NULL); + } else { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + + if (xcert == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + /* Now get the public key from the CA cert */ + pkey = X509_get_pubkey(xcert); + if (!pkey) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CERTFILE; + goto end; + } + + /* Verify the CRL with the CA's public key */ + openssl_ret = X509_CRL_verify(xcrl, pkey); + EVP_PKEY_free(pkey); + if (openssl_ret > 0) { + ret = KMF_OK; /* verify succeed */ + } else { + SET_ERROR(kmfh, openssl_ret); + ret = KMF_ERR_BAD_CRLFILE; + } + +output: + outformat = params->sslparms.format; + + out = BIO_new_file(outcrlfile, "wb"); + if (out == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto end; + } + + if (outformat == KMF_FORMAT_ASN1) { + openssl_ret = (int)i2d_X509_CRL_bio(out, xcrl); + } else if (outformat == KMF_FORMAT_PEM) { + openssl_ret = PEM_write_bio_X509_CRL(out, xcrl); + } else { + ret = KMF_ERR_BAD_PARAMETER; + goto end; + } + + if (openssl_ret <= 0) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_WRITE_FILE; + } else { + ret = KMF_OK; + } + +end: + if (xcrl != NULL) + X509_CRL_free(xcrl); + + if (xcert != NULL) + X509_free(xcert); + + if (in != NULL) + (void) BIO_free(in); + + if (out != NULL) + (void) BIO_free(out); + + if (outcrlfile != NULL) + free(outcrlfile); + + return (ret); +} + +KMF_RETURN +OpenSSL_ListCRL(KMF_HANDLE_T handle, KMF_LISTCRL_PARAMS *params, + char **crldata) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + X509_CRL *x = NULL; + KMF_ENCODE_FORMAT format; + char *crlfile = NULL; + BIO *in = NULL; + BIO *mem = NULL; + long len; + char *memptr; + char *data = NULL; + + if (params == NULL || params->sslparms.crlfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + crlfile = get_fullpath(params->sslparms.dirpath, + params->sslparms.crlfile); + + if (crlfile == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (isdir(crlfile)) { + free(crlfile); + return (KMF_ERR_BAD_PARAMETER); + } + + ret = KMF_IsCRLFile(handle, crlfile, &format); + if (ret != KMF_OK) { + free(crlfile); + return (ret); + } + + if (bio_err == NULL) + bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); + + in = BIO_new_file(crlfile, "rb"); + if (in == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto end; + } + + if (format == KMF_FORMAT_ASN1) { + x = d2i_X509_CRL_bio(in, NULL); + } else if (format == KMF_FORMAT_PEM) { + x = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); + } + + if (x == NULL) { /* should not happen */ + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto end; + } + + mem = BIO_new(BIO_s_mem()); + if (mem == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_MEMORY; + goto end; + } + + (void) X509_CRL_print(mem, x); + len = BIO_get_mem_data(mem, &memptr); + if (len <= 0) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_MEMORY; + goto end; + } + + data = malloc(len + 1); + if (data == NULL) { + ret = KMF_ERR_MEMORY; + goto end; + } + + (void) memcpy(data, memptr, len); + data[len] = '\0'; + *crldata = data; + +end: + if (x != NULL) + X509_CRL_free(x); + + if (crlfile != NULL) + free(crlfile); + + if (in != NULL) + (void) BIO_free(in); + + if (mem != NULL) + (void) BIO_free(mem); + + return (ret); +} + +KMF_RETURN +OpenSSL_DeleteCRL(KMF_HANDLE_T handle, KMF_DELETECRL_PARAMS *params) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_ENCODE_FORMAT format; + char *crlfile = NULL; + BIO *in = NULL; + + if (params == NULL || params->sslparms.crlfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + crlfile = get_fullpath(params->sslparms.dirpath, + params->sslparms.crlfile); + + if (crlfile == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (isdir(crlfile)) { + ret = KMF_ERR_BAD_PARAMETER; + goto end; + } + + ret = KMF_IsCRLFile(handle, crlfile, &format); + if (ret != KMF_OK) + goto end; + + if (unlink(crlfile) != 0) { + SET_SYS_ERROR(kmfh, errno); + ret = KMF_ERR_INTERNAL; + goto end; + } + +end: + if (in != NULL) + (void) BIO_free(in); + if (crlfile != NULL) + free(crlfile); + + return (ret); +} + + +KMF_RETURN +OpenSSL_FindCertInCRL(KMF_HANDLE_T handle, KMF_FINDCERTINCRL_PARAMS *params) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_ENCODE_FORMAT format; + BIO *in = NULL; + X509 *xcert = NULL; + X509_CRL *xcrl = NULL; + STACK_OF(X509_REVOKED) *revoke_stack = NULL; + X509_REVOKED *revoke; + int i; + + if (params == NULL || params->sslparms.crlfile == NULL || + params->sslparms.certfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + ret = KMF_IsCRLFile(handle, params->sslparms.crlfile, &format); + if (ret != KMF_OK) + return (ret); + + /* Read the CRL file and load it into a X509_CRL structure */ + in = BIO_new_file(params->sslparms.crlfile, "rb"); + if (in == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto end; + } + + if (format == KMF_FORMAT_ASN1) { + xcrl = d2i_X509_CRL_bio(in, NULL); + } else if (format == KMF_FORMAT_PEM) { + xcrl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); + } + + if (xcrl == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CRLFILE; + goto end; + } + (void) BIO_free(in); + + /* Read the Certificate file and load it into a X509 structure */ + ret = KMF_IsCertFile(handle, params->sslparms.certfile, &format); + if (ret != KMF_OK) + goto end; + + in = BIO_new_file(params->sslparms.certfile, "rb"); + if (in == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto end; + } + + if (format == KMF_FORMAT_ASN1) { + xcert = d2i_X509_bio(in, NULL); + } else if (format == KMF_FORMAT_PEM) { + xcert = PEM_read_bio_X509(in, NULL, NULL, NULL); + } + + if (xcert == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CERTFILE; + goto end; + } + + /* Check if the certificate and the CRL have same issuer */ + if (X509_NAME_cmp(xcert->cert_info->issuer, xcrl->crl->issuer) != 0) { + ret = KMF_ERR_ISSUER; + goto end; + } + + /* Check to see if the certificate serial number is revoked */ + revoke_stack = X509_CRL_get_REVOKED(xcrl); + if (sk_X509_REVOKED_num(revoke_stack) <= 0) { + /* No revoked certificates in the CRL file */ + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_EMPTY_CRL; + goto end; + } + + for (i = 0; i < sk_X509_REVOKED_num(revoke_stack); i++) { + /*LINTED*/ + revoke = sk_X509_REVOKED_value(revoke_stack, i); + if (ASN1_INTEGER_cmp(xcert->cert_info->serialNumber, + revoke->serialNumber) == 0) { + break; + } + } + + if (i < sk_X509_REVOKED_num(revoke_stack)) { + ret = KMF_OK; + } else { + ret = KMF_ERR_NOT_REVOKED; + } + +end: + if (in != NULL) + (void) BIO_free(in); + if (xcrl != NULL) + X509_CRL_free(xcrl); + if (xcert != NULL) + X509_free(xcert); + + return (ret); +} + +KMF_RETURN +OpenSSL_GetErrorString(KMF_HANDLE_T handle, char **msgstr) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + char str[256]; /* OpenSSL needs at least 120 byte buffer */ + + ERR_error_string_n(kmfh->lasterr.errcode, str, sizeof (str)); + if (strlen(str)) { + *msgstr = (char *)strdup(str); + if ((*msgstr) == NULL) + ret = KMF_ERR_MEMORY; + } else { + *msgstr = NULL; + } + + return (ret); +} + +static int +ext2NID(int kmfext) +{ + switch (kmfext) { + case KMF_X509_EXT_KEY_USAGE: + return (NID_key_usage); + case KMF_X509_EXT_PRIV_KEY_USAGE_PERIOD: + return (NID_private_key_usage_period); + case KMF_X509_EXT_CERT_POLICIES: + return (NID_certificate_policies); + case KMF_X509_EXT_SUBJ_ALTNAME: + return (NID_subject_alt_name); + case KMF_X509_EXT_ISSUER_ALTNAME: + return (NID_issuer_alt_name); + case KMF_X509_EXT_BASIC_CONSTRAINTS: + return (NID_basic_constraints); + case KMF_X509_EXT_EXT_KEY_USAGE: + return (NID_ext_key_usage); + case KMF_X509_EXT_AUTH_KEY_ID: + return (NID_authority_key_identifier); + case KMF_X509_EXT_CRL_DIST_POINTS: + return (NID_crl_distribution_points); + case KMF_X509_EXT_SUBJ_KEY_ID: + return (NID_subject_key_identifier); + case KMF_X509_EXT_POLICY_MAPPINGS: + return (OBJ_sn2nid("policyMappings")); + case KMF_X509_EXT_NAME_CONSTRAINTS: + return (OBJ_sn2nid("nameConstraints")); + case KMF_X509_EXT_POLICY_CONSTRAINTS: + return (OBJ_sn2nid("policyConstraints")); + case KMF_X509_EXT_INHIBIT_ANY_POLICY: + return (OBJ_sn2nid("inhibitAnyPolicy")); + case KMF_X509_EXT_FRESHEST_CRL: + return (OBJ_sn2nid("freshestCRL")); + default: + return (NID_undef); + } +} + +KMF_RETURN +OpenSSL_CertGetPrintable(KMF_HANDLE_T handle, const KMF_DATA *pcert, + KMF_PRINTABLE_ITEM flag, char *resultStr) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + X509 *xcert = NULL; + unsigned char *outbuf = NULL; + unsigned char *outbuf_p; + char *tmpstr = NULL; + int j; + int ext_index, nid, len; + BIO *mem = NULL; + STACK *emlst = NULL; + X509_EXTENSION *ex; + X509_CINF *ci; + + if (pcert == NULL || pcert->Data == NULL || pcert->Length == 0) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* copy cert data to outbuf */ + outbuf = malloc(pcert->Length); + if (outbuf == NULL) { + return (KMF_ERR_MEMORY); + } + (void) memcpy(outbuf, pcert->Data, pcert->Length); + + outbuf_p = outbuf; /* use a temp pointer; required by openssl */ + xcert = d2i_X509(NULL, (const uchar_t **)&outbuf_p, pcert->Length); + if (xcert == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_ENCODING; + goto out; + } + + mem = BIO_new(BIO_s_mem()); + if (mem == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_MEMORY; + goto out; + } + + switch (flag) { + case KMF_CERT_ISSUER: + (void) X509_NAME_print_ex(mem, X509_get_issuer_name(xcert), 0, + XN_FLAG_SEP_CPLUS_SPC); + len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN); + break; + + case KMF_CERT_SUBJECT: + (void) X509_NAME_print_ex(mem, X509_get_subject_name(xcert), 0, + XN_FLAG_SEP_CPLUS_SPC); + len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN); + break; + + case KMF_CERT_VERSION: + tmpstr = i2s_ASN1_INTEGER(NULL, xcert->cert_info->version); + (void) strncpy(resultStr, tmpstr, KMF_CERT_PRINTABLE_LEN); + OPENSSL_free(tmpstr); + len = strlen(resultStr); + break; + + case KMF_CERT_SERIALNUM: + if (i2a_ASN1_INTEGER(mem, X509_get_serialNumber(xcert)) > 0) { + (void) strcpy(resultStr, "0x"); + len = BIO_gets(mem, &resultStr[2], + KMF_CERT_PRINTABLE_LEN - 2); + } + break; + + case KMF_CERT_NOTBEFORE: + (void) ASN1_TIME_print(mem, X509_get_notBefore(xcert)); + len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN); + break; + + case KMF_CERT_NOTAFTER: + (void) ASN1_TIME_print(mem, X509_get_notAfter(xcert)); + len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN); + break; + + case KMF_CERT_PUBKEY_DATA: + { + EVP_PKEY *pkey = X509_get_pubkey(xcert); + if (pkey == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_ENCODING; + goto out; + } + + if (pkey->type == EVP_PKEY_RSA) { + (void) BIO_printf(mem, + "RSA Public Key: (%d bit)\n", + BN_num_bits(pkey->pkey.rsa->n)); + (void) RSA_print(mem, pkey->pkey.rsa, 0); + } else if (pkey->type == EVP_PKEY_DSA) { + (void) BIO_printf(mem, + "%12sDSA Public Key:\n", ""); + (void) DSA_print(mem, pkey->pkey.dsa, 0); + } else { + (void) BIO_printf(mem, + "%12sUnknown Public Key:\n", ""); + } + (void) BIO_printf(mem, "\n"); + EVP_PKEY_free(pkey); + } + len = BIO_read(mem, resultStr, KMF_CERT_PRINTABLE_LEN); + break; + case KMF_CERT_SIGNATURE_ALG: + case KMF_CERT_PUBKEY_ALG: + if (flag == KMF_CERT_SIGNATURE_ALG) { + len = i2a_ASN1_OBJECT(mem, + xcert->sig_alg->algorithm); + } else { + len = i2a_ASN1_OBJECT(mem, + xcert->cert_info->key->algor->algorithm); + } + + if (len > 0) { + len = BIO_read(mem, resultStr, + KMF_CERT_PRINTABLE_LEN); + } + break; + + case KMF_CERT_EMAIL: + emlst = X509_get1_email(xcert); + for (j = 0; j < sk_num(emlst); j++) + (void) BIO_printf(mem, "%s\n", sk_value(emlst, j)); + + len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN); + X509_email_free(emlst); + break; + case KMF_X509_EXT_ISSUER_ALTNAME: + case KMF_X509_EXT_SUBJ_ALTNAME: + case KMF_X509_EXT_KEY_USAGE: + case KMF_X509_EXT_PRIV_KEY_USAGE_PERIOD: + case KMF_X509_EXT_CERT_POLICIES: + case KMF_X509_EXT_BASIC_CONSTRAINTS: + case KMF_X509_EXT_NAME_CONSTRAINTS: + case KMF_X509_EXT_POLICY_CONSTRAINTS: + case KMF_X509_EXT_EXT_KEY_USAGE: + case KMF_X509_EXT_INHIBIT_ANY_POLICY: + case KMF_X509_EXT_AUTH_KEY_ID: + case KMF_X509_EXT_SUBJ_KEY_ID: + case KMF_X509_EXT_POLICY_MAPPINGS: + case KMF_X509_EXT_CRL_DIST_POINTS: + case KMF_X509_EXT_FRESHEST_CRL: + nid = ext2NID(flag); + if (nid == NID_undef) { + ret = KMF_ERR_EXTENSION_NOT_FOUND; + goto out; + } + ci = xcert->cert_info; + + ext_index = X509v3_get_ext_by_NID(ci->extensions, nid, -1); + if (ext_index == -1) { + SET_ERROR(kmfh, ERR_get_error()); + + ret = KMF_ERR_EXTENSION_NOT_FOUND; + goto out; + } + ex = X509v3_get_ext(ci->extensions, ext_index); + + (void) i2a_ASN1_OBJECT(mem, X509_EXTENSION_get_object(ex)); + + if (BIO_printf(mem, ": %s\n", + X509_EXTENSION_get_critical(ex) ? "critical" : "") <= + 0) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_ENCODING; + goto out; + } + if (!X509V3_EXT_print(mem, ex, X509V3_EXT_DUMP_UNKNOWN, 4)) { + (void) BIO_printf(mem, "%*s", 4, ""); + (void) M_ASN1_OCTET_STRING_print(mem, ex->value); + } + if (BIO_write(mem, "\n", 1) <= 0) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_ENCODING; + goto out; + } + len = BIO_read(mem, resultStr, KMF_CERT_PRINTABLE_LEN); + } + if (len <= 0) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_ENCODING; + } + +out: + if (outbuf != NULL) { + free(outbuf); + } + + if (xcert != NULL) { + X509_free(xcert); + } + + if (mem != NULL) { + (void) BIO_free(mem); + } + + return (ret); +} +KMF_RETURN +/*ARGSUSED*/ +OpenSSL_GetPrikeyByCert(KMF_HANDLE_T handle, + KMF_CRYPTOWITHCERT_PARAMS *params, + KMF_DATA *SignerCertData, KMF_KEY_HANDLE *key, + KMF_KEY_ALG keytype) +{ + KMF_RETURN rv = KMF_OK; + KMF_FINDKEY_PARAMS fkparms; + uint32_t numkeys = 0; + + if (params == NULL && params->sslparms.keyfile == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * This is really just a FindKey operation, reuse the + * FindKey function. + */ + (void *)memset(&fkparms, 0, sizeof (fkparms)); + fkparms.kstype = KMF_KEYSTORE_OPENSSL; + fkparms.keyclass = KMF_ASYM_PRI; + fkparms.keytype = keytype; + fkparms.format = params->format; + fkparms.sslparms = params->sslparms; + + rv = OpenSSL_FindKey(handle, &fkparms, key, &numkeys); + + return (rv); +} + +KMF_RETURN +/*ARGSUSED*/ +OpenSSL_DecryptData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key, + KMF_OID *AlgOID, KMF_DATA *ciphertext, + KMF_DATA *output) +{ + KMF_RETURN ret = KMF_OK; + RSA *rsa = NULL; + unsigned int in_len = 0, out_len = 0; + unsigned int total_decrypted = 0, modulus_len = 0; + uint8_t *in_data, *out_data; + int i, blocks; + + if (key == NULL || AlgOID == NULL || + ciphertext == NULL || output == NULL || + ciphertext->Data == NULL || + output->Data == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (key->keyalg == KMF_RSA) { + rsa = EVP_PKEY_get1_RSA((EVP_PKEY *)key->keyp); + modulus_len = RSA_size(rsa); + } else { + return (KMF_ERR_BAD_PARAMETER); + } + + blocks = ciphertext->Length/modulus_len; + out_data = output->Data; + in_data = ciphertext->Data; + out_len = modulus_len - 11; + in_len = modulus_len; + + for (i = 0; i < blocks; i++) { + out_len = RSA_private_decrypt(in_len, + in_data, out_data, rsa, RSA_PKCS1_PADDING); + + if (out_len == 0) { + ret = KMF_ERR_INTERNAL; + goto cleanup; + } + + out_data += out_len; + total_decrypted += out_len; + in_data += in_len; + } + + output->Length = total_decrypted; + +cleanup: + RSA_free(rsa); + if (ret != KMF_OK) + output->Length = 0; + + return (ret); + +} + +/* + * This function will create a certid from issuer_cert and user_cert. + * The caller should use OCSP_CERTID_free(OCSP_CERTID *) to deallocate + * certid memory after use. + */ +static KMF_RETURN +create_certid(KMF_HANDLE_T handle, const KMF_DATA *issuer_cert, + const KMF_DATA *user_cert, OCSP_CERTID **certid) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + X509 *issuer = NULL; + X509 *cert = NULL; + unsigned char *ptmp; + + if (issuer_cert == NULL || user_cert == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* convert the DER-encoded issuer cert to an internal X509 */ + ptmp = issuer_cert->Data; + issuer = d2i_X509(NULL, (const uchar_t **)&ptmp, + issuer_cert->Length); + if (issuer == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OCSP_BAD_ISSUER; + goto end; + } + + /* convert the DER-encoded user cert to an internal X509 */ + ptmp = user_cert->Data; + cert = d2i_X509(NULL, (const uchar_t **)&ptmp, + user_cert->Length); + if (cert == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + + ret = KMF_ERR_OCSP_BAD_CERT; + goto end; + } + + /* create a CERTID */ + *certid = OCSP_cert_to_id(NULL, cert, issuer); + if (*certid == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OCSP_CERTID; + goto end; + } + +end: + if (issuer != NULL) { + X509_free(issuer); + } + + if (cert != NULL) { + X509_free(cert); + } + + return (ret); +} + +KMF_RETURN +OpenSSL_CreateOCSPRequest(KMF_HANDLE_T handle, KMF_OCSPREQUEST_PARAMS *params, + char *reqfile) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + OCSP_CERTID *id = NULL; + OCSP_REQUEST *req = NULL; + BIO *derbio = NULL; + + if (params->user_cert == NULL || params->issuer_cert == NULL || + reqfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + ret = create_certid(handle, params->issuer_cert, params->user_cert, + &id); + if (ret != KMF_OK) { + return (ret); + } + + /* Create an OCSP request */ + req = OCSP_REQUEST_new(); + if (req == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OCSP_CREATE_REQUEST; + goto end; + } + + if (!OCSP_request_add0_id(req, id)) { + ret = KMF_ERR_OCSP_CREATE_REQUEST; + goto end; + } + + /* Write the request to the output file with DER encoding */ + derbio = BIO_new_file(reqfile, "wb"); + if (!derbio) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto end; + } + if (i2d_OCSP_REQUEST_bio(derbio, req) <= 0) { + ret = KMF_ERR_ENCODING; + } + +end: + /* + * We don't need to free "id" explicitely, because OCSP_REQUEST_free() + * will deallocate certid's space also. + */ + if (req != NULL) { + OCSP_REQUEST_free(req); + } + + if (derbio != NULL) { + (void) BIO_free(derbio); + } + + return (ret); +} + +/* ocsp_find_signer_sk() is copied from openssl source */ +static X509 *ocsp_find_signer_sk(STACK_OF(X509) *certs, OCSP_RESPID *id) +{ + int i; + unsigned char tmphash[SHA_DIGEST_LENGTH], *keyhash; + + /* Easy if lookup by name */ + if (id->type == V_OCSP_RESPID_NAME) + return (X509_find_by_subject(certs, id->value.byName)); + + /* Lookup by key hash */ + + /* If key hash isn't SHA1 length then forget it */ + if (id->value.byKey->length != SHA_DIGEST_LENGTH) + return (NULL); + + keyhash = id->value.byKey->data; + /* Calculate hash of each key and compare */ + for (i = 0; i < sk_X509_num(certs); i++) { + /*LINTED*/ + X509 *x = sk_X509_value(certs, i); + (void) X509_pubkey_digest(x, EVP_sha1(), tmphash, NULL); + if (!memcmp(keyhash, tmphash, SHA_DIGEST_LENGTH)) + return (x); + } + return (NULL); +} + +/* ocsp_find_signer() is copied from openssl source */ +/*ARGSUSED*/ +static int +ocsp_find_signer(X509 **psigner, OCSP_BASICRESP *bs, STACK_OF(X509) *certs, + X509_STORE *st, unsigned long flags) +{ + X509 *signer; + OCSP_RESPID *rid = bs->tbsResponseData->responderId; + if ((signer = ocsp_find_signer_sk(certs, rid))) { + *psigner = signer; + return (2); + } + if (!(flags & OCSP_NOINTERN) && + (signer = ocsp_find_signer_sk(bs->certs, rid))) { + *psigner = signer; + return (1); + } + /* Maybe lookup from store if by subject name */ + + *psigner = NULL; + return (0); +} + +/* + * This function will verify the signature of a basic response, using + * the public key from the OCSP responder certificate. + */ +static KMF_RETURN +check_response_signature(KMF_HANDLE_T handle, OCSP_BASICRESP *bs, + KMF_DATA *signer_cert, KMF_DATA *issuer_cert) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + STACK_OF(X509) *cert_stack = NULL; + X509 *signer = NULL; + X509 *issuer = NULL; + EVP_PKEY *skey = NULL; + unsigned char *ptmp; + + + if (bs == NULL || issuer_cert == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * Find the certificate that signed the basic response. + * + * If signer_cert is not NULL, we will use that as the signer cert. + * Otherwise, we will check if the issuer cert is actually the signer. + * If we still do not find a signer, we will look for it from the + * certificate list came with the response file. + */ + if (signer_cert != NULL) { + ptmp = signer_cert->Data; + signer = d2i_X509(NULL, (const uchar_t **)&ptmp, + signer_cert->Length); + if (signer == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OCSP_BAD_SIGNER; + goto end; + } + } else { + /* + * Convert the issuer cert into X509 and push it into a + * stack to be used by ocsp_find_signer(). + */ + ptmp = issuer_cert->Data; + issuer = d2i_X509(NULL, (const uchar_t **)&ptmp, + issuer_cert->Length); + if (issuer == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OCSP_BAD_ISSUER; + goto end; + } + + if ((cert_stack = sk_X509_new_null()) == NULL) { + ret = KMF_ERR_INTERNAL; + goto end; + } + + if (sk_X509_push(cert_stack, issuer) == NULL) { + ret = KMF_ERR_INTERNAL; + goto end; + } + + ret = ocsp_find_signer(&signer, bs, cert_stack, NULL, 0); + if (!ret) { + /* can not find the signer */ + ret = KMF_ERR_OCSP_BAD_SIGNER; + goto end; + } + } + + /* Verify the signature of the response */ + skey = X509_get_pubkey(signer); + if (skey == NULL) { + ret = KMF_ERR_OCSP_BAD_SIGNER; + goto end; + } + + ret = OCSP_BASICRESP_verify(bs, skey, 0); + if (ret == 0) { + ret = KMF_ERR_OCSP_RESPONSE_SIGNATURE; + goto end; + } + +end: + if (issuer != NULL) { + X509_free(issuer); + } + + if (signer != NULL) { + X509_free(signer); + } + + if (skey != NULL) { + EVP_PKEY_free(skey); + } + + if (cert_stack != NULL) { + sk_X509_free(cert_stack); + } + + return (ret); +} + + + +KMF_RETURN +OpenSSL_GetOCSPStatusForCert(KMF_HANDLE_T handle, + KMF_OCSPRESPONSE_PARAMS_INPUT *params_in, + KMF_OCSPRESPONSE_PARAMS_OUTPUT *params_out) +{ + KMF_RETURN ret = KMF_OK; + BIO *derbio = NULL; + OCSP_RESPONSE *resp = NULL; + OCSP_BASICRESP *bs = NULL; + OCSP_CERTID *id = NULL; + OCSP_SINGLERESP *single = NULL; + ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; + int index, status, reason; + + if (params_in == NULL || params_in->issuer_cert == NULL || + params_in->user_cert == NULL || params_in->response == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + if (params_out == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* Read in the response */ + derbio = BIO_new_mem_buf(params_in->response->Data, + params_in->response->Length); + if (!derbio) { + ret = KMF_ERR_MEMORY; + return (ret); + } + + resp = d2i_OCSP_RESPONSE_bio(derbio, NULL); + if (resp == NULL) { + ret = KMF_ERR_OCSP_MALFORMED_RESPONSE; + goto end; + } + + /* Check the response status */ + status = OCSP_response_status(resp); + params_out->response_status = status; + if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + ret = KMF_ERR_OCSP_RESPONSE_STATUS; + goto end; + } + +#ifdef DEBUG + printf("Successfully checked the response file status.\n"); +#endif /* DEBUG */ + + /* Extract basic response */ + bs = OCSP_response_get1_basic(resp); + if (bs == NULL) { + ret = KMF_ERR_OCSP_NO_BASIC_RESPONSE; + goto end; + } + +#ifdef DEBUG + printf("Successfully retrieved the basic response.\n"); +#endif /* DEBUG */ + + /* Check the basic response signature if required */ + if (params_in->ignore_response_sign == B_FALSE) { + ret = check_response_signature(handle, bs, + params_in->signer_cert, params_in->issuer_cert); + if (ret != KMF_OK) + goto end; + } + +#ifdef DEBUG + printf("Successfully verified the response signature.\n"); +#endif /* DEBUG */ + + /* Create a certid for the certificate in question */ + ret = create_certid(handle, params_in->issuer_cert, + params_in->user_cert, &id); + if (ret != KMF_OK) { + ret = KMF_ERR_OCSP_CERTID; + goto end; + } + +#ifdef DEBUG + printf("successfully created a certid for the cert.\n"); +#endif /* DEBUG */ + + /* Find the index of the single response for the certid */ + index = OCSP_resp_find(bs, id, -1); + if (index < 0) { + /* cound not find this certificate in the response */ + ret = KMF_ERR_OCSP_UNKNOWN_CERT; + goto end; + } + +#ifdef DEBUG + printf("Successfully found the single response index for the cert.\n"); +#endif /* DEBUG */ + + /* Retrieve the single response and get the cert status */ + single = OCSP_resp_get0(bs, index); + status = OCSP_single_get0_status(single, &reason, &rev, &thisupd, + &nextupd); + if (status == V_OCSP_CERTSTATUS_GOOD) { + params_out->cert_status = OCSP_GOOD; + } else if (status == V_OCSP_CERTSTATUS_UNKNOWN) { + params_out->cert_status = OCSP_UNKNOWN; + } else { /* revoked */ + params_out->cert_status = OCSP_REVOKED; + params_out->reason = reason; + } + ret = KMF_OK; + + /* Verify the time */ + if (!OCSP_check_validity(thisupd, nextupd, 300, + params_in->response_lifetime)) { + ret = KMF_ERR_OCSP_STATUS_TIME_INVALID; + goto end; + } + +#ifdef DEBUG + printf("Successfully verify the time.\n"); +#endif /* DEBUG */ + +end: + if (derbio != NULL) + (void) BIO_free(derbio); + + if (resp != NULL) + OCSP_RESPONSE_free(resp); + + if (bs != NULL) + OCSP_BASICRESP_free(bs); + + if (id != NULL) + OCSP_CERTID_free(id); + + return (ret); +} + +static KMF_RETURN +fetch_key(KMF_HANDLE_T handle, char *path, + KMF_KEY_CLASS keyclass, KMF_KEY_HANDLE *key) +{ + KMF_RETURN rv = KMF_OK; + EVP_PKEY *pkey; + KMF_RAW_SYM_KEY *rkey = NULL; + + /* Make sure the requested file actually exists. */ + if (access(path, F_OK) != 0) { + return (KMF_ERR_KEY_NOT_FOUND); + } + + if (keyclass == KMF_ASYM_PRI || + keyclass == KMF_ASYM_PUB) { + pkey = openssl_load_key(handle, path); + if (pkey == NULL) { + return (KMF_ERR_KEY_NOT_FOUND); + } + if (key != NULL) { + if (pkey->type == EVP_PKEY_RSA) + key->keyalg = KMF_RSA; + else if (pkey->type == EVP_PKEY_DSA) + key->keyalg = KMF_DSA; + + key->kstype = KMF_KEYSTORE_OPENSSL; + key->keyclass = keyclass; + key->keyp = (void *)pkey; + key->israw = FALSE; + key->keylabel = path; + } else { + EVP_PKEY_free(pkey); + pkey = NULL; + } + } else if (keyclass == KMF_SYMMETRIC) { + KMF_ENCODE_FORMAT fmt; + /* + * If the file is a recognized format, + * then it is NOT a symmetric key. + */ + rv = KMF_GetFileFormat(path, &fmt); + if (rv == KMF_OK || fmt != 0) { + return (KMF_ERR_KEY_NOT_FOUND); + } else if (rv == KMF_ERR_ENCODING) { + /* + * If we don't know the encoding, + * it is probably a symmetric key. + */ + rv = KMF_OK; + } + + if (key != NULL) { + KMF_DATA keyvalue; + rkey = malloc(sizeof (KMF_RAW_SYM_KEY)); + if (rkey == NULL) { + rv = KMF_ERR_MEMORY; + goto out; + } + + (void) memset(rkey, 0, sizeof (KMF_RAW_SYM_KEY)); + rv = KMF_ReadInputFile(handle, path, &keyvalue); + if (rv != KMF_OK) + goto out; + + rkey->keydata.len = keyvalue.Length; + rkey->keydata.val = keyvalue.Data; + + key->kstype = KMF_KEYSTORE_OPENSSL; + key->keyclass = keyclass; + key->israw = TRUE; + key->keylabel = path; + key->keyp = (void *)rkey; + } + } +out: + if (rv != KMF_OK) { + if (rkey != NULL) { + KMF_FreeRawSymKey(rkey); + } + if (pkey != NULL) + EVP_PKEY_free(pkey); + + if (key != NULL) { + key->keyalg = KMF_KEYALG_NONE; + key->keyclass = KMF_KEYCLASS_NONE; + key->keyp = NULL; + } + } + + return (rv); +} + +KMF_RETURN +OpenSSL_FindKey(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS *params, + KMF_KEY_HANDLE *key, uint32_t *numkeys) +{ + KMF_RETURN rv = KMF_OK; + char *fullpath = NULL; + + if (handle == NULL || params == NULL || numkeys == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (params->keyclass != KMF_ASYM_PUB && + params->keyclass != KMF_ASYM_PRI && + params->keyclass != KMF_SYMMETRIC) + return (KMF_ERR_BAD_KEY_CLASS); + + fullpath = get_fullpath(params->sslparms.dirpath, + params->sslparms.keyfile); + + if (fullpath == NULL) + return (KMF_ERR_BAD_PARAMETER); + + *numkeys = 0; + + if (isdir(fullpath)) { + DIR *dirp; + struct dirent *dp; + int n = 0; + + /* open all files in the directory and attempt to read them */ + if ((dirp = opendir(fullpath)) == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + rewinddir(dirp); + while ((dp = readdir(dirp)) != NULL) { + if (strcmp(dp->d_name, ".") && + strcmp(dp->d_name, "..")) { + char *fname; + + fname = get_fullpath(fullpath, + (char *)&dp->d_name); + + rv = fetch_key(handle, fname, + params->keyclass, + key ? &key[n] : NULL); + + if (rv == KMF_OK) + n++; + + if (rv != KMF_OK || key == NULL) + free(fname); + } + } + (void) closedir(dirp); + free(fullpath); + (*numkeys) = n; + } else { + rv = fetch_key(handle, fullpath, params->keyclass, key); + if (rv == KMF_OK) + (*numkeys) = 1; + + if (rv != KMF_OK || key == NULL) + free(fullpath); + } + + if ((*numkeys) == 0) + rv = KMF_ERR_KEY_NOT_FOUND; + + return (rv); +} + +#define HANDLE_PK12_ERROR { \ + SET_ERROR(kmfh, ERR_get_error()); \ + rv = KMF_ERR_ENCODING; \ + goto out; \ +} + +static KMF_RETURN +write_pkcs12(KMF_HANDLE *kmfh, + BIO *bio, + KMF_CREDENTIAL *cred, + EVP_PKEY *pkey, + X509 *sslcert) +{ + KMF_RETURN rv = KMF_OK; + STACK_OF(PKCS12_SAFEBAG) *bag_stack = NULL; + PKCS12_SAFEBAG *bag = NULL; + PKCS7 *cert_authsafe = NULL; + PKCS8_PRIV_KEY_INFO *p8 = NULL; + PKCS7 *key_authsafe = NULL; + STACK_OF(PKCS7) *authsafe_stack = NULL; + PKCS12 *p12_elem = NULL; + char *lab = NULL; + int lab_len = 0; + unsigned char keyid[EVP_MAX_MD_SIZE]; + unsigned int keyidlen = 0; + + /* Must have at least a cert OR a key */ + if (sslcert == NULL && pkey == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(keyid, 0, sizeof (keyid)); + /* + * Section 1: + * + * The first PKCS#12 container (safebag) will hold the certificates + * associated with this key. The result of this section is a + * PIN-encrypted PKCS#7 container (authsafe). If there are no + * certificates, there is no point in creating the "safebag" or the + * "authsafe" so we go to the next section. + */ + if (sslcert != NULL && pkey != NULL) { + if (X509_check_private_key(sslcert, pkey)) { + (void) X509_digest(sslcert, EVP_sha1(), keyid, + &keyidlen); + } else { + /* The key doesn't match the cert */ + HANDLE_PK12_ERROR + } + } + + bag_stack = sk_PKCS12_SAFEBAG_new_null(); + if (bag_stack == NULL) + return (KMF_ERR_MEMORY); + + if (sslcert != NULL) { + /* Convert cert from X509 struct to PKCS#12 bag */ + bag = PKCS12_x5092certbag(sslcert); + if (bag == NULL) { + HANDLE_PK12_ERROR + } + + /* Add the key id to the certificate bag. */ + if (keyidlen > 0 && + !PKCS12_add_localkeyid(bag, keyid, keyidlen)) { + HANDLE_PK12_ERROR + } + + /* Pile it on the bag_stack. */ + if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag)) { + HANDLE_PK12_ERROR + } +#if 0 + /* No support for CA certs yet */ + if (cacerts != NULL && ncacerts > 0) { + int i; + for (i = 0; i < ncacerts; i++) { + KMF_X509_DER_CERT *c = &cacerts[i]; + X509 *ca = NULL; + + uchar_t *p = (uchar_t *)c->certificate.Data; + ca = d2i_X509(NULL, &p, + c->certificate.Length); + if (ca == NULL) { + HANDLE_PK12_ERROR + } + /* Convert CA cert to PKCS#12 bag. */ + bag = PKCS12_x5092certbag(ca); + if (bag == NULL) { + sk_PKCS12_SAFEBAG_pop_free(bag_stack, + PKCS12_SAFEBAG_free); + HANDLE_PK12_ERROR + } + /* Pile it onto the bag_stack. */ + if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag)) { + HANDLE_PK12_ERROR + } + } + } +#endif + /* Turn bag_stack of certs into encrypted authsafe. */ + cert_authsafe = PKCS12_pack_p7encdata( + NID_pbe_WithSHA1And40BitRC2_CBC, + cred->cred, + cred->credlen, NULL, 0, + PKCS12_DEFAULT_ITER, + bag_stack); + + /* Clear away this bag_stack, we're done with it. */ + sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free); + bag_stack = NULL; + + if (cert_authsafe == NULL) { + HANDLE_PK12_ERROR + } + } + /* + * Section 2: + * + * The second PKCS#12 container (safebag) will hold the private key + * that goes with the certificates above. The results of this section + * is an unencrypted PKCS#7 container (authsafe). If there is no + * private key, there is no point in creating the "safebag" or the + * "authsafe" so we go to the next section. + */ + if (pkey != NULL) { + p8 = EVP_PKEY2PKCS8(pkey); + if (p8 == NULL) { + HANDLE_PK12_ERROR + } + /* Put the shrouded key into a PKCS#12 bag. */ + bag = PKCS12_MAKE_SHKEYBAG( + NID_pbe_WithSHA1And3_Key_TripleDES_CBC, + cred->cred, cred->credlen, + NULL, 0, PKCS12_DEFAULT_ITER, p8); + + /* Clean up the PKCS#8 shrouded key, don't need it now. */ + PKCS8_PRIV_KEY_INFO_free(p8); + p8 = NULL; + + if (bag == NULL) { + HANDLE_PK12_ERROR + } + if (keyidlen && + !PKCS12_add_localkeyid(bag, keyid, keyidlen)) { + HANDLE_PK12_ERROR + } + if (lab != NULL) { + if (!PKCS12_add_friendlyname(bag, + (char *)lab, lab_len)) { + HANDLE_PK12_ERROR + } + } + /* Start a PKCS#12 safebag container for the private key. */ + bag_stack = sk_PKCS12_SAFEBAG_new_null(); + if (bag_stack == NULL) { + HANDLE_PK12_ERROR + } + + /* Pile on the private key on the bag_stack. */ + if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag)) { + HANDLE_PK12_ERROR + } + key_authsafe = PKCS12_pack_p7data(bag_stack); + + /* Clear away this bag_stack, we're done with it. */ + sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free); + bag_stack = NULL; + + if (key_authsafe == NULL) { + HANDLE_PK12_ERROR + } + } + /* + * Section 3: + * + * This is where the two PKCS#7 containers, one for the certificates + * and one for the private key, are put together into a PKCS#12 + * element. This final PKCS#12 element is written to the export file. + */ + + /* Start a PKCS#7 stack. */ + authsafe_stack = sk_PKCS7_new_null(); + if (authsafe_stack == NULL) { + HANDLE_PK12_ERROR + } + if (key_authsafe != NULL) { + if (!sk_PKCS7_push(authsafe_stack, key_authsafe)) { + HANDLE_PK12_ERROR + } + } + if (cert_authsafe != NULL) { + if (!sk_PKCS7_push(authsafe_stack, cert_authsafe)) { + HANDLE_PK12_ERROR + } + } + p12_elem = PKCS12_init(NID_pkcs7_data); + if (p12_elem == NULL) { + sk_PKCS7_pop_free(authsafe_stack, PKCS7_free); + HANDLE_PK12_ERROR + } + + /* Put the PKCS#7 stack into the PKCS#12 element. */ + if (!PKCS12_pack_authsafes(p12_elem, authsafe_stack)) { + HANDLE_PK12_ERROR + } + /* Clear away the PKCS#7 stack, we're done with it. */ + sk_PKCS7_pop_free(authsafe_stack, PKCS7_free); + authsafe_stack = NULL; + + /* Set the integrity MAC on the PKCS#12 element. */ + if (!PKCS12_set_mac(p12_elem, cred->cred, cred->credlen, + NULL, 0, PKCS12_DEFAULT_ITER, NULL)) { + HANDLE_PK12_ERROR + } + + /* Write the PKCS#12 element to the export file. */ + if (!i2d_PKCS12_bio(bio, p12_elem)) { + HANDLE_PK12_ERROR + } + + PKCS12_free(p12_elem); +out: + if (rv != KMF_OK) { + /* Clear away this bag_stack, we're done with it. */ + sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free); + sk_PKCS7_pop_free(authsafe_stack, PKCS7_free); + } + return (rv); +} + +static EVP_PKEY * +ImportRawRSAKey(KMF_RAW_RSA_KEY *key) +{ + RSA *rsa = NULL; + EVP_PKEY *newkey = NULL; + + if ((rsa = RSA_new()) == NULL) + return (NULL); + + if ((rsa->n = BN_bin2bn(key->mod.val, key->mod.len, rsa->n)) == NULL) + return (NULL); + + if ((rsa->e = BN_bin2bn(key->pubexp.val, key->pubexp.len, rsa->e)) == + NULL) + return (NULL); + + if (key->priexp.val != NULL) + if ((rsa->d = BN_bin2bn(key->priexp.val, key->priexp.len, + rsa->d)) == NULL) + return (NULL); + + if (key->prime1.val != NULL) + if ((rsa->p = BN_bin2bn(key->prime1.val, key->prime1.len, + rsa->p)) == NULL) + return (NULL); + + if (key->prime2.val != NULL) + if ((rsa->q = BN_bin2bn(key->prime2.val, key->prime2.len, + rsa->q)) == NULL) + return (NULL); + + if (key->exp1.val != NULL) + if ((rsa->dmp1 = BN_bin2bn(key->exp1.val, key->exp1.len, + rsa->dmp1)) == NULL) + return (NULL); + + if (key->exp2.val != NULL) + if ((rsa->dmq1 = BN_bin2bn(key->exp2.val, key->exp2.len, + rsa->dmq1)) == NULL) + return (NULL); + + if (key->coef.val != NULL) + if ((rsa->iqmp = BN_bin2bn(key->coef.val, key->coef.len, + rsa->iqmp)) == NULL) + return (NULL); + + if ((newkey = EVP_PKEY_new()) == NULL) + return (NULL); + + (void) EVP_PKEY_set1_RSA(newkey, rsa); + + /* The original key must be freed once here or it leaks memory */ + RSA_free(rsa); + + return (newkey); +} + +static EVP_PKEY * +ImportRawDSAKey(KMF_RAW_DSA_KEY *key) +{ + DSA *dsa = NULL; + EVP_PKEY *newkey = NULL; + + if ((dsa = DSA_new()) == NULL) + return (NULL); + + if ((dsa->p = BN_bin2bn(key->prime.val, key->prime.len, + dsa->p)) == NULL) + return (NULL); + + if ((dsa->q = BN_bin2bn(key->subprime.val, key->subprime.len, + dsa->q)) == NULL) + return (NULL); + + if ((dsa->g = BN_bin2bn(key->base.val, key->base.len, + dsa->g)) == NULL) + return (NULL); + + if ((dsa->priv_key = BN_bin2bn(key->value.val, key->value.len, + dsa->priv_key)) == NULL) + return (NULL); + + if ((newkey = EVP_PKEY_new()) == NULL) + return (NULL); + + (void) EVP_PKEY_set1_DSA(newkey, dsa); + + /* The original key must be freed once here or it leaks memory */ + DSA_free(dsa); + return (newkey); +} + +static KMF_RETURN +ExportPK12FromRawData(KMF_HANDLE_T handle, + KMF_CREDENTIAL *cred, + int numcerts, KMF_X509_DER_CERT *certlist, + int numkeys, KMF_KEY_HANDLE *keylist, + char *filename) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + BIO *bio = NULL; + X509 *xcert = NULL; + EVP_PKEY *pkey = NULL; + int i; + + /* + * Open the output file. + */ + if ((bio = BIO_new_file(filename, "wb")) == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_OPEN_FILE; + goto cleanup; + } + + if (numcerts > 0 && numkeys > 0) { + for (i = 0; rv == KMF_OK && i < numcerts; i++) { + KMF_RAW_KEY_DATA *key = NULL; + const uchar_t *p = certlist[i].certificate.Data; + long len = certlist[i].certificate.Length; + + if (i < numkeys) { + key = (KMF_RAW_KEY_DATA *)keylist[i].keyp; + + if (key->keytype == KMF_RSA) { + pkey = ImportRawRSAKey( + &key->rawdata.rsa); + } else if (key->keytype == KMF_DSA) { + pkey = ImportRawDSAKey( + &key->rawdata.dsa); + } else { + rv = KMF_ERR_BAD_PARAMETER; + } + } + + xcert = d2i_X509(NULL, &p, len); + if (xcert == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_ENCODING; + } + /* Stick the key and the cert into a PKCS#12 file */ + rv = write_pkcs12(kmfh, bio, cred, pkey, xcert); + if (xcert) + X509_free(xcert); + if (pkey) + EVP_PKEY_free(pkey); + } + } + +cleanup: + + if (bio != NULL) + (void) BIO_free_all(bio); + + return (rv); +} + +KMF_RETURN +OpenSSL_ExportP12(KMF_HANDLE_T handle, + KMF_EXPORTP12_PARAMS *params, + int numcerts, KMF_X509_DER_CERT *certlist, + int numkeys, KMF_KEY_HANDLE *keylist, + char *filename) +{ + KMF_RETURN rv; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_FINDCERT_PARAMS fcargs; + BIO *bio = NULL; + X509 *xcert = NULL; + char *fullpath = NULL; + EVP_PKEY *pkey = NULL; + + /* + * First, find the certificate. + */ + if (params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * If the caller already sent the raw keys and certs, + * shortcut the search and just export that + * data. + * + * One *may* export a key OR a cert by itself. + */ + if (certlist != NULL || keylist != NULL) { + rv = ExportPK12FromRawData(handle, + ¶ms->p12cred, + numcerts, certlist, + numkeys, keylist, + filename); + return (rv); + } + + if (params->sslparms.certfile != NULL) { + fullpath = get_fullpath(params->sslparms.dirpath, + params->sslparms.certfile); + + if (fullpath == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (isdir(fullpath)) { + free(fullpath); + return (KMF_ERR_AMBIGUOUS_PATHNAME); + } + + (void *)memset(&fcargs, 0, sizeof (fcargs)); + fcargs.kstype = params->kstype; + fcargs.certLabel = params->certLabel; + fcargs.issuer = params->issuer; + fcargs.subject = params->subject; + fcargs.serial = params->serial; + fcargs.idstr = params->idstr; + fcargs.sslparms.dirpath = NULL; + fcargs.sslparms.certfile = fullpath; + fcargs.sslparms.format = params->sslparms.format; + + rv = load_X509cert(kmfh, &fcargs, fullpath, &xcert); + if (rv != KMF_OK) + goto end; + } + + /* + * Now find the private key. + */ + if (params->sslparms.keyfile != NULL) { + fullpath = get_fullpath(params->sslparms.dirpath, + params->sslparms.keyfile); + + if (fullpath == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (isdir(fullpath)) { + free(fullpath); + return (KMF_ERR_AMBIGUOUS_PATHNAME); + } + + pkey = openssl_load_key(handle, fullpath); + if (pkey == NULL) { + rv = KMF_ERR_KEY_NOT_FOUND; + goto end; + } + } + + /* + * Open the output file. + */ + if ((bio = BIO_new_file(filename, "wb")) == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_OPEN_FILE; + goto end; + } + + /* Stick the key and the cert into a PKCS#12 file */ + rv = write_pkcs12(kmfh, bio, ¶ms->p12cred, + pkey, xcert); + +end: + if (fullpath) + free(fullpath); + if (xcert) + X509_free(xcert); + if (pkey) + EVP_PKEY_free(pkey); + if (bio) + (void) BIO_free(bio); + + return (rv); +} + +/* + * Helper function to decrypt and parse PKCS#12 import file. + */ +static KMF_RETURN +extract_pkcs12(BIO *fbio, CK_UTF8CHAR *pin, CK_ULONG pinlen, + EVP_PKEY **priv_key, X509 **cert, STACK_OF(X509) **ca) +/* ARGSUSED */ +{ + PKCS12 *pk12, *pk12_tmp; + EVP_PKEY *temp_pkey = NULL; + X509 *temp_cert = NULL; + STACK_OF(X509) *temp_ca = NULL; + + if ((pk12 = PKCS12_new()) == NULL) { + return (KMF_ERR_MEMORY); + } + + if ((pk12_tmp = d2i_PKCS12_bio(fbio, &pk12)) == NULL) { + /* This is ok; it seems to mean there is no more to read. */ + if (ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_ASN1 && + ERR_GET_REASON(ERR_peek_error()) == ASN1_R_HEADER_TOO_LONG) + goto end_extract_pkcs12; + + PKCS12_free(pk12); + return (KMF_ERR_PKCS12_FORMAT); + } + pk12 = pk12_tmp; + + if (PKCS12_parse(pk12, (char *)pin, &temp_pkey, &temp_cert, + &temp_ca) <= 0) { + PKCS12_free(pk12); + return (KMF_ERR_PKCS12_FORMAT); + } + +end_extract_pkcs12: + + *priv_key = temp_pkey; + *cert = temp_cert; + *ca = temp_ca; + + PKCS12_free(pk12); + return (KMF_OK); +} + +static KMF_RETURN +sslBN2KMFBN(BIGNUM *from, KMF_BIGINT *to) +{ + KMF_RETURN rv = KMF_OK; + uint32_t sz; + + sz = BN_num_bytes(from); + to->val = (uchar_t *)malloc(sz); + if (to->val == NULL) + return (KMF_ERR_MEMORY); + + if ((to->len = BN_bn2bin(from, to->val)) != sz) { + free(to->val); + to->val = NULL; + to->len = 0; + rv = KMF_ERR_MEMORY; + } + + return (rv); +} + +static KMF_RETURN +exportRawRSAKey(RSA *rsa, KMF_RAW_KEY_DATA *key) +{ + KMF_RETURN rv; + KMF_RAW_RSA_KEY *kmfkey = &key->rawdata.rsa; + + (void) memset(kmfkey, 0, sizeof (KMF_RAW_RSA_KEY)); + if ((rv = sslBN2KMFBN(rsa->n, &kmfkey->mod)) != KMF_OK) + goto cleanup; + + if ((rv = sslBN2KMFBN(rsa->e, &kmfkey->pubexp)) != KMF_OK) + goto cleanup; + + if (rsa->d != NULL) + if ((rv = sslBN2KMFBN(rsa->d, &kmfkey->priexp)) != KMF_OK) + goto cleanup; + + if (rsa->p != NULL) + if ((rv = sslBN2KMFBN(rsa->p, &kmfkey->prime1)) != KMF_OK) + goto cleanup; + + if (rsa->q != NULL) + if ((rv = sslBN2KMFBN(rsa->q, &kmfkey->prime2)) != KMF_OK) + goto cleanup; + + if (rsa->dmp1 != NULL) + if ((rv = sslBN2KMFBN(rsa->dmp1, &kmfkey->exp1)) != KMF_OK) + goto cleanup; + + if (rsa->dmq1 != NULL) + if ((rv = sslBN2KMFBN(rsa->dmq1, &kmfkey->exp2)) != KMF_OK) + goto cleanup; + + if (rsa->iqmp != NULL) + if ((rv = sslBN2KMFBN(rsa->iqmp, &kmfkey->coef)) != KMF_OK) + goto cleanup; +cleanup: + if (rv != KMF_OK) + KMF_FreeRawKey(key); + else + key->keytype = KMF_RSA; + + /* + * Free the reference to this key, SSL will not actually free + * the memory until the refcount == 0, so this is safe. + */ + RSA_free(rsa); + + return (rv); +} + +static KMF_RETURN +exportRawDSAKey(DSA *dsa, KMF_RAW_KEY_DATA *key) +{ + KMF_RETURN rv; + KMF_RAW_DSA_KEY *kmfkey = &key->rawdata.dsa; + + (void) memset(kmfkey, 0, sizeof (KMF_RAW_DSA_KEY)); + if ((rv = sslBN2KMFBN(dsa->p, &kmfkey->prime)) != KMF_OK) + goto cleanup; + + if ((rv = sslBN2KMFBN(dsa->q, &kmfkey->subprime)) != KMF_OK) + goto cleanup; + + if ((rv = sslBN2KMFBN(dsa->g, &kmfkey->base)) != KMF_OK) + goto cleanup; + + if ((rv = sslBN2KMFBN(dsa->priv_key, &kmfkey->value)) != KMF_OK) + goto cleanup; + +cleanup: + if (rv != KMF_OK) + KMF_FreeRawKey(key); + else + key->keytype = KMF_DSA; + + /* + * Free the reference to this key, SSL will not actually free + * the memory until the refcount == 0, so this is safe. + */ + DSA_free(dsa); + + return (rv); +} + +static KMF_RETURN +add_cert_to_list(KMF_HANDLE *kmfh, X509 *sslcert, + KMF_DATA **certlist, int *ncerts) +{ + KMF_RETURN rv = KMF_OK; + KMF_DATA *list = (*certlist); + KMF_DATA cert; + int n = (*ncerts); + + if (list == NULL) { + list = (KMF_DATA *)malloc(sizeof (KMF_DATA)); + } else { + list = (KMF_DATA *)realloc(list, sizeof (KMF_DATA) * (n + 1)); + } + + if (list == NULL) + return (KMF_ERR_MEMORY); + + rv = ssl_cert2KMFDATA(kmfh, sslcert, &cert); + if (rv == KMF_OK) { + list[n] = cert; + (*ncerts) = n + 1; + + *certlist = list; + } else { + free(list); + } + + return (rv); +} + +static KMF_RETURN +add_key_to_list(KMF_RAW_KEY_DATA **keylist, + KMF_RAW_KEY_DATA *newkey, int *nkeys) +{ + KMF_RAW_KEY_DATA *list = (*keylist); + int n = (*nkeys); + + if (list == NULL) { + list = (KMF_RAW_KEY_DATA *)malloc(sizeof (KMF_RAW_KEY_DATA)); + } else { + list = (KMF_RAW_KEY_DATA *)realloc(list, + sizeof (KMF_RAW_KEY_DATA) * (n + 1)); + } + + if (list == NULL) + return (KMF_ERR_MEMORY); + + list[n] = *newkey; + (*nkeys) = n + 1; + + *keylist = list; + + return (KMF_OK); +} + + +static KMF_RETURN +convertPK12Objects( + KMF_HANDLE *kmfh, + EVP_PKEY *sslkey, X509 *sslcert, STACK_OF(X509) *sslcacerts, + KMF_RAW_KEY_DATA **keylist, int *nkeys, + KMF_DATA **certlist, int *ncerts) +{ + KMF_RETURN rv = KMF_OK; + KMF_RAW_KEY_DATA key; + int i; + + if (sslkey != NULL) { + /* Convert SSL key to raw key */ + switch (sslkey->type) { + case EVP_PKEY_RSA: + rv = exportRawRSAKey(EVP_PKEY_get1_RSA(sslkey), + &key); + if (rv != KMF_OK) + return (rv); + + break; + case EVP_PKEY_DSA: + rv = exportRawDSAKey(EVP_PKEY_get1_DSA(sslkey), + &key); + if (rv != KMF_OK) + return (rv); + + break; + default: + return (KMF_ERR_BAD_PARAMETER); + } + + rv = add_key_to_list(keylist, &key, nkeys); + if (rv != KMF_OK) + return (rv); + } + + /* Now add the certificate to the certlist */ + if (sslcert != NULL) { + rv = add_cert_to_list(kmfh, sslcert, certlist, ncerts); + if (rv != KMF_OK) + return (rv); + } + + /* Also add any included CA certs to the list */ + for (i = 0; i != sk_X509_num(sslcacerts); i++) { + X509 *c; + /* + * sk_X509_value() is macro that embeds a cast to (X509 *). + * Here it translates into ((X509 *)sk_value((ca), (i))). + * Lint is complaining about the embedded casting, and + * to fix it, you need to fix openssl header files. + */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + c = sk_X509_value(sslcacerts, i); + + /* Now add the ca cert to the certlist */ + rv = add_cert_to_list(kmfh, c, certlist, ncerts); + if (rv != KMF_OK) + return (rv); + } + return (rv); +} + +KMF_RETURN +openssl_read_pkcs12(KMF_HANDLE *kmfh, + char *filename, KMF_CREDENTIAL *cred, + KMF_DATA **certlist, int *ncerts, + KMF_RAW_KEY_DATA **keylist, int *nkeys) +{ + KMF_RETURN rv = KMF_OK; + BIO *bio = NULL; + EVP_PKEY *privkey = NULL; + X509 *cert = NULL; + STACK_OF(X509) *cacerts = NULL; + + bio = BIO_new_file(filename, "rb"); + if (bio == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_OPEN_FILE; + goto end; + } + + *certlist = NULL; + *keylist = NULL; + *ncerts = 0; + *nkeys = 0; + while (rv == KMF_OK) { + rv = extract_pkcs12(bio, + (uchar_t *)cred->cred, + (uint32_t)cred->credlen, + &privkey, &cert, &cacerts); + + /* Reached end of import file? */ + if (rv == KMF_OK && privkey == NULL && + cert == NULL && cacerts == NULL) + break; + + if (rv == KMF_OK) + /* Convert keys and certs to exportable format */ + rv = convertPK12Objects(kmfh, privkey, cert, cacerts, + keylist, nkeys, certlist, ncerts); + + if (privkey) + EVP_PKEY_free(privkey); + + if (cert) + X509_free(cert); + + if (cacerts) + sk_X509_free(cacerts); + } +end: + if (bio != NULL) + (void) BIO_free(bio); + + if (privkey) + EVP_PKEY_free(privkey); + + if (cert) + X509_free(cert); + + if (cacerts) + sk_X509_free(cacerts); + + return (rv); +} + +KMF_RETURN +OpenSSL_StorePrivateKey(KMF_HANDLE_T handle, KMF_STOREKEY_PARAMS *params, + KMF_RAW_KEY_DATA *key) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + char *fullpath; + EVP_PKEY *pkey = NULL; + BIO *bio = NULL; + + if (key != NULL) { + if (key->keytype == KMF_RSA) { + pkey = ImportRawRSAKey(&key->rawdata.rsa); + } else if (key->keytype == KMF_DSA) { + pkey = ImportRawDSAKey(&key->rawdata.dsa); + } else { + rv = KMF_ERR_BAD_PARAMETER; + } + } else { + rv = KMF_ERR_BAD_PARAMETER; + } + if (rv != KMF_OK || pkey == NULL) + return (rv); + + fullpath = get_fullpath(params->sslparms.dirpath, + params->sslparms.keyfile); + + if (fullpath == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* If the requested file exists, return an error */ + if (access(fullpath, F_OK) == 0) { + free(fullpath); + return (KMF_ERR_DUPLICATE_KEYFILE); + } + + bio = BIO_new_file(fullpath, "wb"); + if (bio == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_OPEN_FILE; + goto cleanup; + } + + rv = ssl_write_private_key(kmfh, + params->sslparms.format, + bio, ¶ms->cred, pkey); + +cleanup: + if (fullpath) + free(fullpath); + + if (pkey) + EVP_PKEY_free(pkey); + + if (bio) + (void) BIO_free(bio); + + /* Protect the file by making it read-only */ + if (rv == KMF_OK) { + (void) chmod(fullpath, 0400); + } + return (rv); +} + +static KMF_RETURN +create_deskey(DES_cblock **deskey) +{ + DES_cblock *key; + + key = (DES_cblock *) malloc(sizeof (DES_cblock)); + if (key == NULL) { + return (KMF_ERR_MEMORY); + } + + if (DES_random_key(key) == 0) { + free(key); + return (KMF_ERR_KEYGEN_FAILED); + } + + *deskey = key; + return (KMF_OK); +} + +#define KEYGEN_RETRY 3 +#define DES3_KEY_SIZE 24 + +static KMF_RETURN +create_des3key(unsigned char **des3key) +{ + KMF_RETURN ret = KMF_OK; + DES_cblock *deskey1 = NULL; + DES_cblock *deskey2 = NULL; + DES_cblock *deskey3 = NULL; + unsigned char *newkey = NULL; + int retry; + + if ((newkey = malloc(DES3_KEY_SIZE)) == NULL) { + return (KMF_ERR_MEMORY); + } + + /* create the 1st DES key */ + if ((ret = create_deskey(&deskey1)) != KMF_OK) { + goto out; + } + + /* + * Create the 2nd DES key and make sure its value is different + * from the 1st DES key. + */ + retry = 0; + do { + if (deskey2 != NULL) { + free(deskey2); + deskey2 = NULL; + } + + if ((ret = create_deskey(&deskey2)) != KMF_OK) { + goto out; + } + + if (memcmp((const void *) deskey1, (const void *) deskey2, 8) + == 0) { + ret = KMF_ERR_KEYGEN_FAILED; + retry++; + } + } while (ret == KMF_ERR_KEYGEN_FAILED && retry < KEYGEN_RETRY); + + if (ret != KMF_OK) { + goto out; + } + + /* + * Create the 3rd DES key and make sure its value is different + * from the 2nd DES key. + */ + retry = 0; + do { + if (deskey3 != NULL) { + free(deskey3); + deskey3 = NULL; + } + + if ((ret = create_deskey(&deskey3)) != KMF_OK) { + goto out; + } + + if (memcmp((const void *)deskey2, (const void *)deskey3, 8) + == 0) { + ret = KMF_ERR_KEYGEN_FAILED; + retry++; + } + } while (ret == KMF_ERR_KEYGEN_FAILED && retry < KEYGEN_RETRY); + + if (ret != KMF_OK) { + goto out; + } + + /* Concatenate 3 DES keys into a DES3 key */ + (void) memcpy((void *)newkey, (const void *)deskey1, 8); + (void) memcpy((void *)(newkey + 8), (const void *)deskey2, 8); + (void) memcpy((void *)(newkey + 16), (const void *)deskey3, 8); + *des3key = newkey; + +out: + if (deskey1 != NULL) + free(deskey1); + + if (deskey2 != NULL) + free(deskey2); + + if (deskey3 != NULL) + free(deskey3); + + if (ret != KMF_OK && newkey != NULL) + free(newkey); + + return (ret); +} + +KMF_RETURN +OpenSSL_CreateSymKey(KMF_HANDLE_T handle, KMF_CREATESYMKEY_PARAMS *params, + KMF_KEY_HANDLE *symkey) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + char *fullpath = NULL; + KMF_RAW_SYM_KEY *rkey = NULL; + DES_cblock *deskey = NULL; + unsigned char *des3key = NULL; + unsigned char *random = NULL; + int fd = -1; + + if (kmfh == NULL) + return (KMF_ERR_UNINITIALIZED); + + if (params == NULL || params->sslparms.keyfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + fullpath = get_fullpath(params->sslparms.dirpath, + params->sslparms.keyfile); + if (fullpath == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* If the requested file exists, return an error */ + if (access(fullpath, F_OK) == 0) { + free(fullpath); + return (KMF_ERR_DUPLICATE_KEYFILE); + } + + fd = open(fullpath, O_CREAT|O_TRUNC|O_RDWR, 0400); + if (fd == -1) { + ret = KMF_ERR_OPEN_FILE; + goto out; + } + + rkey = malloc(sizeof (KMF_RAW_SYM_KEY)); + if (rkey == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + (void) memset(rkey, 0, sizeof (KMF_RAW_SYM_KEY)); + + if (params->keytype == KMF_DES) { + if ((ret = create_deskey(&deskey)) != KMF_OK) { + goto out; + } + rkey->keydata.val = (uchar_t *)deskey; + rkey->keydata.len = 8; + + symkey->keyalg = KMF_DES; + + } else if (params->keytype == KMF_DES3) { + if ((ret = create_des3key(&des3key)) != KMF_OK) { + goto out; + } + rkey->keydata.val = (uchar_t *)des3key; + rkey->keydata.len = DES3_KEY_SIZE; + symkey->keyalg = KMF_DES3; + + } else if (params->keytype == KMF_AES || params->keytype == KMF_RC4) { + int bytes; + + if (params->keylength % 8 != 0) { + ret = KMF_ERR_BAD_KEY_SIZE; + goto out; + } + + if (params->keytype == KMF_AES) { + if (params->keylength != 128 && + params->keylength != 192 && + params->keylength != 256) { + ret = KMF_ERR_BAD_KEY_SIZE; + goto out; + } + } + + bytes = params->keylength/8; + random = malloc(bytes); + if (random == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + if (RAND_bytes(random, bytes) != 1) { + ret = KMF_ERR_KEYGEN_FAILED; + goto out; + } + + rkey->keydata.val = (uchar_t *)random; + rkey->keydata.len = bytes; + symkey->keyalg = params->keytype; + + } else { + ret = KMF_ERR_BAD_KEY_TYPE; + goto out; + } + + (void) write(fd, (const void *) rkey->keydata.val, rkey->keydata.len); + + symkey->kstype = KMF_KEYSTORE_OPENSSL; + symkey->keyclass = KMF_SYMMETRIC; + symkey->keylabel = (char *)fullpath; + symkey->israw = TRUE; + symkey->keyp = rkey; + +out: + if (fd != -1) + (void) close(fd); + + if (ret != KMF_OK && fullpath != NULL) { + free(fullpath); + } + if (ret != KMF_OK) { + KMF_FreeRawSymKey(rkey); + symkey->keyp = NULL; + symkey->keyalg = KMF_KEYALG_NONE; + } + + return (ret); +} + + +KMF_RETURN +OpenSSL_VerifyCRLFile(KMF_HANDLE_T handle, KMF_VERIFYCRL_PARAMS *params) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + BIO *bcrl = NULL; + X509_CRL *xcrl = NULL; + X509 *xcert = NULL; + EVP_PKEY *pkey; + int sslret; + KMF_ENCODE_FORMAT crl_format; + unsigned char *p; + long len; + + if (params->crl_name == NULL || params->tacert == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + ret = KMF_GetFileFormat(params->crl_name, &crl_format); + if (ret != KMF_OK) + return (ret); + + bcrl = BIO_new_file(params->crl_name, "rb"); + if (bcrl == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto cleanup; + } + + if (crl_format == KMF_FORMAT_ASN1) { + xcrl = d2i_X509_CRL_bio(bcrl, NULL); + } else if (crl_format == KMF_FORMAT_PEM) { + xcrl = PEM_read_bio_X509_CRL(bcrl, NULL, NULL, NULL); + } else { + ret = KMF_ERR_BAD_PARAMETER; + goto cleanup; + } + + if (xcrl == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CRLFILE; + goto cleanup; + } + + p = params->tacert->Data; + len = params->tacert->Length; + xcert = d2i_X509(NULL, (const uchar_t **)&p, len); + + if (xcert == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CERTFILE; + goto cleanup; + } + + /* Get issuer certificate public key */ + pkey = X509_get_pubkey(xcert); + if (!pkey) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + /* Verify CRL signature */ + sslret = X509_CRL_verify(xcrl, pkey); + EVP_PKEY_free(pkey); + if (sslret > 0) { + ret = KMF_OK; + } else { + SET_ERROR(kmfh, sslret); + ret = KMF_ERR_BAD_CRLFILE; + } + +cleanup: + if (bcrl != NULL) + (void) BIO_free(bcrl); + + if (xcrl != NULL) + X509_CRL_free(xcrl); + + if (xcert != NULL) + X509_free(xcert); + + return (ret); + +} + +KMF_RETURN +OpenSSL_CheckCRLDate(KMF_HANDLE_T handle, + KMF_CHECKCRLDATE_PARAMS *params) +{ + + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_ENCODE_FORMAT crl_format; + BIO *bcrl = NULL; + X509_CRL *xcrl = NULL; + int i; + + if (params == NULL || params->crl_name == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + ret = KMF_IsCRLFile(handle, params->crl_name, &crl_format); + if (ret != KMF_OK) + return (ret); + + bcrl = BIO_new_file(params->crl_name, "rb"); + if (bcrl == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto cleanup; + } + + if (crl_format == KMF_FORMAT_ASN1) { + xcrl = d2i_X509_CRL_bio(bcrl, NULL); + } else if (crl_format == KMF_FORMAT_PEM) { + xcrl = PEM_read_bio_X509_CRL(bcrl, NULL, NULL, NULL); + } + + if (xcrl == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CRLFILE; + goto cleanup; + } + + i = X509_cmp_time(X509_CRL_get_lastUpdate(xcrl), NULL); + if (i >= 0) { + ret = KMF_ERR_VALIDITY_PERIOD; + goto cleanup; + } + + if (X509_CRL_get_nextUpdate(xcrl)) { + i = X509_cmp_time(X509_CRL_get_nextUpdate(xcrl), NULL); + + if (i <= 0) { + ret = KMF_ERR_VALIDITY_PERIOD; + goto cleanup; + } + } + + ret = KMF_OK; + +cleanup: + if (bcrl != NULL) + (void) BIO_free(bcrl); + + if (xcrl != NULL) + X509_CRL_free(xcrl); + + return (ret); +} + +/* + * Check a file to see if it is a CRL file with PEM or DER format. + * If success, return its format in the "pformat" argument. + */ +KMF_RETURN +OpenSSL_IsCRLFile(KMF_HANDLE_T handle, char *filename, int *pformat) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + BIO *bio = NULL; + X509_CRL *xcrl = NULL; + + if (filename == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + bio = BIO_new_file(filename, "rb"); + if (bio == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto out; + } + + if ((xcrl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL)) != NULL) { + *pformat = KMF_FORMAT_PEM; + goto out; + } + (void) BIO_free(bio); + + /* + * Now try to read it as raw DER data. + */ + bio = BIO_new_file(filename, "rb"); + if (bio == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto out; + } + + if ((xcrl = d2i_X509_CRL_bio(bio, NULL)) != NULL) { + *pformat = KMF_FORMAT_ASN1; + } else { + ret = KMF_ERR_BAD_CRLFILE; + } + +out: + if (bio != NULL) + (void) BIO_free(bio); + + if (xcrl != NULL) + X509_CRL_free(xcrl); + + return (ret); +} + +/* + * Check a file to see if it is a certficate file with PEM or DER format. + * If success, return its format in the pformat argument. + */ +KMF_RETURN +OpenSSL_IsCertFile(KMF_HANDLE_T handle, char *filename, + KMF_ENCODE_FORMAT *pformat) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + BIO *bio = NULL; + X509 *xcert = NULL; + + if (filename == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + ret = KMF_GetFileFormat(filename, pformat); + if (ret != KMF_OK) + return (ret); + + bio = BIO_new_file(filename, "rb"); + if (bio == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto out; + } + + if ((*pformat) == KMF_FORMAT_PEM) { + if ((xcert = PEM_read_bio_X509(bio, NULL, + NULL, NULL)) == NULL) { + ret = KMF_ERR_BAD_CERTFILE; + } + } else if ((*pformat) == KMF_FORMAT_ASN1) { + if ((xcert = d2i_X509_bio(bio, NULL)) == NULL) { + ret = KMF_ERR_BAD_CERTFILE; + } + } else { + ret = KMF_ERR_BAD_CERTFILE; + } + +out: + if (bio != NULL) + (void) BIO_free(bio); + + if (xcert != NULL) + X509_free(xcert); + + return (ret); +} + +KMF_RETURN +OpenSSL_GetSymKeyValue(KMF_HANDLE_T handle, KMF_KEY_HANDLE *symkey, + KMF_RAW_SYM_KEY *rkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_DATA keyvalue; + + if (kmfh == NULL) + return (KMF_ERR_UNINITIALIZED); + + if (symkey == NULL || rkey == NULL) + return (KMF_ERR_BAD_PARAMETER); + else if (symkey->keyclass != KMF_SYMMETRIC) + return (KMF_ERR_BAD_KEY_CLASS); + + if (symkey->israw) { + KMF_RAW_SYM_KEY *rawkey = (KMF_RAW_SYM_KEY *)symkey->keyp; + + if (rawkey == NULL || + rawkey->keydata.val == NULL || + rawkey->keydata.len == 0) + return (KMF_ERR_BAD_KEYHANDLE); + + rkey->keydata.len = rawkey->keydata.len; + if ((rkey->keydata.val = malloc(rkey->keydata.len)) == NULL) + return (KMF_ERR_MEMORY); + (void) memcpy(rkey->keydata.val, rawkey->keydata.val, + rkey->keydata.len); + } else { + rv = KMF_ReadInputFile(handle, symkey->keylabel, &keyvalue); + if (rv != KMF_OK) + return (rv); + rkey->keydata.len = keyvalue.Length; + rkey->keydata.val = keyvalue.Data; + } + + return (rv); +} diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/i386/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/i386/Makefile new file mode 100644 index 0000000000..443f78537a --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_openssl/i386/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: $(ROOTLIBS) diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/sparc/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/sparc/Makefile new file mode 100644 index 0000000000..472ac90a9a --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_openssl/sparc/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: $(ROOTLIBS) diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/sparcv9/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/sparcv9/Makefile new file mode 100644 index 0000000000..e80bb3751a --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_openssl/sparcv9/Makefile @@ -0,0 +1,31 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../../../Makefile.lib.64 + +LDLIBS += $(OPENSSLLIBS64) +install: $(ROOTLIBS64) diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile new file mode 100644 index 0000000000..b65a323ef5 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile @@ -0,0 +1,46 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +include $(SRC)/lib/Makefile.lib + +SUBDIRS= $(MACH) + +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET= all +check := TARGET= check +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +.KEEP_STATE: + +all clean clobber install lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile.com b/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile.com new file mode 100644 index 0000000000..f2a715de92 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile.com @@ -0,0 +1,65 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# Makefile for KMF Plugins +# + +LIBRARY= kmf_pkcs11.a +VERS= .1 +OBJECTS= pkcs11_spi.o + +include $(SRC)/lib/Makefile.lib + +LIBLINKS= $(DYNLIB:.so.1=.so) +KMFINC= -I../../../include -I../../../ber_der/inc + +PKCS11LIBS= -lkmf -lkmfberder -lpkcs11 -lcryptoutil -lc + +SRCDIR= ../common +INCDIR= ../../include + +CFLAGS += $(CCVERBOSE) +CPPFLAGS += -D_REENTRANT $(KMFINC) -I$(INCDIR) -I/usr/include/libxml2 + +PICS= $(OBJECTS:%=pics/%) +SONAME= $(PLUGIN) + +LDLIBS += $(PKCS11LIBS) + +ROOTLIBDIR= $(ROOT)/usr/lib/security +ROOTLIBDIR64= $(ROOT)/usr/lib/security/$(MACH64) + +.KEEP_STATE: + +LIBS = $(DYNLIB) + +all: $(LIBS) $(LINTLIB) + +lint: lintcheck + +FRC: + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/amd64/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/amd64/Makefile new file mode 100644 index 0000000000..dfd8150806 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/amd64/Makefile @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include $(SRC)/lib/Makefile.lib.64 + +install: $(ROOTLIBS64) diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/mapfile-vers b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/mapfile-vers new file mode 100644 index 0000000000..ee3b6bcb92 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/mapfile-vers @@ -0,0 +1,50 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SUNWprivate_1.1 { + global: + KMF_Plugin_Initialize; + KMFPK11_FindCert; + KMFPK11_FreeKMFCert; + KMFPK11_StoreCert; + KMFPK11_ImportCert; + KMFPK11_DeleteCert; + KMFPK11_CreateKeypair; + KMFPK11_FindKey; + KMFPK11_EncodePubKeyData; + KMFPK11_SignData; + KMFPK11_DeleteKey; + KMFPK11_GetErrorString; + KMFPK11_GetPrikeyByCert; + KMFPK11_DecryptData; + KMFPK11_StorePrivateKey; + KMFPK11_CreateSymKey; + KMFPK11_GetSymKeyValue; + KMFPK11_SetTokenPin; + local: + *; +}; diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c new file mode 100644 index 0000000000..e548c64eb8 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c @@ -0,0 +1,2945 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * PKCS11 token KMF Plugin + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> /* debugging only */ +#include <errno.h> +#include <values.h> + +#include <kmfapiP.h> +#include <oidsalg.h> +#include <ber_der.h> +#include <algorithm.h> + +#include <cryptoutil.h> +#include <security/cryptoki.h> +#include <security/pkcs11.h> + +#define SETATTR(t, n, atype, value, size) \ + t[n].type = atype; \ + t[n].pValue = (CK_BYTE *)value; \ + t[n].ulValueLen = (CK_ULONG)size; + +#define SET_ERROR(h, c) h->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; \ + h->lasterr.errcode = c; + +typedef struct _objlist { + CK_OBJECT_HANDLE handle; + struct _objlist *next; +} OBJLIST; + +static KMF_RETURN +search_certs(KMF_HANDLE_T, char *, char *, char *, KMF_BIGINT *, + boolean_t, KMF_CERT_VALIDITY, OBJLIST **, uint32_t *); + +static KMF_RETURN +keyObj2RawKey(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_KEY_DATA **); + +KMF_RETURN +KMFPK11_ConfigureKeystore(KMF_HANDLE_T, KMF_CONFIG_PARAMS *); + +KMF_RETURN +KMFPK11_FindCert(KMF_HANDLE_T, + KMF_FINDCERT_PARAMS *, + KMF_X509_DER_CERT *, + uint32_t *); + +void +KMFPK11_FreeKMFCert(KMF_HANDLE_T, + KMF_X509_DER_CERT *kmf_cert); + +KMF_RETURN +KMFPK11_StoreCert(KMF_HANDLE_T, KMF_STORECERT_PARAMS *, KMF_DATA *); + +KMF_RETURN +KMFPK11_ImportCert(KMF_HANDLE_T, KMF_IMPORTCERT_PARAMS *); + +KMF_RETURN +KMFPK11_DeleteCert(KMF_HANDLE_T, KMF_DELETECERT_PARAMS *); + +KMF_RETURN +KMFPK11_CreateKeypair(KMF_HANDLE_T, KMF_CREATEKEYPAIR_PARAMS *, + KMF_KEY_HANDLE *, KMF_KEY_HANDLE *); + +KMF_RETURN +KMFPK11_DeleteKey(KMF_HANDLE_T, KMF_DELETEKEY_PARAMS *, + KMF_KEY_HANDLE *, boolean_t); + +KMF_RETURN +KMFPK11_EncodePubKeyData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_DATA *); + +KMF_RETURN +KMFPK11_SignData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *, + KMF_DATA *, KMF_DATA *); + +KMF_RETURN +KMFPK11_GetErrorString(KMF_HANDLE_T, char **); + +KMF_RETURN +KMFPK11_GetPrikeyByCert(KMF_HANDLE_T, KMF_CRYPTOWITHCERT_PARAMS *, KMF_DATA *, + KMF_KEY_HANDLE *, KMF_KEY_ALG); + +KMF_RETURN +KMFPK11_DecryptData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *, + KMF_DATA *, KMF_DATA *); + +KMF_RETURN +KMFPK11_FindKey(KMF_HANDLE_T, KMF_FINDKEY_PARAMS *, + KMF_KEY_HANDLE *, uint32_t *); + +KMF_RETURN +KMFPK11_StorePrivateKey(KMF_HANDLE_T, KMF_STOREKEY_PARAMS *, + KMF_RAW_KEY_DATA *); + +KMF_RETURN +KMFPK11_CreateSymKey(KMF_HANDLE_T, KMF_CREATESYMKEY_PARAMS *, + KMF_KEY_HANDLE *); + +KMF_RETURN +KMFPK11_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_SYM_KEY *); + +KMF_RETURN +KMFPK11_SetTokenPin(KMF_HANDLE_T, KMF_SETPIN_PARAMS *, KMF_CREDENTIAL *); + +static +KMF_PLUGIN_FUNCLIST pk11token_plugin_table = +{ + 1, /* Version */ + KMFPK11_ConfigureKeystore, + KMFPK11_FindCert, + KMFPK11_FreeKMFCert, + KMFPK11_StoreCert, + KMFPK11_ImportCert, + NULL, /* ImportCRL */ + KMFPK11_DeleteCert, + NULL, /* DeleteCRL */ + KMFPK11_CreateKeypair, + KMFPK11_FindKey, + KMFPK11_EncodePubKeyData, + KMFPK11_SignData, + KMFPK11_DeleteKey, + NULL, /* ListCRL */ + NULL, /* FindCRL */ + NULL, /* FindCertInCRL */ + KMFPK11_GetErrorString, + KMFPK11_GetPrikeyByCert, + KMFPK11_DecryptData, + NULL, /* ExportP12 */ + KMFPK11_StorePrivateKey, + KMFPK11_CreateSymKey, + KMFPK11_GetSymKeyValue, + KMFPK11_SetTokenPin, + NULL /* Finalize */ +}; + +KMF_PLUGIN_FUNCLIST * +KMF_Plugin_Initialize() +{ + return (&pk11token_plugin_table); +} + +KMF_RETURN +KMFPK11_ConfigureKeystore(KMF_HANDLE_T handle, KMF_CONFIG_PARAMS *params) +{ + KMF_RETURN rv = KMF_OK; + + if (params == NULL || params->pkcs11config.label == NULL) + return (KMF_ERR_BAD_PARAMETER); + + rv = KMF_SelectToken(handle, params->pkcs11config.label, + params->pkcs11config.readonly); + + return (rv); +} + +static KMF_RETURN +pk11_authenticate(KMF_HANDLE_T handle, + KMF_CREDENTIAL *cred) +{ + + CK_RV ck_rv = CKR_OK; + CK_SESSION_HANDLE hSession = (CK_SESSION_HANDLE)handle->pk11handle; + + if (hSession == NULL) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (cred == NULL || cred->cred == NULL || cred->credlen == 0) { + return (KMF_ERR_BAD_PARAMETER); + } + + if ((ck_rv = C_Login(hSession, CKU_USER, + (uchar_t *)cred->cred, cred->credlen)) != CKR_OK) { + if (ck_rv != CKR_USER_ALREADY_LOGGED_IN) { + handle->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; + handle->lasterr.errcode = ck_rv; + return (KMF_ERR_AUTH_FAILED); + } + } + + return (KMF_OK); +} + +static KMF_RETURN +PK11Cert2KMFCert(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE hObj, + KMF_X509_DER_CERT *kmfcert) +{ + KMF_RETURN rv = 0; + CK_RV ckrv = CKR_OK; + + CK_CERTIFICATE_TYPE cktype; + CK_OBJECT_CLASS class; + CK_BBOOL cktrusted, token; + CK_ULONG subject_len, value_len, issuer_len, serno_len, id_len; + CK_BYTE *subject = NULL, *value = NULL; + CK_BYTE *label = NULL; + CK_ULONG label_len = 0; + CK_ATTRIBUTE templ[10]; + + SETATTR(templ, 0, CKA_CLASS, &class, sizeof (class)); + + /* Is this a certificate object ? */ + ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, templ, 1); + if (ckrv != CKR_OK || class != CKO_CERTIFICATE) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_INTERNAL); + } + + SETATTR(templ, 0, CKA_CERTIFICATE_TYPE, &cktype, sizeof (cktype)); + SETATTR(templ, 1, CKA_TOKEN, &token, sizeof (token)); + SETATTR(templ, 2, CKA_TRUSTED, &cktrusted, sizeof (cktrusted)); + + ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, templ, 3); + + if (ckrv != CKR_OK || cktype != CKC_X_509) { + SET_ERROR(kmfh, ckrv); + return (ckrv); + } else { + /* What attributes are available and how big are they? */ + subject_len = issuer_len = serno_len = id_len = value_len = + label_len = 0; + SETATTR(templ, 0, CKA_SUBJECT, NULL, subject_len); + SETATTR(templ, 1, CKA_ISSUER, NULL, issuer_len); + SETATTR(templ, 2, CKA_SERIAL_NUMBER, NULL, serno_len); + SETATTR(templ, 3, CKA_ID, NULL, id_len); + SETATTR(templ, 4, CKA_VALUE, NULL, value_len); + SETATTR(templ, 5, CKA_LABEL, NULL, label_len); + + /* + * Query the object with NULL values in the pValue spot + * so we know how much space to allocate for each field. + */ + ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, templ, 6); + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_INTERNAL); /* TODO - Error messages ? */ + } + + subject_len = templ[0].ulValueLen; + issuer_len = templ[1].ulValueLen; + serno_len = templ[2].ulValueLen; + id_len = templ[3].ulValueLen; + value_len = templ[4].ulValueLen; + label_len = templ[5].ulValueLen; + + /* + * For PKCS#11 CKC_X_509 certificate objects, + * the following attributes must be defined. + * CKA_SUBJECT, CKA_ID, CKA_ISSUER, CKA_SERIAL_NUMBER, + * CKA_VALUE. + */ + if (subject_len == 0 || issuer_len == 0 || + serno_len == 0 || value_len == 0) { + return (KMF_ERR_INTERNAL); + } + + /* Only fetch the value field if we are saving the data */ + if (kmfcert != NULL) { + int i = 0; + value = malloc(value_len); + if (value == NULL) { + rv = KMF_ERR_MEMORY; + goto errout; + } + + SETATTR(templ, i, CKA_VALUE, value, value_len); + i++; + if (label_len > 0) { + label = malloc(label_len + 1); + if (label == NULL) { + rv = KMF_ERR_MEMORY; + goto errout; + } + (void) memset(label, 0, label_len + 1); + SETATTR(templ, i, CKA_LABEL, label, + label_len); + i++; + } + + /* re-query the object with room for the value attr */ + ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, + templ, i); + + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + goto errout; + } + + kmfcert->certificate.Data = value; + kmfcert->certificate.Length = value_len; + kmfcert->kmf_private.flags |= KMF_FLAG_CERT_SIGNED; + kmfcert->kmf_private.keystore_type = + KMF_KEYSTORE_PK11TOKEN; + kmfcert->kmf_private.label = (char *)label; + + rv = KMF_OK; + } + } + +errout: + if (rv != KMF_OK) { + if (subject) + free(subject); + if (value) + free(value); + + if (kmfcert) { + kmfcert->certificate.Data = NULL; + kmfcert->certificate.Length = 0; + } + } + return (rv); +} + +static void +free_objlist(OBJLIST *head) +{ + OBJLIST *temp = head; + + while (temp != NULL) { + head = head->next; + free(temp); + temp = head; + } +} + +/* + * The caller should make sure that the templ->pValue is NULL since + * it will be overwritten below. + */ +static KMF_RETURN +get_attr(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, + CK_ATTRIBUTE *templ) +{ + CK_RV rv; + + rv = C_GetAttributeValue(kmfh->pk11handle, obj, templ, 1); + if (rv != CKR_OK) { + SET_ERROR(kmfh, rv); + return (KMF_ERR_INTERNAL); + } + + if (templ->ulValueLen > 0) { + templ->pValue = malloc(templ->ulValueLen); + if (templ->pValue == NULL) + return (KMF_ERR_MEMORY); + + rv = C_GetAttributeValue(kmfh->pk11handle, obj, templ, 1); + if (rv != CKR_OK) { + SET_ERROR(kmfh, rv); + return (KMF_ERR_INTERNAL); + } + } + + return (KMF_OK); +} + +/* + * Match a certificate with an issuer and/or subject name. + * This is tricky because we cannot reliably compare DER encodings + * because RDNs may have their AV-pairs in different orders even + * if the values are the same. You must compare individual + * AV pairs for the RDNs. + * + * RETURN: 0 for a match, non-zero for a non-match. + */ +static KMF_RETURN +matchcert(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, + KMF_X509_NAME *issuer, KMF_X509_NAME *subject) +{ + KMF_RETURN rv = KMF_OK; + CK_ATTRIBUTE certattr; + KMF_DATA name; + KMF_X509_NAME dn; + + if (issuer->numberOfRDNs > 0) { + certattr.type = CKA_ISSUER; + certattr.pValue = NULL; + certattr.ulValueLen = 0; + + rv = get_attr(kmfh, obj, &certattr); + + if (rv == KMF_OK) { + name.Data = certattr.pValue; + name.Length = certattr.ulValueLen; + rv = DerDecodeName(&name, &dn); + if (rv == KMF_OK) { + rv = KMF_CompareRDNs(issuer, &dn); + KMF_FreeDN(&dn); + } + free(certattr.pValue); + } + + if (rv != KMF_OK) + return (rv); + } + if (subject->numberOfRDNs > 0) { + certattr.type = CKA_SUBJECT; + certattr.pValue = NULL; + certattr.ulValueLen = 0; + + rv = get_attr(kmfh, obj, &certattr); + + if (rv == KMF_OK) { + name.Data = certattr.pValue; + name.Length = certattr.ulValueLen; + rv = DerDecodeName(&name, &dn); + if (rv == KMF_OK) { + rv = KMF_CompareRDNs(subject, &dn); + KMF_FreeDN(&dn); + } + free(certattr.pValue); + } + } + + return (rv); +} + +/* + * delete "curr" node from the "newlist". + */ +static void +pk11_delete_obj_from_list(OBJLIST **newlist, + OBJLIST **prev, OBJLIST **curr) +{ + + if (*curr == *newlist) { + /* first node in the list */ + *newlist = (*curr)->next; + *prev = (*curr)->next; + free(*curr); + *curr = *newlist; + } else { + (*prev)->next = (*curr)->next; + free(*curr); + *curr = (*prev)->next; + } +} + +/* + * prepare_object_search + * + * Because this code is shared by the FindCert and + * DeleteCert functions, put it in a separate routine + * to save some work and make code easier to debug and + * read. + */ +static KMF_RETURN +search_certs(KMF_HANDLE_T handle, + char *label, char *issuer, char *subject, KMF_BIGINT *serial, + boolean_t private, KMF_CERT_VALIDITY validity, + OBJLIST **objlist, uint32_t *numobj) +{ + KMF_RETURN rv = KMF_OK; + CK_RV ckrv = CKR_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CK_ATTRIBUTE templ[10]; + CK_BBOOL true = TRUE; + CK_OBJECT_CLASS oclass = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE ctype = CKC_X_509; + KMF_X509_NAME subjectDN, issuerDN; + int i; + OBJLIST *newlist, *tail; + CK_ULONG num = 0; + uint32_t num_ok_certs = 0; /* number of non-expired or expired certs */ + + (void) memset(&templ, 0, 10 * sizeof (CK_ATTRIBUTE)); + (void) memset(&issuerDN, 0, sizeof (KMF_X509_NAME)); + (void) memset(&subjectDN, 0, sizeof (KMF_X509_NAME)); + i = 0; + SETATTR(templ, i, CKA_TOKEN, &true, sizeof (true)); i++; + SETATTR(templ, i, CKA_CLASS, &oclass, sizeof (oclass)); i++; + SETATTR(templ, i, CKA_CERTIFICATE_TYPE, &ctype, + sizeof (ctype)); i++; + + if (label != NULL && strlen(label)) { + SETATTR(templ, i, CKA_LABEL, label, strlen(label)); + i++; + } + if (private) { + SETATTR(templ, i, CKA_PRIVATE, &true, sizeof (true)); i++; + } + + if (issuer != NULL && strlen(issuer)) { + if ((rv = KMF_DNParser(issuer, &issuerDN)) != KMF_OK) + return (rv); + } + if (subject != NULL && strlen(subject)) { + if ((rv = KMF_DNParser(subject, &subjectDN)) != KMF_OK) + return (rv); + } + + if (serial != NULL && serial->val != NULL && serial->len > 0) { + SETATTR(templ, i, CKA_SERIAL_NUMBER, + serial->val, serial->len); + i++; + } + + (*numobj) = 0; + *objlist = NULL; + newlist = NULL; + + ckrv = C_FindObjectsInit(kmfh->pk11handle, templ, i); + if (ckrv != CKR_OK) + goto cleanup; + + tail = newlist = NULL; + while (ckrv == CKR_OK) { + CK_OBJECT_HANDLE tObj; + ckrv = C_FindObjects(kmfh->pk11handle, &tObj, 1, &num); + if (ckrv != CKR_OK || num == 0) + break; + + /* + * 'matchcert' returns 0 if subject/issuer match + * + * If no match, move on to the next one + */ + if (matchcert(kmfh, tObj, &issuerDN, &subjectDN)) + continue; + + if (newlist == NULL) { + newlist = malloc(sizeof (OBJLIST)); + if (newlist == NULL) { + rv = KMF_ERR_MEMORY; + break; + } + newlist->handle = tObj; + newlist->next = NULL; + tail = newlist; + } else { + tail->next = malloc(sizeof (OBJLIST)); + if (tail->next != NULL) { + tail = tail->next; + } else { + rv = KMF_ERR_MEMORY; + break; + } + tail->handle = tObj; + tail->next = NULL; + } + (*numobj)++; + } + ckrv = C_FindObjectsFinal(kmfh->pk11handle); + +cleanup: + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + if (newlist != NULL) { + free_objlist(newlist); + *numobj = 0; + newlist = NULL; + } + } else { + if (validity == KMF_ALL_CERTS) { + *objlist = newlist; + } else { + OBJLIST *node, *prev; + KMF_X509_DER_CERT tmp_kmf_cert; + uint32_t i = 0; + + node = prev = newlist; + /* + * Now check to see if any found certificate is expired + * or valid. + */ + while (node != NULL && i < (*numobj)) { + (void) memset(&tmp_kmf_cert, 0, + sizeof (KMF_X509_DER_CERT)); + rv = PK11Cert2KMFCert(kmfh, node->handle, + &tmp_kmf_cert); + if (rv != KMF_OK) { + goto cleanup1; + } + + rv = KMF_CheckCertDate(handle, + &tmp_kmf_cert.certificate); + + if (validity == KMF_NONEXPIRED_CERTS) { + if (rv == KMF_OK) { + num_ok_certs++; + prev = node; + node = node->next; + } else if (rv == + KMF_ERR_VALIDITY_PERIOD) { + /* + * expired - remove it from list + */ + pk11_delete_obj_from_list( + &newlist, &prev, &node); + } else { + goto cleanup1; + } + } + + if (validity == KMF_EXPIRED_CERTS) { + if (rv == KMF_ERR_VALIDITY_PERIOD) { + num_ok_certs++; + prev = node; + node = node->next; + rv = KMF_OK; + } else if (rv == KMF_OK) { + /* + * valid - remove it from list + */ + pk11_delete_obj_from_list( + &newlist, &prev, &node); + } else { + goto cleanup1; + } + } + i++; + KMF_FreeKMFCert(handle, &tmp_kmf_cert); + } + *numobj = num_ok_certs; + *objlist = newlist; + } + } + +cleanup1: + if (rv != KMF_OK && newlist != NULL) { + free_objlist(newlist); + *numobj = 0; + *objlist = NULL; + } + + if (issuer != NULL) + KMF_FreeDN(&issuerDN); + + if (subject != NULL) + KMF_FreeDN(&subjectDN); + + return (rv); +} + +/* + * The caller may pass a NULL value for kmf_cert below and the function will + * just return the number of certs found (in num_certs). + */ +KMF_RETURN +KMFPK11_FindCert(KMF_HANDLE_T handle, KMF_FINDCERT_PARAMS *params, + KMF_X509_DER_CERT *kmf_cert, + uint32_t *num_certs) +{ + KMF_RETURN rv = 0; + uint32_t want_certs; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + OBJLIST *objlist = NULL; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (params == NULL || num_certs == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (*num_certs > 0) + want_certs = *num_certs; + else + want_certs = MAXINT; /* count them all */ + + *num_certs = 0; + + rv = search_certs(handle, + params->certLabel, params->issuer, + params->subject, params->serial, + params->pkcs11parms.private, + params->find_cert_validity, + &objlist, num_certs); + + if (rv == KMF_OK && objlist != NULL && kmf_cert != NULL) { + OBJLIST *node = objlist; + int i = 0; + while (node != NULL && i < want_certs) { + rv = PK11Cert2KMFCert(kmfh, node->handle, + &kmf_cert[i]); + i++; + node = node->next; + } + } + + if (objlist != NULL) + free_objlist(objlist); + + if (*num_certs == 0) + rv = KMF_ERR_CERT_NOT_FOUND; + + return (rv); +} + +/*ARGSUSED*/ +void +KMFPK11_FreeKMFCert(KMF_HANDLE_T handle, + KMF_X509_DER_CERT *kmf_cert) +{ + if (kmf_cert != NULL && kmf_cert->certificate.Data != NULL) { + free(kmf_cert->certificate.Data); + kmf_cert->certificate.Data = NULL; + kmf_cert->certificate.Length = 0; + + if (kmf_cert->kmf_private.label != NULL) { + free(kmf_cert->kmf_private.label); + kmf_cert->kmf_private.label = NULL; + } + } +} + +KMF_RETURN +KMFPK11_EncodePubKeyData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *pKey, + KMF_DATA *eData) +{ + KMF_RETURN ret = KMF_OK; + CK_RV rv; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CK_OBJECT_CLASS ckObjClass = CKO_PUBLIC_KEY; + CK_KEY_TYPE ckKeyType; + KMF_DATA Modulus, Exponent, Prime, Subprime, Base, Value; + KMF_OID *Algorithm; + BerElement *asn1 = NULL; + BerValue *PubKeyParams = NULL, *EncodedKey = NULL; + KMF_X509_SPKI spki; + + CK_ATTRIBUTE rsaTemplate[4]; + CK_ATTRIBUTE dsaTemplate[6]; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (pKey == NULL || pKey->keyp == CK_INVALID_HANDLE) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(&Modulus, 0, sizeof (Modulus)); + (void) memset(&Exponent, 0, sizeof (Exponent)); + (void) memset(&Prime, 0, sizeof (Prime)); + (void) memset(&Subprime, 0, sizeof (Subprime)); + (void) memset(&Base, 0, sizeof (Base)); + (void) memset(&Value, 0, sizeof (Value)); + + SETATTR(rsaTemplate, 0, CKA_CLASS, &ckObjClass, sizeof (ckObjClass)); + SETATTR(rsaTemplate, 1, CKA_KEY_TYPE, &ckKeyType, sizeof (ckKeyType)); + SETATTR(rsaTemplate, 2, CKA_MODULUS, Modulus.Data, &Modulus.Length); + SETATTR(rsaTemplate, 3, CKA_PUBLIC_EXPONENT, Exponent.Data, + &Exponent.Length); + + SETATTR(dsaTemplate, 0, CKA_CLASS, &ckObjClass, sizeof (ckObjClass)); + SETATTR(dsaTemplate, 1, CKA_KEY_TYPE, &ckKeyType, sizeof (ckKeyType)); + SETATTR(dsaTemplate, 2, CKA_PRIME, Prime.Data, &Prime.Length); + SETATTR(dsaTemplate, 3, CKA_SUBPRIME, Subprime.Data, &Subprime.Length); + SETATTR(dsaTemplate, 4, CKA_BASE, Base.Data, &Base.Length); + SETATTR(dsaTemplate, 5, CKA_VALUE, Value.Data, &Value.Length); + + switch (pKey->keyalg) { + case KMF_RSA: + /* Get the length of the fields */ + rv = C_GetAttributeValue(kmfh->pk11handle, + (CK_OBJECT_HANDLE)pKey->keyp, + rsaTemplate, 4); + if (rv != CKR_OK) { + SET_ERROR(kmfh, rv); + return (KMF_ERR_BAD_PARAMETER); + } + + Modulus.Length = rsaTemplate[2].ulValueLen; + Modulus.Data = malloc(Modulus.Length); + if (Modulus.Data == NULL) + return (KMF_ERR_MEMORY); + + Exponent.Length = rsaTemplate[3].ulValueLen; + Exponent.Data = malloc(Exponent.Length); + if (Exponent.Data == NULL) { + free(Modulus.Data); + return (KMF_ERR_MEMORY); + } + + SETATTR(rsaTemplate, 2, CKA_MODULUS, Modulus.Data, + Modulus.Length); + SETATTR(rsaTemplate, 3, CKA_PUBLIC_EXPONENT, + Exponent.Data, Exponent.Length); + /* Now get the values */ + rv = C_GetAttributeValue(kmfh->pk11handle, + (CK_OBJECT_HANDLE)pKey->keyp, + rsaTemplate, 4); + if (rv != CKR_OK) { + SET_ERROR(kmfh, rv); + free(Modulus.Data); + free(Exponent.Data); + return (KMF_ERR_BAD_PARAMETER); + } + + /* + * This is the KEY algorithm, not the + * signature algorithm. + */ + Algorithm = X509_AlgIdToAlgorithmOid(KMF_ALGID_RSA); + if (Algorithm != NULL) { + + /* Encode the RSA Key Data */ + if ((asn1 = kmfder_alloc()) == NULL) { + free(Modulus.Data); + free(Exponent.Data); + return (KMF_ERR_MEMORY); + } + if (kmfber_printf(asn1, "{II}", + Modulus.Data, Modulus.Length, + Exponent.Data, Exponent.Length) == -1) { + kmfber_free(asn1, 1); + free(Modulus.Data); + free(Exponent.Data); + return (KMF_ERR_ENCODING); + } + if (kmfber_flatten(asn1, &EncodedKey) == -1) { + kmfber_free(asn1, 1); + free(Modulus.Data); + free(Exponent.Data); + return (KMF_ERR_ENCODING); + } + kmfber_free(asn1, 1); + } + + free(Exponent.Data); + free(Modulus.Data); + + break; + case KMF_DSA: + /* Get the length of the fields */ + rv = C_GetAttributeValue(kmfh->pk11handle, + (CK_OBJECT_HANDLE)pKey->keyp, + dsaTemplate, 6); + if (rv != CKR_OK) { + SET_ERROR(kmfh, rv); + return (KMF_ERR_BAD_PARAMETER); + } + Prime.Length = dsaTemplate[2].ulValueLen; + Prime.Data = malloc(Prime.Length); + if (Prime.Data == NULL) { + return (KMF_ERR_MEMORY); + } + + Subprime.Length = dsaTemplate[3].ulValueLen; + Subprime.Data = malloc(Subprime.Length); + if (Subprime.Data == NULL) { + free(Prime.Data); + return (KMF_ERR_MEMORY); + } + + Base.Length = dsaTemplate[4].ulValueLen; + Base.Data = malloc(Base.Length); + if (Base.Data == NULL) { + free(Prime.Data); + free(Subprime.Data); + return (KMF_ERR_MEMORY); + } + + Value.Length = dsaTemplate[5].ulValueLen; + Value.Data = malloc(Value.Length); + if (Value.Data == NULL) { + free(Prime.Data); + free(Subprime.Data); + free(Base.Data); + return (KMF_ERR_MEMORY); + } + SETATTR(dsaTemplate, 2, CKA_PRIME, Prime.Data, + Prime.Length); + SETATTR(dsaTemplate, 3, CKA_SUBPRIME, Subprime.Data, + Subprime.Length); + SETATTR(dsaTemplate, 4, CKA_BASE, Base.Data, + Base.Length); + SETATTR(dsaTemplate, 5, CKA_VALUE, Value.Data, + Value.Length); + + /* Now get the values */ + rv = C_GetAttributeValue(kmfh->pk11handle, + (CK_OBJECT_HANDLE)pKey->keyp, + dsaTemplate, 6); + if (rv != CKR_OK) { + free(Prime.Data); + free(Subprime.Data); + free(Base.Data); + free(Value.Data); + SET_ERROR(kmfh, rv); + return (KMF_ERR_BAD_PARAMETER); + } + /* + * This is the KEY algorithm, not the + * signature algorithm. + */ + Algorithm = + X509_AlgIdToAlgorithmOid(KMF_ALGID_DSA); + + /* Encode the DSA Algorithm Parameters */ + if ((asn1 = kmfder_alloc()) == NULL) { + free(Prime.Data); + free(Subprime.Data); + free(Base.Data); + free(Value.Data); + return (KMF_ERR_MEMORY); + } + + if (kmfber_printf(asn1, "{III}", + Prime.Data, Prime.Length, + Subprime.Data, Subprime.Length, + Base.Data, Base.Length) == -1) { + + kmfber_free(asn1, 1); + free(Prime.Data); + free(Subprime.Data); + free(Base.Data); + free(Value.Data); + return (KMF_ERR_ENCODING); + } + if (kmfber_flatten(asn1, &PubKeyParams) == -1) { + kmfber_free(asn1, 1); + free(Prime.Data); + free(Subprime.Data); + free(Base.Data); + free(Value.Data); + return (KMF_ERR_ENCODING); + } + kmfber_free(asn1, 1); + free(Prime.Data); + free(Subprime.Data); + free(Base.Data); + + /* Encode the DSA Key Value */ + if ((asn1 = kmfder_alloc()) == NULL) { + free(Value.Data); + return (KMF_ERR_MEMORY); + } + + if (kmfber_printf(asn1, "I", + Value.Data, Value.Length) == -1) { + kmfber_free(asn1, 1); + free(Value.Data); + return (KMF_ERR_ENCODING); + } + if (kmfber_flatten(asn1, &EncodedKey) == -1) { + kmfber_free(asn1, 1); + free(Value.Data); + return (KMF_ERR_ENCODING); + } + kmfber_free(asn1, 1); + free(Value.Data); + break; + default: + return (KMF_ERR_BAD_PARAMETER); + } + + /* Now, build an SPKI structure for the final encoding step */ + spki.algorithm.algorithm = *Algorithm; + if (PubKeyParams != NULL) { + spki.algorithm.parameters.Data = + (uchar_t *)PubKeyParams->bv_val; + spki.algorithm.parameters.Length = PubKeyParams->bv_len; + } else { + spki.algorithm.parameters.Data = NULL; + spki.algorithm.parameters.Length = 0; + } + + if (EncodedKey != NULL) { + spki.subjectPublicKey.Data = (uchar_t *)EncodedKey->bv_val; + spki.subjectPublicKey.Length = EncodedKey->bv_len; + } else { + spki.subjectPublicKey.Data = NULL; + spki.subjectPublicKey.Length = 0; + } + + /* Finally, encode the entire SPKI record */ + ret = DerEncodeSPKI(&spki, eData); + +cleanup: + if (EncodedKey) { + free(EncodedKey->bv_val); + free(EncodedKey); + } + + if (PubKeyParams) { + free(PubKeyParams->bv_val); + free(PubKeyParams); + } + + return (ret); +} + + +static KMF_RETURN +CreateCertObject(KMF_HANDLE_T handle, char *label, KMF_DATA *pcert) +{ + KMF_RETURN rv = 0; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + KMF_X509_CERTIFICATE *signed_cert_ptr = NULL; + KMF_DATA data; + KMF_DATA Id; + + CK_RV ckrv; + CK_ULONG subject_len, issuer_len, serno_len; + CK_BYTE *subject, *issuer, *serial; + CK_BBOOL true = TRUE; + CK_CERTIFICATE_TYPE certtype = CKC_X_509; + CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; + CK_ATTRIBUTE x509templ[11]; + CK_OBJECT_HANDLE hCert = NULL; + int i; + + if (!kmfh) + return (KMF_ERR_INTERNAL); /* should not happen */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_INTERNAL); /* should not happen */ + + if (pcert == NULL || pcert->Data == NULL || pcert->Length == 0) + return (KMF_ERR_INTERNAL); /* should not happen */ + + /* + * The data *must* be a DER encoded X.509 certificate. + * Convert it to a CSSM cert and then parse the fields so + * the PKCS#11 attributes can be filled in correctly. + */ + rv = DerDecodeSignedCertificate((const KMF_DATA *)pcert, + &signed_cert_ptr); + if (rv != KMF_OK) { + return (KMF_ERR_ENCODING); + } + + /* + * Encode fields into PKCS#11 attributes. + */ + + /* Get the subject name */ + rv = DerEncodeName(&signed_cert_ptr->certificate.subject, &data); + if (rv == KMF_OK) { + subject = data.Data; + subject_len = data.Length; + } else { + rv = KMF_ERR_ENCODING; + goto cleanup; + } + + /* Encode the issuer */ + rv = DerEncodeName(&signed_cert_ptr->certificate.issuer, &data); + if (rv == KMF_OK) { + issuer = data.Data; + issuer_len = data.Length; + } else { + rv = KMF_ERR_ENCODING; + goto cleanup; + } + + /* Encode serial number */ + if (signed_cert_ptr->certificate.serialNumber.len > 0 && + signed_cert_ptr->certificate.serialNumber.val != NULL) { + serial = signed_cert_ptr->certificate.serialNumber.val; + serno_len = signed_cert_ptr->certificate.serialNumber.len; + } else { + rv = KMF_ERR_ENCODING; + goto cleanup; + } + + /* Generate an ID from the SPKI data */ + rv = GetIDFromSPKI(&signed_cert_ptr->certificate.subjectPublicKeyInfo, + &Id); + + if (rv != KMF_OK) { + SET_ERROR(kmfh, rv); + goto cleanup; + } + + i = 0; + SETATTR(x509templ, i, CKA_CLASS, &certClass, + sizeof (certClass)); i++; + SETATTR(x509templ, i, CKA_CERTIFICATE_TYPE, &certtype, + sizeof (certtype)); i++; + SETATTR(x509templ, i, CKA_TOKEN, &true, sizeof (true)); i++; + SETATTR(x509templ, i, CKA_SUBJECT, subject, subject_len); i++; + SETATTR(x509templ, i, CKA_ISSUER, issuer, issuer_len); i++; + SETATTR(x509templ, i, CKA_SERIAL_NUMBER, serial, serno_len); i++; + SETATTR(x509templ, i, CKA_VALUE, pcert->Data, pcert->Length); i++; + SETATTR(x509templ, i, CKA_ID, Id.Data, Id.Length); i++; + if (label != NULL && strlen(label)) { + SETATTR(x509templ, i, CKA_LABEL, label, strlen(label)); + i++; + } + + /* + * The cert object handle is actually "leaked" here. If the app + * really wants to clean up the data space, it will have to call + * KMF_DeleteCert and specify the softtoken keystore. + */ + ckrv = C_CreateObject(kmfh->pk11handle, x509templ, i, &hCert); + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, rv); + rv = KMF_ERR_INTERNAL; + } + free(subject); + free(issuer); + +cleanup: + if (Id.Data != NULL) + free(Id.Data); + + if (signed_cert_ptr) { + KMF_FreeSignedCert(signed_cert_ptr); + free(signed_cert_ptr); + } + return (rv); +} + + +KMF_RETURN +KMFPK11_StoreCert(KMF_HANDLE_T handle, KMF_STORECERT_PARAMS *params, + KMF_DATA *pcert) +{ + KMF_RETURN rv = 0; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (pcert == NULL || pcert->Data == NULL || pcert->Length == 0) + return (KMF_ERR_BAD_PARAMETER); + + rv = CreateCertObject(handle, params->certLabel, pcert); + return (rv); +} + + + +KMF_RETURN +KMFPK11_ImportCert(KMF_HANDLE_T handle, KMF_IMPORTCERT_PARAMS *params) +{ + KMF_RETURN rv = 0; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_ENCODE_FORMAT format; + KMF_DATA cert1 = { NULL, 0}; + KMF_DATA cert2 = { NULL, 0}; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (params == NULL || params->certfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* + * Check if the input cert file is a valid certificate and + * auto-detect the file format of it. + */ + rv = KMF_IsCertFile(handle, params->certfile, &format); + if (rv != KMF_OK) + return (rv); + + /* Read in the CERT file */ + rv = KMF_ReadInputFile(handle, params->certfile, &cert1); + if (rv != KMF_OK) { + return (rv); + } + + /* + * If the input certificate is in PEM format, we need to convert + * it to DER first. + */ + if (format == KMF_FORMAT_PEM) { + int derlen; + rv = KMF_Pem2Der(cert1.Data, cert1.Length, + &cert2.Data, &derlen); + if (rv != KMF_OK) { + goto out; + } + cert2.Length = (size_t)derlen; + } + + rv = CreateCertObject(handle, params->certLabel, + format == KMF_FORMAT_ASN1 ? &cert1 : &cert2); + +out: + if (cert1.Data != NULL) { + free(cert1.Data); + } + + if (cert2.Data != NULL) { + free(cert2.Data); + } + + return (rv); +} + +KMF_RETURN +KMFPK11_DeleteCert(KMF_HANDLE_T handle, KMF_DELETECERT_PARAMS *params) +{ + KMF_RETURN rv = 0; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + OBJLIST *objlist; + uint32_t numObjects = 0; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * Use the same search routine as is used for the FindCert + * operation. + */ + objlist = NULL; + rv = search_certs(handle, + params->certLabel, params->issuer, + params->subject, params->serial, + params->pkcs11parms.private, + params->find_cert_validity, + &objlist, &numObjects); + + if (rv == KMF_OK && objlist != NULL) { + OBJLIST *node = objlist; + + while (node != NULL) { + CK_RV ckrv; + ckrv = C_DestroyObject(kmfh->pk11handle, + node->handle); + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + break; + } + node = node->next; + } + free_objlist(objlist); + } + + if (rv == KMF_OK && numObjects == 0) + rv = KMF_ERR_CERT_NOT_FOUND; + +out: + return (rv); +} + +KMF_RETURN +KMFPK11_CreateKeypair(KMF_HANDLE_T handle, KMF_CREATEKEYPAIR_PARAMS *params, + KMF_KEY_HANDLE *privkey, KMF_KEY_HANDLE *pubkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + CK_RV ckrv = 0; + CK_OBJECT_HANDLE pubKey = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE priKey = CK_INVALID_HANDLE; + CK_SESSION_HANDLE hSession = kmfh->pk11handle; + + static CK_OBJECT_CLASS priClass = CKO_PRIVATE_KEY; + static CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY; + + static CK_ULONG rsaKeyType = CKK_RSA; + static CK_ULONG modulusBits = 1024; + static CK_BYTE PubExpo[3] = {0x01, 0x00, 0x01}; + static CK_BBOOL true = TRUE; + static CK_BBOOL ontoken = TRUE; + static CK_BBOOL false = FALSE; + static CK_ULONG dsaKeyType = CKK_DSA; + + CK_ATTRIBUTE rsaPubKeyTemplate[8]; + CK_ATTRIBUTE rsaPriKeyTemplate[6]; + + static CK_BYTE ckDsaPrime[128] = { + 0xb2, 0x6b, 0xc3, 0xfb, 0xe3, 0x26, 0xf4, 0xc2, + 0xcf, 0xdd, 0xf9, 0xae, 0x3e, 0x39, 0x7f, 0x9c, + 0xa7, 0x73, 0xc3, 0x00, 0xa3, 0x50, 0x67, 0xc3, + 0xab, 0x49, 0x2c, 0xea, 0x59, 0x10, 0xa4, 0xbc, + 0x09, 0x94, 0xa9, 0x05, 0x3b, 0x0d, 0x35, 0x3c, + 0x55, 0x52, 0x47, 0xf0, 0xe3, 0x72, 0x5b, 0xe8, + 0x72, 0xa0, 0x71, 0x1c, 0x23, 0x4f, 0x6d, 0xe8, + 0xac, 0xe5, 0x21, 0x1b, 0xc0, 0xd8, 0x42, 0xd3, + 0x87, 0xae, 0x83, 0x5e, 0x52, 0x7e, 0x46, 0x09, + 0xb5, 0xc7, 0x3d, 0xd6, 0x00, 0xf5, 0xf2, 0x9c, + 0x84, 0x30, 0x81, 0x7e, 0x7b, 0x30, 0x5b, 0xd5, + 0xab, 0xd0, 0x2f, 0x21, 0xb3, 0xd8, 0xed, 0xdb, + 0x97, 0x77, 0xe4, 0x7e, 0x6c, 0xcc, 0xb9, 0x6b, + 0xdd, 0xaa, 0x96, 0x04, 0xe7, 0xd4, 0x55, 0x11, + 0x53, 0xab, 0xba, 0x95, 0x9a, 0xa2, 0x8c, 0x27, + 0xd9, 0xcf, 0xad, 0xf3, 0xcf, 0x3a, 0x0c, 0x4b}; + + static CK_BYTE ckDsaSubPrime[20] = { + 0xa4, 0x5f, 0x2a, 0x27, 0x09, 0x49, 0xb6, 0xfe, + 0x73, 0xeb, 0x95, 0x7d, 0x00, 0xf3, 0x42, 0xfc, + 0x78, 0x47, 0xb0, 0xd5}; + + static CK_BYTE ckDsaBase[128] = { + 0x5c, 0x57, 0x16, 0x49, 0xef, 0xc8, 0xfb, 0x4b, + 0xee, 0x07, 0x45, 0x3b, 0x6a, 0x1d, 0xf3, 0xe5, + 0xeb, 0xee, 0xad, 0x11, 0x13, 0xe3, 0x52, 0xe3, + 0x0d, 0xc0, 0x21, 0x25, 0xfa, 0xf0, 0x93, 0x1c, + 0x53, 0x4d, 0xdc, 0x0d, 0x76, 0xd2, 0xfe, 0xc2, + 0xd7, 0x72, 0x64, 0x69, 0x53, 0x3d, 0x33, 0xbd, + 0xe1, 0x34, 0xf2, 0x5a, 0x67, 0x83, 0xe0, 0xd3, + 0x1c, 0xd6, 0x41, 0x4d, 0x16, 0xe8, 0x6c, 0x5a, + 0x07, 0x95, 0x21, 0x9a, 0xa3, 0xc4, 0xb9, 0x05, + 0x9d, 0x11, 0xcb, 0xc8, 0xc4, 0x9d, 0x00, 0x1a, + 0xf4, 0x85, 0x2a, 0xa9, 0x20, 0x3c, 0xba, 0x67, + 0xe5, 0xed, 0x31, 0xb2, 0x11, 0xfb, 0x1f, 0x73, + 0xec, 0x61, 0x29, 0xad, 0xc7, 0x68, 0xb2, 0x3f, + 0x38, 0xea, 0xd9, 0x87, 0x83, 0x9e, 0x7e, 0x19, + 0x18, 0xdd, 0xc2, 0xc3, 0x5b, 0x16, 0x6d, 0xce, + 0xcf, 0x88, 0x91, 0x07, 0xe0, 0x2b, 0xa8, 0x54 }; + + static CK_ATTRIBUTE ckDsaPubKeyTemplate[] = { + { CKA_CLASS, &pubClass, sizeof (pubClass) }, + { CKA_KEY_TYPE, &dsaKeyType, sizeof (dsaKeyType) }, + { CKA_TOKEN, &ontoken, sizeof (ontoken)}, + { CKA_PRIVATE, &false, sizeof (false)}, + { CKA_PRIME, &ckDsaPrime, sizeof (ckDsaPrime) }, + { CKA_SUBPRIME, &ckDsaSubPrime, sizeof (ckDsaSubPrime)}, + { CKA_BASE, &ckDsaBase, sizeof (ckDsaBase) }, + { CKA_VERIFY, &true, sizeof (true) }, +}; + +#define NUMBER_DSA_PUB_TEMPLATES (sizeof (ckDsaPubKeyTemplate) / \ + sizeof (CK_ATTRIBUTE)) +#define MAX_DSA_PUB_TEMPLATES (sizeof (ckDsaPubKeyTemplate) / \ + sizeof (CK_ATTRIBUTE)) + + static CK_ATTRIBUTE ckDsaPriKeyTemplate[] = { + {CKA_CLASS, &priClass, sizeof (priClass)}, + {CKA_KEY_TYPE, &dsaKeyType, sizeof (dsaKeyType)}, + {CKA_TOKEN, &ontoken, sizeof (ontoken)}, + {CKA_PRIVATE, &true, sizeof (true)}, + {CKA_SIGN, &true, sizeof (true)}, + }; + + CK_ATTRIBUTE labelattr[1]; + CK_ATTRIBUTE idattr[1]; + char IDHashData[SHA1_HASH_LENGTH]; + KMF_DATA IDInput, IDOutput; + +#define NUMBER_DSA_PRI_TEMPLATES (sizeof (ckDsaPriKeyTemplate) / \ + sizeof (CK_ATTRIBUTE)) +#define MAX_DSA_PRI_TEMPLATES (sizeof (ckDsaPriKeyTemplate) / \ + sizeof (CK_ATTRIBUTE)) + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + rv = pk11_authenticate(handle, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + if (params->keytype == KMF_RSA) { + CK_MECHANISM keyGenMech = {CKM_RSA_PKCS_KEY_PAIR_GEN, + NULL, 0}; + CK_BYTE *modulus; + CK_ULONG modulusLength; + CK_ATTRIBUTE modattr[1]; + + SETATTR(rsaPubKeyTemplate, 0, CKA_CLASS, + &pubClass, sizeof (pubClass)); + SETATTR(rsaPubKeyTemplate, 1, CKA_KEY_TYPE, + &rsaKeyType, sizeof (rsaKeyType)); + SETATTR(rsaPubKeyTemplate, 2, CKA_TOKEN, + &false, sizeof (false)); + SETATTR(rsaPubKeyTemplate, 3, CKA_PRIVATE, + &false, sizeof (false)); + SETATTR(rsaPubKeyTemplate, 4, CKA_MODULUS_BITS, + &modulusBits, sizeof (modulusBits)); + if (params->rsa_exponent.len > 0 && + params->rsa_exponent.val != NULL) { + SETATTR(rsaPubKeyTemplate, 5, + CKA_PUBLIC_EXPONENT, + params->rsa_exponent.val, + params->rsa_exponent.len); + } else { + SETATTR(rsaPubKeyTemplate, 5, + CKA_PUBLIC_EXPONENT, &PubExpo, + sizeof (PubExpo)); + } + SETATTR(rsaPubKeyTemplate, 6, CKA_ENCRYPT, + &true, sizeof (true)); + SETATTR(rsaPubKeyTemplate, 7, CKA_VERIFY, + &true, sizeof (true)); + + SETATTR(rsaPriKeyTemplate, 0, CKA_CLASS, &priClass, + sizeof (priClass)); + SETATTR(rsaPriKeyTemplate, 1, CKA_KEY_TYPE, &rsaKeyType, + sizeof (rsaKeyType)); + SETATTR(rsaPriKeyTemplate, 2, CKA_TOKEN, &ontoken, + sizeof (ontoken)); + SETATTR(rsaPriKeyTemplate, 3, CKA_PRIVATE, &true, + sizeof (true)); + SETATTR(rsaPriKeyTemplate, 4, CKA_DECRYPT, &true, + sizeof (true)); + SETATTR(rsaPriKeyTemplate, 5, CKA_SIGN, &true, + sizeof (true)); + + SETATTR(modattr, 0, CKA_MODULUS, NULL, &modulusLength); + + modulusBits = params->keylength; + + pubKey = CK_INVALID_HANDLE; + priKey = CK_INVALID_HANDLE; + ckrv = C_GenerateKeyPair(hSession, &keyGenMech, + rsaPubKeyTemplate, + (sizeof (rsaPubKeyTemplate)/sizeof (CK_ATTRIBUTE)), + rsaPriKeyTemplate, + (sizeof (rsaPriKeyTemplate)/sizeof (CK_ATTRIBUTE)), + &pubKey, &priKey); + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_KEYGEN_FAILED); + } + + if (privkey != NULL) { + privkey->kstype = KMF_KEYSTORE_PK11TOKEN; + privkey->keyalg = KMF_RSA; + privkey->keyclass = KMF_ASYM_PRI; + privkey->keyp = (void *)priKey; + } + if (pubkey != NULL) { + pubkey->kstype = KMF_KEYSTORE_PK11TOKEN; + pubkey->keyalg = KMF_RSA; + pubkey->keyclass = KMF_ASYM_PUB; + pubkey->keyp = (void *)pubKey; + } + + /* Get the Modulus field to use as input for creating the ID */ + rv = C_GetAttributeValue(kmfh->pk11handle, + (CK_OBJECT_HANDLE)pubKey, + modattr, 1); + if (rv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_BAD_PARAMETER); + } + + modulusLength = modattr[0].ulValueLen; + modulus = malloc(modulusLength); + if (modulus == NULL) + return (KMF_ERR_MEMORY); + + modattr[0].pValue = modulus; + rv = C_GetAttributeValue(kmfh->pk11handle, + (CK_OBJECT_HANDLE)pubKey, + modattr, 1); + if (rv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + free(modulus); + return (KMF_ERR_BAD_PARAMETER); + } + + IDInput.Data = modulus; + IDInput.Length = modulusLength; + + } else if (params->keytype == KMF_DSA) { + CK_MECHANISM keyGenMech = {CKM_DSA_KEY_PAIR_GEN, NULL, 0}; + CK_BYTE *keyvalue; + CK_ULONG valueLen; + CK_ATTRIBUTE valattr[1]; + + SETATTR(ckDsaPriKeyTemplate, 2, CKA_TOKEN, + &ontoken, sizeof (ontoken)); + SETATTR(valattr, 0, CKA_VALUE, NULL, &valueLen); + + ckrv = C_GenerateKeyPair(hSession, &keyGenMech, + ckDsaPubKeyTemplate, + (sizeof (ckDsaPubKeyTemplate)/sizeof (CK_ATTRIBUTE)), + ckDsaPriKeyTemplate, + (sizeof (ckDsaPriKeyTemplate)/sizeof (CK_ATTRIBUTE)), + &pubKey, &priKey); + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_KEYGEN_FAILED); + } + + if (privkey != NULL) { + privkey->kstype = KMF_KEYSTORE_PK11TOKEN; + privkey->keyalg = KMF_DSA; + privkey->keyclass = KMF_ASYM_PRI; + privkey->keyp = (void *)priKey; + } + if (pubkey != NULL) { + pubkey->kstype = KMF_KEYSTORE_PK11TOKEN; + pubkey->keyalg = KMF_DSA; + pubkey->keyclass = KMF_ASYM_PUB; + pubkey->keyp = (void *)pubKey; + } + /* Get the Public Value to use as input for creating the ID */ + rv = C_GetAttributeValue(hSession, + (CK_OBJECT_HANDLE)pubKey, + valattr, 1); + if (rv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_BAD_PARAMETER); + } + + valueLen = valattr[0].ulValueLen; + keyvalue = malloc(valueLen); + if (keyvalue == NULL) + return (KMF_ERR_MEMORY); + + valattr[0].pValue = keyvalue; + rv = C_GetAttributeValue(hSession, + (CK_OBJECT_HANDLE)pubKey, + valattr, 1); + if (rv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + free(keyvalue); + return (KMF_ERR_BAD_PARAMETER); + } + + IDInput.Data = keyvalue; + IDInput.Length = valueLen; + } else { + return (KMF_ERR_BAD_PARAMETER); + } + + if (params->keylabel != NULL && + strlen(params->keylabel)) { + + SETATTR(labelattr, 0, CKA_LABEL, params->keylabel, + strlen(params->keylabel)); + + /* Set the CKA_LABEL if one was indicated */ + if ((ckrv = C_SetAttributeValue(hSession, pubKey, + labelattr, 1)) != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + goto cleanup; + } + if (pubkey != NULL) { + pubkey->keylabel = + (char *)strdup(params->keylabel); + if (pubkey->keylabel == NULL) { + rv = KMF_ERR_MEMORY; + goto cleanup; + } + } + if ((ckrv = C_SetAttributeValue(hSession, priKey, + labelattr, 1)) != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + goto cleanup; + } + if (privkey != NULL) { + privkey->keylabel = + (char *)strdup(params->keylabel); + if (privkey->keylabel == NULL) { + rv = KMF_ERR_MEMORY; + goto cleanup; + } + } + } + + /* Now, assign a CKA_ID value so it can be searched */ + /* ID_Input was assigned above in the RSA or DSA keygen section */ + IDOutput.Data = (uchar_t *)IDHashData; + IDOutput.Length = sizeof (IDHashData); + + rv = DigestData(hSession, &IDInput, &IDOutput); + free(IDInput.Data); + + if (rv != CKR_OK) { + SET_ERROR(kmfh, rv); + goto cleanup; + } + SETATTR(idattr, 0, CKA_ID, IDOutput.Data, IDOutput.Length); + if ((ckrv = C_SetAttributeValue(hSession, pubKey, + idattr, 1)) != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + goto cleanup; + } + if ((ckrv = C_SetAttributeValue(hSession, priKey, + idattr, 1)) != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + goto cleanup; + } + +cleanup: + if (rv != KMF_OK) { + if (pubKey != CK_INVALID_HANDLE) + (void) C_DestroyObject(hSession, pubKey); + if (priKey != CK_INVALID_HANDLE) + (void) C_DestroyObject(hSession, priKey); + if (privkey) { + privkey->keyp = NULL; + if (privkey->keylabel) + free(privkey->keylabel); + } + if (pubkey) { + pubkey->keyp = NULL; + if (pubkey->keylabel) + free(pubkey->keylabel); + } + } + return (rv); +} + +KMF_RETURN +KMFPK11_DeleteKey(KMF_HANDLE_T handle, KMF_DELETEKEY_PARAMS *params, + KMF_KEY_HANDLE *key, boolean_t destroy) +{ + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CK_RV ckrv = CKR_OK; + KMF_RETURN rv = KMF_OK; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (key == NULL || key->keyp == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (key->keyclass != KMF_ASYM_PUB && + key->keyclass != KMF_ASYM_PRI && + key->keyclass != KMF_SYMMETRIC) + return (KMF_ERR_BAD_KEY_CLASS); + + if (destroy) { + rv = pk11_authenticate(handle, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + } + + if (!key->israw && destroy) + ckrv = C_DestroyObject(kmfh->pk11handle, + (CK_OBJECT_HANDLE)key->keyp); + + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + /* Report authentication failures to the caller */ + if (ckrv == CKR_PIN_EXPIRED || + ckrv == CKR_SESSION_READ_ONLY) + rv = KMF_ERR_AUTH_FAILED; + else + rv = KMF_ERR_INTERNAL; + } + return (rv); + +} + +KMF_RETURN +KMFPK11_SignData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *keyp, + KMF_OID *algOID, + KMF_DATA *tobesigned, + KMF_DATA *output) +{ + CK_RV ckrv; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CK_SESSION_HANDLE hSession = kmfh->pk11handle; + CK_MECHANISM mechanism; + PKCS_ALGORITHM_MAP *pAlgMap; + KMF_ALGORITHM_INDEX AlgId; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (keyp == NULL || algOID == NULL || + tobesigned == NULL || output == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* These functions are available to the plugin from libkmf */ + AlgId = X509_AlgorithmOidToAlgId(algOID); + if (AlgId == KMF_ALGID_NONE) + return (KMF_ERR_BAD_PARAMETER); + + /* Map the Algorithm OID to a PKCS#11 mechanism */ + pAlgMap = PKCS_GetAlgorithmMap(KMF_ALGCLASS_SIGNATURE, + AlgId, PKCS_GetDefaultSignatureMode(AlgId)); + + if (pAlgMap == NULL) + return (KMF_ERR_BAD_PARAMETER); + + mechanism.mechanism = pAlgMap->pkcs_mechanism; + mechanism.pParameter = NULL; + mechanism.ulParameterLen = 0; + + ckrv = C_SignInit(hSession, &mechanism, (CK_OBJECT_HANDLE)keyp->keyp); + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_INTERNAL); + } + + ckrv = C_Sign(hSession, + tobesigned->Data, tobesigned->Length, + output->Data, (CK_ULONG *)&output->Length); + + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_INTERNAL); + } + + return (KMF_OK); +} + +KMF_RETURN +KMFPK11_GetErrorString(KMF_HANDLE_T handle, char **msgstr) +{ + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + *msgstr = NULL; + if (kmfh->lasterr.errcode != 0) { + char *e = pkcs11_strerror(kmfh->lasterr.errcode); + if (e == NULL || (*msgstr = (char *)strdup(e)) == NULL) { + return (KMF_ERR_MEMORY); + } + } + + return (KMF_OK); +} + +static CK_RV +getObjectKeytype(KMF_HANDLE_T handle, CK_OBJECT_HANDLE obj, + CK_ULONG *keytype) +{ + CK_RV rv = CKR_OK; + CK_ATTRIBUTE templ; + CK_ULONG len = sizeof (CK_ULONG); + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + templ.type = CKA_KEY_TYPE; + templ.pValue = keytype; + templ.ulValueLen = len; + + rv = C_GetAttributeValue(kmfh->pk11handle, obj, &templ, 1); + + return (rv); + +} +static CK_RV +getObjectLabel(KMF_HANDLE_T handle, CK_OBJECT_HANDLE obj, + char **outlabel) +{ + CK_RV rv = CKR_OK; + CK_ATTRIBUTE templ; + char Label[BUFSIZ]; + CK_ULONG len = sizeof (Label); + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + (void) memset(Label, 0, len); + templ.type = CKA_LABEL; + templ.pValue = Label; + templ.ulValueLen = len; + + rv = C_GetAttributeValue(kmfh->pk11handle, obj, &templ, 1); + if (rv == CKR_OK) { + *outlabel = (char *)strdup(Label); + } else { + *outlabel = NULL; + } + return (rv); +} + +KMF_RETURN +KMFPK11_GetPrikeyByCert(KMF_HANDLE_T handle, + KMF_CRYPTOWITHCERT_PARAMS *params, + KMF_DATA *SignerCertData, KMF_KEY_HANDLE *key, + KMF_KEY_ALG keytype) +{ + KMF_X509_SPKI *pubkey; + KMF_X509_CERTIFICATE *SignerCert = NULL; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_RETURN rv = KMF_OK; + CK_RV ckrv = CKR_OK; + CK_ATTRIBUTE templ[4]; + CK_OBJECT_HANDLE pri_obj = CK_INVALID_HANDLE; + CK_ULONG obj_count; + CK_OBJECT_CLASS certClass = CKO_PRIVATE_KEY; + CK_BBOOL true = TRUE; + KMF_DATA Id = { NULL, 0 }; + + /* Decode the signer cert so we can get the SPKI data */ + if ((rv = DerDecodeSignedCertificate(SignerCertData, + &SignerCert)) != KMF_OK) + return (rv); + + /* Get the public key info from the signer certificate */ + pubkey = &SignerCert->certificate.subjectPublicKeyInfo; + + /* Generate an ID from the SPKI data */ + rv = GetIDFromSPKI(pubkey, &Id); + + if (rv != KMF_OK) { + SET_ERROR(kmfh, rv); + goto errout; + } + + SETATTR(templ, 0, CKA_CLASS, &certClass, sizeof (certClass)); + SETATTR(templ, 1, CKA_TOKEN, &true, sizeof (true)); + SETATTR(templ, 2, CKA_PRIVATE, &true, sizeof (true)); + SETATTR(templ, 3, CKA_ID, Id.Data, Id.Length); + + rv = pk11_authenticate(handle, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + if ((ckrv = C_FindObjectsInit(kmfh->pk11handle, templ, 4)) != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + goto errout; + } + + if ((rv = C_FindObjects(kmfh->pk11handle, &pri_obj, 1, + &obj_count)) != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + goto errout; + } + + if (obj_count == 0) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + goto errout; + } + + key->kstype = KMF_KEYSTORE_PK11TOKEN; + key->keyclass = KMF_ASYM_PRI; + key->keyalg = keytype; + key->keyp = (void *)pri_obj; + + (void) C_FindObjectsFinal(kmfh->pk11handle); + + ckrv = getObjectLabel(handle, (CK_OBJECT_HANDLE)key->keyp, + &key->keylabel); + + if (ckrv != CKR_OK) { + SET_ERROR(handle, ckrv); + rv = KMF_ERR_INTERNAL; + } else { + rv = KMF_OK; + } + + if (rv == KMF_OK && params->format == KMF_FORMAT_RAWKEY) { + KMF_RAW_KEY_DATA *rkey = NULL; + rv = keyObj2RawKey(handle, key, &rkey); + if (rv == KMF_OK) { + key->keyp = rkey; + key->israw = TRUE; + } + } + +errout: + if (Id.Data != NULL) + free(Id.Data); + + if (SignerCert != NULL) { + KMF_FreeSignedCert(SignerCert); + free(SignerCert); + } + return (rv); +} + +KMF_RETURN +KMFPK11_DecryptData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key, + KMF_OID *algOID, KMF_DATA *ciphertext, + KMF_DATA *output) +{ + CK_RV ckrv; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CK_SESSION_HANDLE hSession = kmfh->pk11handle; + CK_MECHANISM mechanism; + PKCS_ALGORITHM_MAP *pAlgMap; + KMF_ALGORITHM_INDEX AlgId; + CK_ULONG out_len = 0, block_len = 0, total_decrypted = 0; + uint8_t *in_data, *out_data; + int i, blocks; + CK_ATTRIBUTE ckTemplate[1]; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (key == NULL || algOID == NULL || + ciphertext == NULL || output == NULL) + return (KMF_ERR_BAD_PARAMETER); + + AlgId = X509_AlgorithmOidToAlgId(algOID); + if (AlgId == KMF_ALGID_NONE) + return (KMF_ERR_BAD_PARAMETER); + + /* Map the Algorithm ID to a PKCS#11 mechanism */ + pAlgMap = PKCS_GetAlgorithmMap(KMF_ALGCLASS_SIGNATURE, + AlgId, PKCS_GetDefaultSignatureMode(AlgId)); + + if (pAlgMap == NULL) + return (KMF_ERR_BAD_PARAMETER); + + mechanism.mechanism = pAlgMap->pkcs_mechanism; + mechanism.pParameter = NULL; + mechanism.ulParameterLen = 0; + + SETATTR(ckTemplate, 0, CKA_MODULUS, (CK_BYTE *)NULL, + sizeof (CK_ULONG)); + + /* Get the modulus length */ + ckrv = C_GetAttributeValue(hSession, + (CK_OBJECT_HANDLE)key->keyp, ckTemplate, 1); + + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_INTERNAL); + } + + block_len = ckTemplate[0].ulValueLen; + + /* Compute the number of times to do single-part decryption */ + blocks = ciphertext->Length/block_len; + + out_data = output->Data; + in_data = ciphertext->Data; + out_len = block_len - 11; + + for (i = 0; i < blocks; i++) { + ckrv = C_DecryptInit(hSession, &mechanism, + (CK_OBJECT_HANDLE)key->keyp); + + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_INTERNAL); + } + + ckrv = C_Decrypt(hSession, in_data, block_len, + out_data, (CK_ULONG *)&out_len); + + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_INTERNAL); + } + + out_data += out_len; + total_decrypted += out_len; + in_data += block_len; + + } + + output->Length = total_decrypted; + return (KMF_OK); +} + +static void +attr2bigint(CK_ATTRIBUTE_PTR attr, KMF_BIGINT *big) +{ + big->val = attr->pValue; + big->len = attr->ulValueLen; +} + + +static KMF_RETURN +get_raw_rsa(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, KMF_RAW_RSA_KEY *rawrsa) +{ + KMF_RETURN rv = KMF_OK; + CK_SESSION_HANDLE sess = kmfh->pk11handle; + CK_ATTRIBUTE rsa_pri_attrs[8] = { + { CKA_MODULUS, NULL, 0 }, + { CKA_PUBLIC_EXPONENT, NULL, 0 }, + { CKA_PRIVATE_EXPONENT, NULL, 0 }, /* optional */ + { CKA_PRIME_1, NULL, 0 }, /* | */ + { CKA_PRIME_2, NULL, 0 }, /* | */ + { CKA_EXPONENT_1, NULL, 0 }, /* | */ + { CKA_EXPONENT_2, NULL, 0 }, /* | */ + { CKA_COEFFICIENT, NULL, 0 } /* V */ + }; + CK_ULONG count = sizeof (rsa_pri_attrs) / sizeof (CK_ATTRIBUTE); + int i; + + if ((rv = C_GetAttributeValue(sess, obj, + rsa_pri_attrs, count)) != CKR_OK) { + SET_ERROR(kmfh, rv); + return (KMF_ERR_INTERNAL); + } + + /* Allocate memory for each attribute. */ + for (i = 0; i < count; i++) { + if (rsa_pri_attrs[i].ulValueLen == (CK_ULONG)-1 || + rsa_pri_attrs[i].ulValueLen == 0) { + rsa_pri_attrs[i].ulValueLen = 0; + continue; + } + if ((rsa_pri_attrs[i].pValue = + malloc(rsa_pri_attrs[i].ulValueLen)) == NULL) { + rv = KMF_ERR_MEMORY; + goto end; + } + } + /* Now that we have space, really get the attributes */ + if ((rv = C_GetAttributeValue(sess, obj, + rsa_pri_attrs, count)) != CKR_OK) { + SET_ERROR(kmfh, rv); + rv = KMF_ERR_INTERNAL; + goto end; + } + i = 0; + attr2bigint(&(rsa_pri_attrs[i++]), &rawrsa->mod); + attr2bigint(&(rsa_pri_attrs[i++]), &rawrsa->pubexp); + + if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 && + rsa_pri_attrs[i].ulValueLen != 0) + attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->priexp); + i++; + + if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 && + rsa_pri_attrs[i].ulValueLen != 0) + attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->prime1); + i++; + + if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 && + rsa_pri_attrs[i].ulValueLen != 0) + attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->prime2); + i++; + + if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 && + rsa_pri_attrs[i].ulValueLen != 0) + attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->exp1); + i++; + + if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 && + rsa_pri_attrs[i].ulValueLen != 0) + attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->exp2); + i++; + + if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 && + rsa_pri_attrs[i].ulValueLen != 0) + attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->coef); + i++; + +end: + if (rv != KMF_OK) { + for (i = 0; i < count; i++) { + if (rsa_pri_attrs[i].pValue != NULL) + free(rsa_pri_attrs[i].pValue); + } + (void) memset(rawrsa, 0, sizeof (KMF_RAW_RSA_KEY)); + } + return (rv); +} + +static KMF_RETURN +get_raw_dsa(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, KMF_RAW_DSA_KEY *rawdsa) +{ + KMF_RETURN rv = KMF_OK; + CK_SESSION_HANDLE sess = kmfh->pk11handle; + CK_ATTRIBUTE dsa_pri_attrs[8] = { + { CKA_PRIME, NULL, 0 }, + { CKA_SUBPRIME, NULL, 0 }, + { CKA_BASE, NULL, 0 }, + { CKA_VALUE, NULL, 0 } + }; + CK_ULONG count = sizeof (dsa_pri_attrs) / sizeof (CK_ATTRIBUTE); + int i; + + if ((rv = C_GetAttributeValue(sess, obj, + dsa_pri_attrs, count)) != CKR_OK) { + SET_ERROR(kmfh, rv); + return (KMF_ERR_INTERNAL); + } + + /* Allocate memory for each attribute. */ + for (i = 0; i < count; i++) { + if (dsa_pri_attrs[i].ulValueLen == (CK_ULONG)-1 || + dsa_pri_attrs[i].ulValueLen == 0) { + dsa_pri_attrs[i].ulValueLen = 0; + continue; + } + if ((dsa_pri_attrs[i].pValue = + malloc(dsa_pri_attrs[i].ulValueLen)) == NULL) { + rv = KMF_ERR_MEMORY; + goto end; + } + } + if ((rv = C_GetAttributeValue(sess, obj, + dsa_pri_attrs, count)) != CKR_OK) { + SET_ERROR(kmfh, rv); + rv = KMF_ERR_INTERNAL; + goto end; + } + + /* Fill in all the temp variables. They are all required. */ + i = 0; + attr2bigint(&(dsa_pri_attrs[i++]), &rawdsa->prime); + attr2bigint(&(dsa_pri_attrs[i++]), &rawdsa->subprime); + attr2bigint(&(dsa_pri_attrs[i++]), &rawdsa->base); + attr2bigint(&(dsa_pri_attrs[i++]), &rawdsa->value); + +end: + if (rv != KMF_OK) { + for (i = 0; i < count; i++) { + if (dsa_pri_attrs[i].pValue != NULL) + free(dsa_pri_attrs[i].pValue); + } + (void) memset(rawdsa, 0, sizeof (KMF_RAW_DSA_KEY)); + } + return (rv); +} + +static KMF_RETURN +get_raw_sym(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, KMF_RAW_SYM_KEY *rawsym) +{ + KMF_RETURN rv = KMF_OK; + CK_RV ckrv; + CK_SESSION_HANDLE sess = kmfh->pk11handle; + CK_ATTRIBUTE sym_attr[1]; + CK_ULONG value_len = 0; + + /* find the key length first */ + sym_attr[0].type = CKA_VALUE; + sym_attr[0].pValue = NULL; + sym_attr[0].ulValueLen = value_len; + if ((ckrv = C_GetAttributeValue(sess, obj, sym_attr, 1)) != CKR_OK) { + /* + * Don't return error if the key is sensitive, just + * don't return any raw data. Operations like "list" + * need to succeed even if the raw data is not + * available. + */ + if (ckrv == CKR_ATTRIBUTE_SENSITIVE) { + rawsym->keydata.val = NULL; + rawsym->keydata.len = 0; + return (CKR_OK); + } + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_INTERNAL); + } + + /* Allocate memory for pValue */ + sym_attr[0].pValue = malloc(sym_attr[0].ulValueLen); + if (sym_attr[0].pValue == NULL) { + return (KMF_ERR_MEMORY); + } + + /* get the key data */ + if ((rv = C_GetAttributeValue(sess, obj, sym_attr, 1)) != CKR_OK) { + SET_ERROR(kmfh, rv); + free(sym_attr[0].pValue); + return (KMF_ERR_INTERNAL); + } + + rawsym->keydata.val = sym_attr[0].pValue; + rawsym->keydata.len = sym_attr[0].ulValueLen; + return (rv); +} + +static KMF_RETURN +keyObj2RawKey(KMF_HANDLE_T handle, KMF_KEY_HANDLE *inkey, + KMF_RAW_KEY_DATA **outkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_RAW_KEY_DATA *rkey; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + rkey = malloc(sizeof (KMF_RAW_KEY_DATA)); + if (rkey == NULL) + return (KMF_ERR_MEMORY); + + (void) memset(rkey, 0, sizeof (KMF_RAW_KEY_DATA)); + + rkey->keytype = inkey->keyalg; + + if (inkey->keyalg == KMF_RSA) { + rv = get_raw_rsa(kmfh, (CK_OBJECT_HANDLE)inkey->keyp, + &rkey->rawdata.rsa); + } else if (inkey->keyalg == KMF_DSA) { + rv = get_raw_dsa(kmfh, (CK_OBJECT_HANDLE)inkey->keyp, + &rkey->rawdata.dsa); + } else if (inkey->keyalg == KMF_AES || + inkey->keyalg == KMF_RC4 || + inkey->keyalg == KMF_DES || + inkey->keyalg == KMF_DES3) { + rv = get_raw_sym(kmfh, (CK_OBJECT_HANDLE)inkey->keyp, + &rkey->rawdata.sym); + } else { + rv = KMF_ERR_BAD_PARAMETER; + } + + if (rv == KMF_OK) { + *outkey = rkey; + } else if (rkey != NULL) { + free(rkey); + *outkey = NULL; + } + + return (rv); +} + + +static KMF_RETURN +kmf2pk11keytype(KMF_KEY_ALG keyalg, CK_KEY_TYPE *type) +{ + switch (keyalg) { + case KMF_RSA: + *type = CKK_RSA; + break; + case KMF_DSA: + *type = CKK_DSA; + break; + case KMF_AES: + *type = CKK_AES; + break; + case KMF_RC4: + *type = CKK_RC4; + break; + case KMF_DES: + *type = CKK_DES; + break; + case KMF_DES3: + *type = CKK_DES3; + break; + default: + return (KMF_ERR_BAD_KEY_TYPE); + } + + return (KMF_OK); +} + +static int +IDStringToData(char *idstr, KMF_DATA *iddata) +{ + int len, i; + char *iddup, *byte; + uint_t lvalue; + + if (idstr == NULL || !strlen(idstr)) + return (-1); + + iddup = (char *)strdup(idstr); + if (iddup == NULL) + return (KMF_ERR_MEMORY); + + len = strlen(iddup) / 3 + 1; + iddata->Data = malloc(len); + if (iddata->Data == NULL) + return (KMF_ERR_MEMORY); + (void) memset(iddata->Data, 0, len); + iddata->Length = len; + + byte = strtok(iddup, ":"); + if (byte == NULL) { + free(iddup); + free(iddata->Data); + iddata->Data = NULL; + iddata->Length = 0; + return (-1); + } + + i = 0; + do { + (void) sscanf(byte, "%x", &lvalue); + iddata->Data[i++] = (uchar_t)(lvalue & 0x000000FF); + byte = strtok(NULL, ":"); + } while (byte != NULL && i < len); + + iddata->Length = i; + free(iddup); + return (0); +} + +KMF_RETURN +KMFPK11_FindKey(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS *parms, + KMF_KEY_HANDLE *keys, uint32_t *numkeys) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + uint32_t want_keys, i; + CK_RV ckrv; + CK_ATTRIBUTE pTmpl[10]; + CK_OBJECT_CLASS class; + CK_BBOOL true = TRUE; + CK_BBOOL false = FALSE; + CK_ULONG alg; + CK_BBOOL is_token; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (parms == NULL || numkeys == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (numkeys != NULL && *numkeys > 0) + want_keys = *numkeys; + else + want_keys = MAXINT; /* count them all */ + + if (parms->keyclass == KMF_ASYM_PUB) { + class = CKO_PUBLIC_KEY; + is_token = false; + } else if (parms->keyclass == KMF_ASYM_PRI) { + class = CKO_PRIVATE_KEY; + is_token = true; + } else if (parms->keyclass == KMF_SYMMETRIC) { + class = CKO_SECRET_KEY; + is_token = true; + } else { + return (KMF_ERR_BAD_KEY_CLASS); + } + + i = 0; + pTmpl[i].type = CKA_TOKEN; + pTmpl[i].pValue = &is_token; + pTmpl[i].ulValueLen = sizeof (CK_BBOOL); + i++; + + pTmpl[i].type = CKA_CLASS; + pTmpl[i].pValue = &class; + pTmpl[i].ulValueLen = sizeof (class); + i++; + + if (parms->findLabel != NULL && strlen(parms->findLabel)) { + pTmpl[i].type = CKA_LABEL; + pTmpl[i].pValue = parms->findLabel; + pTmpl[i].ulValueLen = strlen(parms->findLabel); + i++; + } + + if (parms->keytype != 0) { + rv = kmf2pk11keytype(parms->keytype, &alg); + if (rv != KMF_OK) { + return (KMF_ERR_BAD_KEY_TYPE); + } + pTmpl[i].type = CKA_KEY_TYPE; + pTmpl[i].pValue = &alg; + pTmpl[i].ulValueLen = sizeof (alg); + i++; + } + + if (parms->idstr != NULL) { + KMF_DATA iddata = { NULL, 0 }; + + /* + * ID String parameter is assumed to be of form: + * XX:XX:XX:XX:XX ... :XX + * where XX is a hex number. + * + * We must convert this back to binary in order to + * use it in a search. + */ + rv = IDStringToData(parms->idstr, &iddata); + if (rv == KMF_OK) { + pTmpl[i].type = CKA_ID; + pTmpl[i].pValue = iddata.Data; + pTmpl[i].ulValueLen = iddata.Length; + i++; + } else { + return (rv); + } + } + + if (parms->pkcs11parms.private) { + pTmpl[i].type = CKA_PRIVATE; + pTmpl[i].pValue = &true; + pTmpl[i].ulValueLen = sizeof (true); + i++; + } + + if (is_token) { + rv = pk11_authenticate(handle, &parms->cred); + if (rv != KMF_OK) { + return (rv); + } + } + + ckrv = C_FindObjectsInit(kmfh->pk11handle, pTmpl, i); + if (ckrv == CKR_OK) { + CK_ULONG obj_count, n = 0; + while (ckrv == CKR_OK && n < want_keys) { + CK_OBJECT_HANDLE hObj; + + ckrv = C_FindObjects(kmfh->pk11handle, &hObj, + 1, &obj_count); + if (ckrv == CKR_OK && obj_count == 1) { + if (keys != NULL) { + CK_ULONG keytype; + keys[n].kstype = KMF_KEYSTORE_PK11TOKEN; + keys[n].keyclass = parms->keyclass; + keys[n].israw = FALSE; + keys[n].keyp = (void *)hObj; + + ckrv = getObjectKeytype(handle, + (CK_OBJECT_HANDLE)keys[n].keyp, + &keytype); + if (ckrv != CKR_OK) + goto end; + + ckrv = getObjectLabel(handle, + (CK_OBJECT_HANDLE)keys[n].keyp, + &(keys[n].keylabel)); + if (ckrv != CKR_OK) + goto end; + + if (keytype == CKK_RSA) + keys[n].keyalg = KMF_RSA; + else if (keytype == CKK_DSA) + keys[n].keyalg = KMF_DSA; + else if (keytype == CKK_AES) + keys[n].keyalg = KMF_AES; + else if (keytype == CKK_RC4) + keys[n].keyalg = KMF_RC4; + else if (keytype == CKK_DES) + keys[n].keyalg = KMF_DES; + else if (keytype == CKK_DES3) + keys[n].keyalg = KMF_DES3; + + } + n++; + } else { + break; + } + } + ckrv = C_FindObjectsFinal(kmfh->pk11handle); + + /* "numkeys" indicates the number that were actually found */ + *numkeys = n; + } + if (ckrv == KMF_OK && keys != NULL && (*numkeys) > 0 && + parms->format == KMF_FORMAT_RAWKEY) { + /* Convert keys to "rawkey" format */ + for (i = 0; i < (*numkeys); i++) { + KMF_RAW_KEY_DATA *rkey = NULL; + rv = keyObj2RawKey(handle, &keys[i], &rkey); + if (rv == KMF_OK) { + keys[i].keyp = rkey; + keys[i].israw = TRUE; + } else { + break; + } + } + } +end: + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + /* Report authentication failures to the caller */ + if (ckrv == CKR_USER_NOT_LOGGED_IN || + ckrv == CKR_PIN_INCORRECT || + ckrv == CKR_PIN_INVALID || + ckrv == CKR_PIN_EXPIRED || + ckrv == CKR_PIN_LOCKED || + ckrv == CKR_SESSION_READ_ONLY) + rv = KMF_ERR_AUTH_FAILED; + else + rv = KMF_ERR_INTERNAL; + } else if ((*numkeys) == 0) { + rv = KMF_ERR_KEY_NOT_FOUND; + } + + return (rv); +} + +static char * +convertDate(char *fulldate) +{ + struct tm tms; + char newtime[9]; + + (void) strptime(fulldate, "%b %d %T %Y %Z", &tms); + + if (tms.tm_year < 69) + tms.tm_year += 100; + + (void) strftime(newtime, sizeof (newtime), "m%d", &tms); + + newtime[8] = 0; + + /* memory returned must be freed by the caller */ + return ((char *)strdup(newtime)); +} + +KMF_RETURN +KMFPK11_StorePrivateKey(KMF_HANDLE_T handle, KMF_STOREKEY_PARAMS *params, + KMF_RAW_KEY_DATA *rawkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + int i; + CK_RV ckrv = CKR_OK; + CK_ATTRIBUTE templ[32]; + CK_OBJECT_HANDLE keyobj; + CK_KEY_TYPE keytype; + CK_OBJECT_CLASS oClass = CKO_PRIVATE_KEY; + CK_BBOOL cktrue = TRUE; + CK_DATE startdate, enddate; + KMF_DATA id = {NULL, 0}; + KMF_DATA subject = {NULL, 0}; + KMF_X509EXT_KEY_USAGE kuext; + KMF_X509_CERTIFICATE *x509 = NULL; + CK_BBOOL kufound; + char *notbefore = NULL, *start = NULL; + char *notafter = NULL, *end = NULL; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (params == NULL || params->certificate == NULL || + rawkey == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (rawkey->keytype == KMF_RSA) + keytype = CKK_RSA; + else if (rawkey->keytype == KMF_DSA) + keytype = CKK_DSA; + else + return (KMF_ERR_BAD_PARAMETER); + + rv = pk11_authenticate(handle, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + id.Data = NULL; + id.Length = 0; + rv = KMF_GetCertIDData(params->certificate, &id); + if (rv != KMF_OK) { + goto cleanup; + } + + rv = DerDecodeSignedCertificate( + (const KMF_DATA *)params->certificate, &x509); + if (rv != KMF_OK) { + goto cleanup; + } + + rv = DerEncodeName(&x509->certificate.subject, &subject); + if (rv != KMF_OK) { + goto cleanup; + } + + rv = KMF_GetCertStartDateString(handle, params->certificate, + ¬before); + if (rv != KMF_OK) { + goto cleanup; + } + start = convertDate(notbefore); + + rv = KMF_GetCertEndDateString(handle, params->certificate, + ¬after); + if (rv != KMF_OK) { + goto cleanup; + } + end = convertDate(notafter); + + if ((rv = KMF_GetCertKeyUsageExt(params->certificate, &kuext)) + != KMF_OK && rv != KMF_ERR_EXTENSION_NOT_FOUND) + goto cleanup; + + kufound = (rv == KMF_OK); + rv = KMF_OK; /* reset if we got KMF_ERR_EXTENSION_NOT_FOUND above */ + + i = 0; + SETATTR(templ, i, CKA_CLASS, &oClass, sizeof (CK_OBJECT_CLASS)); i++; + SETATTR(templ, i, CKA_KEY_TYPE, &keytype, sizeof (keytype)); i++; + SETATTR(templ, i, CKA_TOKEN, &cktrue, sizeof (cktrue)); i++; + SETATTR(templ, i, CKA_PRIVATE, &cktrue, sizeof (cktrue)); i++; + SETATTR(templ, i, CKA_SUBJECT, subject.Data, subject.Length); i++; + + /* + * Only set the KeyUsage stuff if the KU extension was present. + */ + if (kufound) { + CK_BBOOL condition; + + condition = (kuext.KeyUsageBits & KMF_keyEncipherment) ? + B_TRUE : B_FALSE; + SETATTR(templ, i, CKA_UNWRAP, &condition, + sizeof (CK_BBOOL)); i++; + condition = (kuext.KeyUsageBits & KMF_dataEncipherment) ? + B_TRUE : B_FALSE; + SETATTR(templ, i, CKA_DECRYPT, &condition, + sizeof (CK_BBOOL)); i++; + condition = (kuext.KeyUsageBits & KMF_digitalSignature) ? + B_TRUE : B_FALSE; + SETATTR(templ, i, CKA_SIGN, &condition, + sizeof (CK_BBOOL)); i++; + condition = (kuext.KeyUsageBits & KMF_digitalSignature) ? + B_TRUE : B_FALSE; + SETATTR(templ, i, CKA_SIGN_RECOVER, &condition, + sizeof (CK_BBOOL)); i++; + } + if (params->label != NULL) { + SETATTR(templ, i, CKA_LABEL, params->label, + strlen(params->label)); + i++; + } + if (id.Data != NULL && + id.Data != NULL && id.Length > 0) { + SETATTR(templ, i, CKA_ID, id.Data, id.Length); + i++; + } + if (start != NULL) { + /* + * This make some potentially dangerous assumptions: + * 1. that the startdate in the parameter block is + * properly formatted as YYYYMMDD + * 2. That the CK_DATE structure is always the same. + */ + (void) memcpy(&startdate, start, sizeof (CK_DATE)); + SETATTR(templ, i, CKA_START_DATE, &startdate, + sizeof (startdate)); + i++; + } + if (end != NULL) { + (void) memcpy(&enddate, end, sizeof (CK_DATE)); + SETATTR(templ, i, CKA_END_DATE, &enddate, sizeof (enddate)); + i++; + } + if (keytype == CKK_RSA) { + SETATTR(templ, i, CKA_MODULUS, + rawkey->rawdata.rsa.mod.val, + rawkey->rawdata.rsa.mod.len); + i++; + SETATTR(templ, i, CKA_PUBLIC_EXPONENT, + rawkey->rawdata.rsa.pubexp.val, + rawkey->rawdata.rsa.pubexp.len); + i++; + if (rawkey->rawdata.rsa.priexp.val != NULL) { + SETATTR(templ, i, CKA_PRIVATE_EXPONENT, + rawkey->rawdata.rsa.priexp.val, + rawkey->rawdata.rsa.priexp.len); + i++; + } + if (rawkey->rawdata.rsa.prime1.val != NULL) { + SETATTR(templ, i, CKA_PRIME_1, + rawkey->rawdata.rsa.prime1.val, + rawkey->rawdata.rsa.prime1.len); + i++; + } + if (rawkey->rawdata.rsa.prime2.val != NULL) { + SETATTR(templ, i, CKA_PRIME_2, + rawkey->rawdata.rsa.prime2.val, + rawkey->rawdata.rsa.prime2.len); + i++; + } + if (rawkey->rawdata.rsa.exp1.val != NULL) { + SETATTR(templ, i, CKA_EXPONENT_1, + rawkey->rawdata.rsa.exp1.val, + rawkey->rawdata.rsa.exp1.len); + i++; + } + if (rawkey->rawdata.rsa.exp2.val != NULL) { + SETATTR(templ, i, CKA_EXPONENT_2, + rawkey->rawdata.rsa.exp2.val, + rawkey->rawdata.rsa.exp2.len); + i++; + } + if (rawkey->rawdata.rsa.coef.val != NULL) { + SETATTR(templ, i, CKA_COEFFICIENT, + rawkey->rawdata.rsa.coef.val, + rawkey->rawdata.rsa.coef.len); + i++; + } + } else { + SETATTR(templ, i, CKA_PRIME, + rawkey->rawdata.dsa.prime.val, + rawkey->rawdata.dsa.prime.len); + i++; + SETATTR(templ, i, CKA_SUBPRIME, + rawkey->rawdata.dsa.subprime.val, + rawkey->rawdata.dsa.subprime.len); + i++; + SETATTR(templ, i, CKA_BASE, + rawkey->rawdata.dsa.base.val, + rawkey->rawdata.dsa.base.len); + i++; + SETATTR(templ, i, CKA_VALUE, + rawkey->rawdata.dsa.value.val, + rawkey->rawdata.dsa.value.len); + i++; + } + + ckrv = C_CreateObject(kmfh->pk11handle, templ, i, &keyobj); + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + + /* Report authentication failures to the caller */ + if (ckrv == CKR_USER_NOT_LOGGED_IN || + ckrv == CKR_PIN_INCORRECT || + ckrv == CKR_PIN_INVALID || + ckrv == CKR_PIN_EXPIRED || + ckrv == CKR_PIN_LOCKED || + ckrv == CKR_SESSION_READ_ONLY) + rv = KMF_ERR_AUTH_FAILED; + else + rv = KMF_ERR_INTERNAL; + } +cleanup: + KMF_FreeData(&id); + KMF_FreeData(&subject); + KMF_FreeSignedCert(x509); + free(x509); + + return (rv); +} + +KMF_RETURN +KMFPK11_CreateSymKey(KMF_HANDLE_T handle, KMF_CREATESYMKEY_PARAMS *params, + KMF_KEY_HANDLE *symkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CK_RV ckrv; + CK_SESSION_HANDLE hSession = kmfh->pk11handle; + CK_OBJECT_HANDLE keyhandle; + CK_MECHANISM keyGenMech; + CK_OBJECT_CLASS class = CKO_SECRET_KEY; + CK_ULONG secKeyType; + CK_ULONG secKeyLen; /* for RC4 and AES */ + CK_BBOOL true = TRUE; + CK_BBOOL false = FALSE; + CK_ATTRIBUTE templ[15]; + int i; + + if (kmfh == NULL) + return (KMF_ERR_UNINITIALIZED); + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + keyGenMech.pParameter = NULL_PTR; + keyGenMech.ulParameterLen = 0; + switch (params->keytype) { + case KMF_AES: + keyGenMech.mechanism = CKM_AES_KEY_GEN; + secKeyType = CKK_AES; + break; + case KMF_RC4: + keyGenMech.mechanism = CKM_RC4_KEY_GEN; + secKeyType = CKK_RC4; + break; + case KMF_DES: + keyGenMech.mechanism = CKM_DES_KEY_GEN; + secKeyType = CKK_DES; + break; + case KMF_DES3: + keyGenMech.mechanism = CKM_DES3_KEY_GEN; + secKeyType = CKK_DES3; + break; + default: + return (KMF_ERR_BAD_KEY_TYPE); + } + + i = 0; + SETATTR(templ, i, CKA_CLASS, &class, sizeof (class)); + i++; + SETATTR(templ, i, CKA_KEY_TYPE, &secKeyType, sizeof (secKeyType)); + i++; + + if (params->keytype == KMF_AES || params->keytype == KMF_RC4) { + if ((params->keylength % 8) != 0) { + return (KMF_ERR_BAD_KEY_SIZE); + } + secKeyLen = params->keylength/8; /* in bytes for RC4/AES */ + SETATTR(templ, i, CKA_VALUE_LEN, &secKeyLen, + sizeof (secKeyLen)); + i++; + } + + if (params->keylabel != NULL) { + SETATTR(templ, i, CKA_LABEL, params->keylabel, + strlen(params->keylabel)); + i++; + } + + if (params->pkcs11parms.sensitive == B_TRUE) { + SETATTR(templ, i, CKA_SENSITIVE, &true, sizeof (true)); + } else { + SETATTR(templ, i, CKA_SENSITIVE, &false, sizeof (false)); + } + i++; + + if (params->pkcs11parms.not_extractable == B_TRUE) { + SETATTR(templ, i, CKA_EXTRACTABLE, &false, sizeof (false)); + } else { + SETATTR(templ, i, CKA_EXTRACTABLE, &true, sizeof (true)); + } + i++; + + SETATTR(templ, i, CKA_TOKEN, &true, sizeof (true)); + i++; + SETATTR(templ, i, CKA_PRIVATE, &true, sizeof (true)); + i++; + SETATTR(templ, i, CKA_ENCRYPT, &true, sizeof (true)); + i++; + SETATTR(templ, i, CKA_DECRYPT, &true, sizeof (true)); + i++; + SETATTR(templ, i, CKA_SIGN, &true, sizeof (true)); + i++; + SETATTR(templ, i, CKA_VERIFY, &true, sizeof (true)); + i++; + + rv = pk11_authenticate(handle, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + ckrv = C_GenerateKey(hSession, &keyGenMech, templ, i, &keyhandle); + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_KEYGEN_FAILED; + goto out; + } + + symkey->kstype = KMF_KEYSTORE_PK11TOKEN; + symkey->keyalg = params->keytype; + symkey->keyclass = KMF_SYMMETRIC; + symkey->israw = FALSE; + symkey->keyp = (void *)keyhandle; + +out: + return (rv); +} + + +KMF_RETURN +KMFPK11_GetSymKeyValue(KMF_HANDLE_T handle, KMF_KEY_HANDLE *symkey, + KMF_RAW_SYM_KEY *rkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + if (kmfh == NULL) + return (KMF_ERR_UNINITIALIZED); + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (symkey == NULL || rkey == NULL) + return (KMF_ERR_BAD_PARAMETER); + else if (symkey->keyclass != KMF_SYMMETRIC) + return (KMF_ERR_BAD_KEY_CLASS); + + if (symkey->israw) { + KMF_RAW_KEY_DATA *rawkey = (KMF_RAW_KEY_DATA *)symkey->keyp; + + if (rawkey == NULL || + rawkey->rawdata.sym.keydata.val == NULL || + rawkey->rawdata.sym.keydata.len == 0) + return (KMF_ERR_BAD_KEYHANDLE); + + rkey->keydata.len = rawkey->rawdata.sym.keydata.len; + if ((rkey->keydata.val = malloc(rkey->keydata.len)) == NULL) + return (KMF_ERR_MEMORY); + (void) memcpy(rkey->keydata.val, + rawkey->rawdata.sym.keydata.val, rkey->keydata.len); + } else { + rv = get_raw_sym(kmfh, (CK_OBJECT_HANDLE)symkey->keyp, rkey); + } + + return (rv); +} + +KMF_RETURN +KMFPK11_SetTokenPin(KMF_HANDLE_T handle, KMF_SETPIN_PARAMS *params, + KMF_CREDENTIAL *newpin) +{ + KMF_RETURN ret = KMF_OK; + CK_RV rv = CKR_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CK_SESSION_HANDLE session = NULL; + + if (handle == NULL || params == NULL || newpin == NULL) + return (KMF_ERR_BAD_PARAMETER); + + rv = C_OpenSession(params->pkcs11parms.slot, + CKF_SERIAL_SESSION | CKF_RW_SESSION, + NULL, NULL, &session); + if (rv != CKR_OK) { + SET_ERROR(kmfh, rv); + ret = KMF_ERR_UNINITIALIZED; + goto end; + } + + rv = C_SetPIN(session, + (CK_BYTE *)params->cred.cred, params->cred.credlen, + (CK_BYTE *)newpin->cred, newpin->credlen); + + if (rv != CKR_OK) { + SET_ERROR(kmfh, rv); + if (rv == CKR_PIN_INCORRECT || + rv == CKR_PIN_INVALID || + rv == CKR_PIN_EXPIRED || + rv == CKR_PIN_LOCKED) + ret = KMF_ERR_AUTH_FAILED; + else + ret = KMF_ERR_INTERNAL; + } +end: + if (session != NULL) + (void) C_CloseSession(session); + return (ret); +} diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/i386/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/i386/Makefile new file mode 100644 index 0000000000..443f78537a --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/i386/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: $(ROOTLIBS) diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparc/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparc/Makefile new file mode 100644 index 0000000000..472ac90a9a --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparc/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: $(ROOTLIBS) diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparcv9/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparcv9/Makefile new file mode 100644 index 0000000000..0dd91e1065 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparcv9/Makefile @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../../../Makefile.lib.64 + +install: $(ROOTLIBS64) |