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/kmf_pkcs11 | |
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/kmf_pkcs11')
-rw-r--r-- | usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile | 46 | ||||
-rw-r--r-- | usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile.com | 65 | ||||
-rw-r--r-- | usr/src/lib/libkmf/plugins/kmf_pkcs11/amd64/Makefile | 30 | ||||
-rw-r--r-- | usr/src/lib/libkmf/plugins/kmf_pkcs11/common/mapfile-vers | 50 | ||||
-rw-r--r-- | usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c | 2945 | ||||
-rw-r--r-- | usr/src/lib/libkmf/plugins/kmf_pkcs11/i386/Makefile | 29 | ||||
-rw-r--r-- | usr/src/lib/libkmf/plugins/kmf_pkcs11/sparc/Makefile | 29 | ||||
-rw-r--r-- | usr/src/lib/libkmf/plugins/kmf_pkcs11/sparcv9/Makefile | 30 |
8 files changed, 3224 insertions, 0 deletions
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) |