# # 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 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../../../Makefile.master include ../../Makefile.lib # Hammerhead: amd64-only SUBDIRS= $(MACH64) all : TARGET= all check : TARGET= check clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install .KEEP_STATE: all clean clobber install: $(SUBDIRS) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: include ../../Makefile.targ # # 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 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. LIBRARY= libpkcs11.a VERS= .1 OBJECTS= \ metaAttrManager.o \ metaCrypt.o \ metaDigest.o \ metaDualCrypt.o \ metaGeneral.o \ metaKeys.o \ metaMechManager.o \ metaObject.o \ metaObjectManager.o \ metaRand.o \ metaSession.o \ metaSessionManager.o \ metaSign.o \ metaSlotManager.o \ metaSlotToken.o \ metaUtil.o \ metaVerify.o \ pkcs11General.o \ pkcs11SlotToken.o \ pkcs11Session.o \ pkcs11Object.o \ pkcs11Crypt.o \ pkcs11Digest.o \ pkcs11Sign.o \ pkcs11Verify.o \ pkcs11DualCrypt.o \ pkcs11Keys.o \ pkcs11Rand.o \ pkcs11Slottable.o \ pkcs11Conf.o \ pkcs11Sessionlist.o \ pkcs11SUNWExtensions.o include ../../../Makefile.lib SRCDIR= ../common INCDIR= ../../include LIBS = $(DYNLIB) # Hammerhead: Add -ldl for dlopen/dlclose/dlsym (GNU ld requires explicit linkage) LDLIBS += -lcryptoutil -ldl -lc CFLAGS += $(CCVERBOSE) CPPFLAGS += -I$(INCDIR) -I$(SRCDIR) -D_REENTRANT CERRWARN += $(CNOWARN_UNINIT) # not linted SMATCH=off .KEEP_STATE: all: $(LIBS) include $(SRC)/lib/Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (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 2004 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: all $(ROOTLIBS64) $(ROOTLINKS64) # # 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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNW_1.1 { global: C_CancelFunction; C_CloseAllSessions; C_CloseSession; C_CopyObject; C_CreateObject; C_Decrypt; C_DecryptDigestUpdate; C_DecryptFinal; C_DecryptInit; C_DecryptUpdate; C_DecryptVerifyUpdate; C_DeriveKey; C_DestroyObject; C_Digest; C_DigestEncryptUpdate; C_DigestFinal; C_DigestInit; C_DigestKey; C_DigestUpdate; C_Encrypt; C_EncryptFinal; C_EncryptInit; C_EncryptUpdate; C_Finalize; C_FindObjects; C_FindObjectsFinal; C_FindObjectsInit; C_GenerateKey; C_GenerateKeyPair; C_GenerateRandom; C_GetAttributeValue; C_GetFunctionList; C_GetFunctionStatus; C_GetInfo; C_GetMechanismInfo; C_GetMechanismList; C_GetObjectSize; C_GetOperationState; C_GetSessionInfo; C_GetSlotInfo; C_GetSlotList; C_GetTokenInfo; C_Initialize; C_InitPIN; C_InitToken; C_Login; C_Logout; C_OpenSession; C_SeedRandom; C_SetAttributeValue; C_SetOperationState; C_SetPIN; C_Sign; C_SignEncryptUpdate; C_SignFinal; C_SignInit; C_SignRecover; C_SignRecoverInit; C_SignUpdate; C_UnwrapKey; C_Verify; C_VerifyFinal; C_VerifyInit; C_VerifyRecover; C_VerifyRecoverInit; C_VerifyUpdate; C_WaitForSlotEvent; C_WrapKey; SUNW_C_GetMechSession; SUNW_C_KeyToObject; local: *; }; SYMBOL_VERSION SUNWprivate { global: pkcs11_GetCriteriaSession; pkcs11_ObjectToKey; pkcs11_PasswdToPBKD2Object; pkcs11_PasswdToKey; local: *; }; /* * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2012 Milan Jurik. All rights reserved. * Copyright (c) 2018, Joyent, Inc. */ #include #include #include #include "metaGlobal.h" #include "metaAttrMasters.h" static void find_attribute(CK_ATTRIBUTE_TYPE attrtype, generic_attr_t *attributes, size_t num_attributes, generic_attr_t **found_attribute); /* * get_master_attributes_by_object * * Returns an (statically allocated) set of object attributes, as determined by * class and keytype of the supplied object. The attributes are only * initialized to default values. */ CK_RV get_master_attributes_by_object(slot_session_t *session, slot_object_t *slot_object, generic_attr_t **attributes, size_t *num_attributes) { CK_RV rv; CK_ATTRIBUTE attr; CK_OBJECT_CLASS class; CK_ULONG subtype = CK_UNAVAILABLE_INFORMATION; /* first get the class */ attr.type = CKA_CLASS; attr.pValue = &class; attr.ulValueLen = sizeof (class); rv = FUNCLIST(session->fw_st_id)->C_GetAttributeValue( session->hSession, slot_object->hObject, &attr, 1); if (rv != CKR_OK) { return (rv); } attr.pValue = &subtype; attr.ulValueLen = sizeof (subtype); switch (class) { case CKO_CERTIFICATE: attr.type = CKA_CERTIFICATE_TYPE; break; case CKO_HW_FEATURE: attr.type = CKA_HW_FEATURE_TYPE; break; case CKO_PUBLIC_KEY: case CKO_PRIVATE_KEY: case CKO_SECRET_KEY: case CKO_DOMAIN_PARAMETERS: attr.type = CKA_KEY_TYPE; break; case CKO_DATA: goto get_attr; default: /* should never be here */ return (CKR_ATTRIBUTE_VALUE_INVALID); } rv = FUNCLIST(session->fw_st_id)->C_GetAttributeValue( session->hSession, slot_object->hObject, &attr, 1); if (rv != CKR_OK) { return (rv); } get_attr: rv = get_master_attributes_by_type(class, subtype, attributes, num_attributes); return (rv); } /* * get_master_attributes_by_template * * Returns an (statically allocated) set of object attributes, as determined by * the supplied object template. The template is only used to determine the * class/subclass of the object. The attributes are only initialized to * default values. */ CK_RV get_master_attributes_by_template( CK_ATTRIBUTE *template, CK_ULONG template_size, generic_attr_t **attributes, size_t *num_attributes) { CK_OBJECT_CLASS class; CK_ULONG subtype = CK_UNAVAILABLE_INFORMATION; boolean_t found; found = get_template_ulong(CKA_CLASS, template, template_size, &class); if (!found) { return (CKR_TEMPLATE_INCOMPLETE); } switch (class) { case CKO_CERTIFICATE: found = get_template_ulong(CKA_CERTIFICATE_TYPE, template, template_size, &subtype); break; case CKO_HW_FEATURE: found = get_template_ulong(CKA_HW_FEATURE_TYPE, template, template_size, &subtype); break; case CKO_PUBLIC_KEY: case CKO_PRIVATE_KEY: case CKO_SECRET_KEY: case CKO_DOMAIN_PARAMETERS: found = get_template_ulong(CKA_KEY_TYPE, template, template_size, &subtype); break; case CKO_DATA: /* CKO_DATA has no subtype, just pretend it is found */ found = B_TRUE; break; default: /* unknown object class */ return (CKR_ATTRIBUTE_VALUE_INVALID); } if (!found) { return (CKR_TEMPLATE_INCOMPLETE); } return (get_master_attributes_by_type(class, subtype, attributes, num_attributes)); } /* * get_master_template_by_type * * Returns an (statically allocated) set of object attributes, as determined * by the specified class and subtype. The attributes are initialized to default * values. */ CK_RV get_master_template_by_type(CK_OBJECT_CLASS class, CK_ULONG subtype, generic_attr_t **attributes, size_t *num_attributes) { generic_attr_t *master_template = NULL; size_t master_template_size = 0; switch (class) { case CKO_HW_FEATURE: switch (subtype) { case CKO_HW_FEATURE: master_template = (generic_attr_t *)OBJ_HW_CLOCK; master_template_size = sizeof (OBJ_HW_CLOCK); break; case CKH_MONOTONIC_COUNTER: master_template = (generic_attr_t *)OBJ_HW_MONOTONIC; master_template_size = sizeof (OBJ_HW_MONOTONIC); break; default: /* Unsupported. */ break; } break; case CKO_DATA: /* Objects of this class have no subtype. */ master_template = (generic_attr_t *)OBJ_DATA; master_template_size = sizeof (OBJ_DATA); break; case CKO_CERTIFICATE: switch (subtype) { case CKC_X_509: master_template = (generic_attr_t *)OBJ_CERT_X509; master_template_size = sizeof (OBJ_CERT_X509); break; case CKC_X_509_ATTR_CERT: master_template = (generic_attr_t *)OBJ_CERT_X509ATTR; master_template_size = sizeof (OBJ_CERT_X509ATTR); break; default: /* Unsupported. */ break; } break; case CKO_PUBLIC_KEY: switch (subtype) { case CKK_RSA: master_template = (generic_attr_t *)OBJ_PUBKEY_RSA; master_template_size = sizeof (OBJ_PUBKEY_RSA); break; case CKK_DSA: master_template = (generic_attr_t *)OBJ_PUBKEY_DSA; master_template_size = sizeof (OBJ_PUBKEY_DSA); break; case CKK_EC: master_template = (generic_attr_t *)OBJ_PUBKEY_EC; master_template_size = sizeof (OBJ_PUBKEY_EC); break; case CKK_DH: master_template = (generic_attr_t *)OBJ_PUBKEY_DH; master_template_size = sizeof (OBJ_PUBKEY_DH); break; case CKK_X9_42_DH: master_template = (generic_attr_t *)OBJ_PUBKEY_X942DH; master_template_size = sizeof (OBJ_PUBKEY_X942DH); break; case CKK_KEA: master_template = (generic_attr_t *)OBJ_PUBKEY_KEA; master_template_size = sizeof (OBJ_PUBKEY_KEA); break; default: /* Unsupported. */ break; } break; case CKO_PRIVATE_KEY: switch (subtype) { case CKK_RSA: master_template = (generic_attr_t *)OBJ_PRIVKEY_RSA; master_template_size = sizeof (OBJ_PRIVKEY_RSA); break; case CKK_DSA: master_template = (generic_attr_t *)OBJ_PRIVKEY_DSA; master_template_size = sizeof (OBJ_PRIVKEY_DSA); break; case CKK_EC: master_template = (generic_attr_t *)OBJ_PRIVKEY_EC; master_template_size = sizeof (OBJ_PRIVKEY_EC); break; case CKK_DH: master_template = (generic_attr_t *)OBJ_PRIVKEY_DH; master_template_size = sizeof (OBJ_PRIVKEY_DH); break; case CKK_X9_42_DH: master_template = (generic_attr_t *)OBJ_PRIVKEY_X942DH; master_template_size = sizeof (OBJ_PRIVKEY_X942DH); break; case CKK_KEA: master_template = (generic_attr_t *)OBJ_PRIVKEY_KEA; master_template_size = sizeof (OBJ_PRIVKEY_KEA); break; default: /* Unsupported. */ break; } break; case CKO_SECRET_KEY: /* * The only difference between secret keys is that some * are valiable length (eg CKK_AES), while others are not * (eg CKK_DES) -- and do not have a CKA_VALUE_LEN attribute. * * FUTURE(?): Consider using obj_seckey_withlen for unknown * keytypes. This is the most likely choice, as new algorithms * seem to support variable length keys. That's not the default * now, because if people have implemented new key types with * different attribute sets (like the mess of public/private * key types), then incorrect behaviour would result. It's * easier to relax this restriction than to tighten it (which * would introduce a regression to anyone relying on this * working for unknown key types). * */ switch (subtype) { case CKK_DES: case CKK_DES2: case CKK_DES3: case CKK_IDEA: case CKK_CDMF: case CKK_SKIPJACK: case CKK_BATON: case CKK_JUNIPER: master_template = (generic_attr_t *)OBJ_SECKEY; master_template_size = sizeof (OBJ_SECKEY); break; case CKK_GENERIC_SECRET: case CKK_RC2: case CKK_RC4: case CKK_RC5: case CKK_AES: case CKK_BLOWFISH: case CKK_CAST: case CKK_CAST3: case CKK_CAST128: master_template = (generic_attr_t *)OBJ_SECKEY_WITHLEN; master_template_size = sizeof (OBJ_SECKEY_WITHLEN); break; default: /* Unsupported. */ break; } break; case CKO_DOMAIN_PARAMETERS: switch (subtype) { case CKK_DSA: master_template = (generic_attr_t *)OBJ_DOM_DSA; master_template_size = sizeof (OBJ_DOM_DSA); break; case CKK_DH: master_template = (generic_attr_t *)OBJ_DOM_DH; master_template_size = sizeof (OBJ_DOM_DH); break; case CKK_X9_42_DH: master_template = (generic_attr_t *)OBJ_DOM_X942DH; master_template_size = sizeof (OBJ_DOM_X942DH); break; default: /* Unsupported. */ break; } break; default: /* Unsupported. */ break; } /* Requested object is unknown or invalid. */ if (master_template == NULL) return (CKR_ATTRIBUTE_VALUE_INVALID); else { *attributes = master_template; *num_attributes = master_template_size; return (CKR_OK); } } /* * get_master_attributes_by_type * * Returns an (statically allocated) set of object attributes, as determined by * the specified class and subtype. The attributes are initialized to default * values. */ CK_RV get_master_attributes_by_type(CK_OBJECT_CLASS class, CK_ULONG subtype, generic_attr_t **attributes, size_t *num_attributes) { CK_RV rv; generic_attr_t *master_template = NULL; generic_attr_t *new_attributes; size_t i, num_new_attributes, master_template_size = 0; /* Determine the appropriate master template needed. */ rv = get_master_template_by_type(class, subtype, &master_template, &master_template_size); if (rv != CKR_OK) return (rv); /* Duplicate the master template. */ new_attributes = malloc(master_template_size); if (new_attributes == NULL) return (CKR_HOST_MEMORY); (void) memcpy(new_attributes, master_template, master_template_size); num_new_attributes = master_template_size / sizeof (generic_attr_t); /* Set the pointer in the appropriate storage area. */ for (i = 0; i < num_new_attributes; i++) { generic_attr_t *attr; attr = new_attributes + i; switch (attr->attribute.ulValueLen) { case (sizeof (CK_ULONG)): attr->attribute.pValue = &attr->generic_ulong; break; case (sizeof (CK_BBOOL)): attr->attribute.pValue = &attr->generic_bbool; break; default: attr->attribute.pValue = attr->generic_data; break; } } /* Secret keys share a common template, so set the key type here. */ if (class == CKO_SECRET_KEY) { /* Keytype / subtype is always the second attribute. */ new_attributes[1].generic_ulong = subtype; } *attributes = new_attributes; *num_attributes = num_new_attributes; return (CKR_OK); } /* * get_master_attributes_by_duplication * * Returns an (statically allocated) set of object attributes, as copied from an * existing set of attributes. The new attributes inherit the values from * the old attributes. */ CK_RV get_master_attributes_by_duplication( generic_attr_t *src_attrs, size_t num_src_attrs, generic_attr_t **dst_attrs, size_t *num_dst_attrs) { CK_RV rv = CKR_OK; generic_attr_t *new_attrs, *src, *dst; size_t i; new_attrs = malloc(sizeof (generic_attr_t) * num_src_attrs); if (new_attrs == NULL) return (CKR_HOST_MEMORY); for (i = 0; i < num_src_attrs; i++) { src = src_attrs + i; dst = new_attrs + i; *dst = *src; /* Adjust pointers in dst so that they don't point to src. */ if (src->isMalloced) { dst->attribute.pValue = malloc(src->attribute.ulValueLen); if (dst->attribute.pValue == NULL) { /* * Continue on error, so that the cleanup * routine doesn't see pointers to src_attrs. */ dst->attribute.ulValueLen = 0; rv = CKR_HOST_MEMORY; continue; } } else if (src->attribute.pValue == &src->generic_bbool) { dst->attribute.pValue = &dst->generic_bbool; } else if (src->attribute.pValue == &src->generic_ulong) { dst->attribute.pValue = &dst->generic_ulong; } else if (src->attribute.pValue == &src->generic_data) { dst->attribute.pValue = &dst->generic_data; } else { /* This shouldn't happen. */ dst->attribute.pValue = NULL; dst->attribute.ulValueLen = 0; rv = CKR_GENERAL_ERROR; num_src_attrs = i + 1; break; } (void) memcpy(dst->attribute.pValue, src->attribute.pValue, src->attribute.ulValueLen); } if (rv != CKR_OK) { dealloc_attributes(new_attrs, num_src_attrs); } else { *dst_attrs = new_attrs; *num_dst_attrs = num_src_attrs; } return (rv); } /* * dealloc_attributes * * Deallocates the storage used for a set of attributes. The attribute * values are zeroed out before being free'd. */ void dealloc_attributes(generic_attr_t *attributes, size_t num_attributes) { size_t i; generic_attr_t *attr; for (i = 0; i < num_attributes; i++) { attr = attributes + i; /* * Zero-out any attribute values. We could do this just for * attributes with isSensitive == True, but it's not much * extra work to just do them all. [Most attributes are just * 1 or 4 bytes] */ explicit_bzero(attr->attribute.pValue, attr->attribute.ulValueLen); if (attr->isMalloced) free(attr->attribute.pValue); } free(attributes); } /* * attribute_set_value * * Sets the value of the specified attribute. Any portion of the old value * which will not be overwritten by the new value is zeroed out. */ CK_RV attribute_set_value(CK_ATTRIBUTE *new_attr, generic_attr_t *attributes, size_t num_attributes) { generic_attr_t *attr = NULL; if (new_attr == NULL) return (CKR_TEMPLATE_INCOMPLETE); else if (new_attr->pValue == NULL) { return (CKR_ATTRIBUTE_VALUE_INVALID); } find_attribute(new_attr->type, attributes, num_attributes, &attr); if (attr == NULL) { return (CKR_ATTRIBUTE_TYPE_INVALID); } /* Store the new value. */ if (attr->attribute.ulValueLen >= new_attr->ulValueLen) { /* Existing storage is sufficient to store new value. */ /* bzero() out any data that won't be overwritten. */ explicit_bzero((char *)attr->attribute.pValue + new_attr->ulValueLen, attr->attribute.ulValueLen - new_attr->ulValueLen); } else if (new_attr->ulValueLen <= sizeof (attr->generic_data)) { /* Use generic storage to avoid a malloc. */ explicit_bzero(attr->attribute.pValue, attr->attribute.ulValueLen); if (attr->isMalloced) { /* * If app sets a large value (triggering a malloc), * then sets a tiny value, and finally again sets * a large value (phew!) we could end up here. * * FUTURE?: Store the original malloc size, so that * we can regrow the value up to the original size. * This might avoid some heap churn for pathalogic * applications. */ free(attr->attribute.pValue); attr->isMalloced = B_FALSE; } attr->attribute.pValue = attr->generic_data; } else { /* Need to allocate storage for the new value. */ void *newStorage; newStorage = malloc(new_attr->ulValueLen); if (newStorage == NULL) return (CKR_HOST_MEMORY); bzero(attr->attribute.pValue, attr->attribute.ulValueLen); attr->attribute.pValue = newStorage; attr->isMalloced = B_TRUE; } (void) memcpy(attr->attribute.pValue, new_attr->pValue, new_attr->ulValueLen); attr->attribute.ulValueLen = new_attr->ulValueLen; attr->hasValueForClone = B_TRUE; return (CKR_OK); } /* * find_attribute * * Passes a pointer to the requested attribute, or NULL if not found. */ static void find_attribute(CK_ATTRIBUTE_TYPE attrtype, generic_attr_t *attributes, size_t num_attributes, generic_attr_t **found_attribute) { generic_attr_t *attr; boolean_t found = B_FALSE; size_t i; /* Find the requested attribute. */ for (i = 0, attr = attributes; i < num_attributes; i++, attr++) { if (attr->attribute.type == attrtype) { found = B_TRUE; break; } } *found_attribute = found ? attr : NULL; } /* * get_template_ulong * * Look for the specified ulong-size attribute, and retrieve its value. The * return value specifies if the attribute was found (or not). */ boolean_t get_template_ulong(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *attributes, CK_ULONG num_attributes, CK_ULONG *result) { boolean_t found = B_FALSE; CK_ULONG i; for (i = 0; i < num_attributes; i++) { if (attributes[i].type == type) { CK_ULONG *value = attributes[i].pValue; *result = *value; found = B_TRUE; break; } } return (found); } /* * get_template_boolean * * Look for the specified boolean attribute, and retrieve its value. The * return value specifies if the attribute was found (or not). */ boolean_t get_template_boolean(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *attributes, CK_ULONG num_attributes, boolean_t *result) { boolean_t found = B_FALSE; CK_ULONG i; for (i = 0; i < num_attributes; i++) { if (attributes[i].type == type) { CK_BBOOL *value = attributes[i].pValue; if (*value == CK_FALSE) *result = B_FALSE; else *result = B_TRUE; found = B_TRUE; break; } } return (found); } /* * set_template_boolean * * Look for the specified boolean attribute, and set its value. * * if 'local' is true, it sets the pointer to the value in the template a new * location. There should be no memory leak created by this because we are * only doing this to booleans which should not be malloc'ed. * * if 'local' is false, it sets its value. * * The return value specifies if the attribute was found (or not). */ int set_template_boolean(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *attributes, CK_ULONG num_attributes, boolean_t local, CK_BBOOL *value) { int i; for (i = 0; i < num_attributes; i++) { if (attributes[i].type == type) { if (local) attributes[i].pValue = value; else *((CK_BBOOL *)attributes[i].pValue) = *value; return (i); } } return (-1); } /* * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _META_ATTRMASTERS_H #define _META_ATTRMASTERS_H #ifdef __cplusplus extern "C" { #endif /* * Master object templates * * [This file should only be included by a single source file. This is a * non-traditional header file in that it simply contains a bunch of large, * preinitialized static const structures. They're stored here to keep them * "out of the way."] * * In PKCS#11, each object is well-defined... Each object type has an exact * set of attributes, and each attribute always has some value. Some * attribute values must be specificed when the object is created, others * are optional (ie, a default value exisits). Thus, the template an * application provides when creating a new object may be a subset of the * allowed attributes. The "master" templates presented here, however, * are complete. */ /* * Aliases for some field values in generic_attr_t, so that the initialization * below isn't just a confusing mess of B_TRUE and B_FALSE. Lint * complaints about using "!Foo" in const initializers, * so we #define each value. */ #define unused 0 #define Mallocd B_TRUE #define Clone B_TRUE #define EmptyValue B_TRUE #define NotMallocd B_FALSE #define NotClone B_FALSE #define NotEmptyValue B_FALSE #define EMPTYDATE ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' #define EMPTY '\0' /* * A note regarding CKA_CLASS and sub-type (eg CKA_KEY_TYPE) * * These two attributes have been moved to the top of the master template * definitions. All the metaslot code assumes that CKA_CLASS resides in index=0, * and the sub-type resides in index=1. */ /* * Common storage object attributes, Table 19 (p81) of PKCS#11 2.11r1 spec. */ #define COMMON_STORAGE_ATTRIBUTES \ { { CKA_TOKEN, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_FALSE, unused, { unused } }, \ { { CKA_PRIVATE, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_FALSE, unused, { unused } }, \ { { CKA_MODIFIABLE, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_TRUE, unused, { unused } }, \ { { CKA_LABEL, NULL, 0 }, \ NotMallocd, Clone, EmptyValue, B_FALSE, \ unused, unused, { EMPTY } } /* * Common certificate attributes, Table 21 (p83) of PKCS#11 2.11r1 spec. * (CKA_CERTIFICATE_TYPE has been moved, to place at top of template) * */ #define COMMON_CERTIFICATE_ATTRIBUTES \ { { CKA_TRUSTED, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, NotClone, NotEmptyValue, B_FALSE, \ CK_FALSE, unused, { unused } } /* * Common key attributes, Table 25 (p89) of PKCS#11 2.11r1 spec. * (CKA_KEY_TYPE has been moved, to place at top of template) * */ #define COMMON_KEY_ATTRIBUTES \ { { CKA_ID, NULL, 0 }, \ NotMallocd, Clone, EmptyValue, B_FALSE, \ unused, unused, { EMPTY } }, \ { { CKA_START_DATE, NULL, sizeof (CK_DATE) }, \ NotMallocd, Clone, EmptyValue, B_FALSE, \ unused, unused, { EMPTYDATE } }, \ { { CKA_END_DATE, NULL, sizeof (CK_DATE) }, \ NotMallocd, Clone, EmptyValue, B_FALSE, \ unused, unused, { EMPTYDATE } }, \ { { CKA_DERIVE, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_FALSE, unused, { unused } }, \ { { CKA_LOCAL, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, NotClone, NotEmptyValue, B_FALSE, \ CK_FALSE, unused, { unused } }, \ { { CKA_KEY_GEN_MECHANISM, NULL, sizeof (CK_MECHANISM_TYPE) }, \ NotMallocd, NotClone, EmptyValue, B_FALSE, \ unused, CK_UNAVAILABLE_INFORMATION, { unused } } /* * Common public-key attributes, Table 26 (p90) of PKCS#11 2.11r1 spec. * * CKA_SUBJECT has the PKCS#11-specified default. The object-usage attributes * are token-specific defaults. * */ #define COMMON_PUBKEY_ATTRIBUTES \ { { CKA_SUBJECT, NULL, 0 }, \ NotMallocd, Clone, EmptyValue, B_FALSE, \ unused, unused, { EMPTY } }, \ { { CKA_ENCRYPT, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_TRUE, unused, { unused } }, \ { { CKA_VERIFY, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_TRUE, unused, { unused } }, \ { { CKA_VERIFY_RECOVER, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_TRUE, unused, { unused } }, \ { { CKA_WRAP, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_TRUE, unused, { unused } }, \ { { CKA_TRUSTED, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, NotClone, NotEmptyValue, B_FALSE, \ CK_FALSE, unused, { unused } } /* * Common private-key attributes, Table 34 (p97) of PKCS#11 2.11r1 spec. */ #define COMMON_PRIVKEY_ATTRIBUTES \ { { CKA_SUBJECT, NULL, 0 }, \ NotMallocd, Clone, EmptyValue, B_FALSE, \ unused, unused, { EMPTY } }, \ { { CKA_SENSITIVE, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_FALSE, unused, { unused } }, \ { { CKA_SECONDARY_AUTH, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, EmptyValue, B_FALSE, \ CK_FALSE, unused, { unused } }, \ { { CKA_DECRYPT, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_TRUE, unused, { unused } }, \ { { CKA_SIGN, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_TRUE, unused, { unused } }, \ { { CKA_SIGN_RECOVER, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_TRUE, unused, { unused } }, \ { { CKA_UNWRAP, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_TRUE, unused, { unused } }, \ { { CKA_EXTRACTABLE, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_TRUE, unused, { unused } }, \ { { CKA_ALWAYS_SENSITIVE, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, NotClone, NotEmptyValue, B_FALSE, \ CK_FALSE, unused, { unused } }, \ { { CKA_NEVER_EXTRACTABLE, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, NotClone, NotEmptyValue, B_FALSE, \ CK_FALSE, unused, { unused } } /* * Common secret-key attributes, Table 42 (p108) of PKCS#11 2.11r1 spec. */ #define COMMON_SECKEY_ATTRIBUTES \ { { CKA_SENSITIVE, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_FALSE, unused, { unused } }, \ { { CKA_ENCRYPT, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_TRUE, unused, { unused } }, \ { { CKA_DECRYPT, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_TRUE, unused, { unused } }, \ { { CKA_SIGN, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_TRUE, unused, { unused } }, \ { { CKA_VERIFY, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_TRUE, unused, { unused } }, \ { { CKA_WRAP, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_TRUE, unused, { unused } }, \ { { CKA_UNWRAP, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_TRUE, unused, { unused } }, \ { { CKA_EXTRACTABLE, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_TRUE, unused, { unused } }, \ { { CKA_ALWAYS_SENSITIVE, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, NotClone, NotEmptyValue, B_FALSE, \ CK_FALSE, unused, { unused } }, \ { { CKA_NEVER_EXTRACTABLE, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, NotClone, NotEmptyValue, B_FALSE, \ CK_FALSE, unused, { unused } } /* * Common domain-paramaters attributes, Table 60 (p123) of PKCS#11 2.11r1 spec. * (CKA_KEY_TYPE has been removed, to place elsewhere) */ #define COMMON_DOMAIN_ATTRIBUTES \ { { CKA_LOCAL, NULL, sizeof (CK_BBOOL) }, \ NotMallocd, Clone, NotEmptyValue, B_FALSE, \ CK_FALSE, unused, { unused } } /* ========================= HW Objects ========================= */ /* * Master template for: CKO_HW_FEATURE + CKH_CLOCK */ static const generic_attr_t OBJ_HW_CLOCK[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_HW_FEATURE, { unused } }, { { CKA_HW_FEATURE_TYPE, NULL, sizeof (CK_HW_FEATURE_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKH_CLOCK, { unused } }, { { CKA_VALUE, NULL, 16 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTYDATE, EMPTYDATE } } }; /* * Master template for: CKO_HW_FEATURE + CKH_MONOTONIC_COUNTER * * NOTE: no sub-type for this class! */ static const generic_attr_t OBJ_HW_MONOTONIC[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_HW_FEATURE, { unused } }, { { CKA_HW_FEATURE_TYPE, NULL, sizeof (CK_HW_FEATURE_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKH_MONOTONIC_COUNTER, { unused } }, { { CKA_VALUE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_RESET_ON_INIT, NULL, sizeof (CK_BBOOL) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, CK_FALSE, unused, { unused } }, { { CKA_HAS_RESET, NULL, sizeof (CK_BBOOL) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, CK_FALSE, unused, { unused } } }; /* ========================= Data Objects ========================= */ /* * Master template for CKO_DATA + (no subtypes for this class) * * Defaults are according to PKCS#11. * * NOTE: no sub-type for this class! */ static const generic_attr_t OBJ_DATA[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_DATA, { unused } }, COMMON_STORAGE_ATTRIBUTES, { { CKA_APPLICATION, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_OBJECT_ID, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_VALUE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } } }; /* ========================= Certificate Objects ========================= */ /* * Master template for CKO_CERTIFICATE + CKC_X_509 * * Defaults are according to PKCS#11. */ static const generic_attr_t OBJ_CERT_X509[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_CERTIFICATE, { unused } }, { { CKA_CERTIFICATE_TYPE, NULL, sizeof (CK_CERTIFICATE_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKC_X_509, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_CERTIFICATE_ATTRIBUTES, { { CKA_SUBJECT, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_ID, NULL, 0 }, NotMallocd, Clone, EmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_ISSUER, NULL, 0 }, NotMallocd, Clone, EmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_SERIAL_NUMBER, NULL, 0 }, NotMallocd, Clone, EmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_VALUE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } } }; /* * Master template for CKO_CERTIFICATE + CKC_X_509_ATTR_CERT * * Defaults are according to PKCS#11. */ static const generic_attr_t OBJ_CERT_X509ATTR[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_CERTIFICATE, { unused } }, { { CKA_CERTIFICATE_TYPE, NULL, sizeof (CK_CERTIFICATE_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKC_X_509_ATTR_CERT, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_CERTIFICATE_ATTRIBUTES, { { CKA_OWNER, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_AC_ISSUER, NULL, 0 }, NotMallocd, Clone, EmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_SERIAL_NUMBER, NULL, 0 }, NotMallocd, Clone, EmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_ATTR_TYPES, NULL, 0 }, NotMallocd, Clone, EmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_VALUE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } } }; /* ========================= Public Keys ========================= */ /* * Master template for CKO_PUBLIC_KEY + CKK_RSA */ static const generic_attr_t OBJ_PUBKEY_RSA[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_PUBLIC_KEY, { unused } }, { { CKA_KEY_TYPE, NULL, sizeof (CK_KEY_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKK_RSA, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_KEY_ATTRIBUTES, COMMON_PUBKEY_ATTRIBUTES, { { CKA_MODULUS, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_MODULUS_BITS, NULL, sizeof (CK_ULONG)}, NotMallocd, NotClone, NotEmptyValue, B_FALSE, unused, 0, { unused } }, { { CKA_PUBLIC_EXPONENT, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } } }; /* * Master template for CKO_PUBLIC_KEY + CKK_DSA * */ static const generic_attr_t OBJ_PUBKEY_DSA[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_PUBLIC_KEY, { unused } }, { { CKA_KEY_TYPE, NULL, sizeof (CK_KEY_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKK_DSA, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_KEY_ATTRIBUTES, COMMON_PUBKEY_ATTRIBUTES, { { CKA_PRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_SUBPRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_BASE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_VALUE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } } }; /* * Master template for CKO_PUBLIC_KEY + CKK_EC * */ static const generic_attr_t OBJ_PUBKEY_EC[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_PUBLIC_KEY, { unused } }, { { CKA_KEY_TYPE, NULL, sizeof (CK_KEY_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKK_EC, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_KEY_ATTRIBUTES, COMMON_PUBKEY_ATTRIBUTES, { { CKA_EC_PARAMS, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_EC_POINT, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } } }; /* * Master template for CKO_PUBLIC_KEY + CKK_DH * */ static const generic_attr_t OBJ_PUBKEY_DH[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_PUBLIC_KEY, { unused } }, { { CKA_KEY_TYPE, NULL, sizeof (CK_KEY_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKK_DH, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_KEY_ATTRIBUTES, COMMON_PUBKEY_ATTRIBUTES, { { CKA_PRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_BASE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_VALUE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } } }; /* * Master template for CKO_PUBLIC_KEY + CKK_X9_42_DH * */ static const generic_attr_t OBJ_PUBKEY_X942DH[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_PUBLIC_KEY, { unused } }, { { CKA_KEY_TYPE, NULL, sizeof (CK_KEY_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKK_X9_42_DH, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_KEY_ATTRIBUTES, COMMON_PUBKEY_ATTRIBUTES, { { CKA_PRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_BASE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_SUBPRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_VALUE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } } }; /* * Master template for CKO_PUBLIC_KEY + CKK_KEA * */ static const generic_attr_t OBJ_PUBKEY_KEA[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_PUBLIC_KEY, { unused } }, { { CKA_KEY_TYPE, NULL, sizeof (CK_KEY_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKK_KEA, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_KEY_ATTRIBUTES, COMMON_PUBKEY_ATTRIBUTES, { { CKA_PRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_BASE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_SUBPRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_VALUE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } } }; /* ========================= Private Keys ========================= */ /* * Master template for CKO_PRIVATE_KEY + CKK_RSA * */ static const generic_attr_t OBJ_PRIVKEY_RSA[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_PRIVATE_KEY, { unused } }, { { CKA_KEY_TYPE, NULL, sizeof (CK_KEY_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKK_RSA, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_KEY_ATTRIBUTES, COMMON_PRIVKEY_ATTRIBUTES, { { CKA_MODULUS, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_PRIVATE_EXPONENT, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_PUBLIC_EXPONENT, NULL, 0 }, NotMallocd, Clone, EmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_PRIME_1, NULL, 0 }, NotMallocd, Clone, EmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_PRIME_2, NULL, 0 }, NotMallocd, Clone, EmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_EXPONENT_1, NULL, 0 }, NotMallocd, Clone, EmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_EXPONENT_2, NULL, 0 }, NotMallocd, Clone, EmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_COEFFICIENT, NULL, 0 }, NotMallocd, Clone, EmptyValue, B_FALSE, unused, unused, { EMPTY } } }; /* * Master template for CKO_PRIVATE_KEY + CKK_DSA * */ static const generic_attr_t OBJ_PRIVKEY_DSA[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_PRIVATE_KEY, { unused } }, { { CKA_KEY_TYPE, NULL, sizeof (CK_KEY_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKK_DSA, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_KEY_ATTRIBUTES, COMMON_PRIVKEY_ATTRIBUTES, { { CKA_PRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_SUBPRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_BASE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_VALUE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } } }; /* * Master template for CKO_PRIVATE_KEY + CKK_EC * */ static const generic_attr_t OBJ_PRIVKEY_EC[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_PRIVATE_KEY, { unused } }, { { CKA_KEY_TYPE, NULL, sizeof (CK_KEY_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKK_EC, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_KEY_ATTRIBUTES, COMMON_PRIVKEY_ATTRIBUTES, { { CKA_EC_PARAMS, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_VALUE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } } }; /* * Master template for CKO_PRIVATE_KEY + CKK_DH */ static const generic_attr_t OBJ_PRIVKEY_DH[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_PRIVATE_KEY, { unused } }, { { CKA_KEY_TYPE, NULL, sizeof (CK_KEY_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKK_DH, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_KEY_ATTRIBUTES, COMMON_PRIVKEY_ATTRIBUTES, { { CKA_PRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_BASE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_VALUE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_VALUE_BITS, NULL, sizeof (CK_ULONG) }, NotMallocd, NotClone, NotEmptyValue, B_FALSE, unused, 0, { unused } } }; /* * Master template for CKO_PRIVATE_KEY + CKK_X9_42_DH * */ static const generic_attr_t OBJ_PRIVKEY_X942DH[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_PRIVATE_KEY, { unused } }, { { CKA_KEY_TYPE, NULL, sizeof (CK_KEY_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKK_X9_42_DH, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_KEY_ATTRIBUTES, COMMON_PRIVKEY_ATTRIBUTES, { { CKA_PRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_SUBPRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_BASE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_VALUE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } } }; /* * Master template for CKO_PRIVATE_KEY + CKK_KEA * */ static const generic_attr_t OBJ_PRIVKEY_KEA[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_PRIVATE_KEY, { unused } }, { { CKA_KEY_TYPE, NULL, sizeof (CK_KEY_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKK_KEA, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_KEY_ATTRIBUTES, COMMON_PRIVKEY_ATTRIBUTES, { { CKA_PRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_BASE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_SUBPRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_VALUE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } } }; /* ========================= Secret Keys ========================= */ /* * Master template for CKO_SECRET_KEY + (fixed-length keytype) */ static const generic_attr_t OBJ_SECKEY[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_SECRET_KEY, { unused } }, { { CKA_KEY_TYPE, NULL, sizeof (CK_KEY_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKK_GENERIC_SECRET, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_KEY_ATTRIBUTES, COMMON_SECKEY_ATTRIBUTES, { { CKA_VALUE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } } }; /* * Master template for CKO_SECRET_KEY + (variable-length keytype) * */ static const generic_attr_t OBJ_SECKEY_WITHLEN[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_SECRET_KEY, { unused } }, { { CKA_KEY_TYPE, NULL, sizeof (CK_KEY_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKK_GENERIC_SECRET, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_KEY_ATTRIBUTES, COMMON_SECKEY_ATTRIBUTES, { { CKA_VALUE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_VALUE_LEN, NULL, sizeof (CK_ULONG) }, NotMallocd, NotClone, NotEmptyValue, B_FALSE, unused, 0, { unused } } }; /* ========================= Domain Parameters ========================= */ /* * Master template for CKO_DOMAIN_PARAMETERS + CKK_DSA * */ static const generic_attr_t OBJ_DOM_DSA[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_DOMAIN_PARAMETERS, { unused } }, { { CKA_KEY_TYPE, NULL, sizeof (CK_KEY_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKK_DSA, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_DOMAIN_ATTRIBUTES, { { CKA_PRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_SUBPRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_BASE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_PRIME_BITS, NULL, sizeof (CK_ULONG) }, NotMallocd, NotClone, NotEmptyValue, B_FALSE, unused, 0, { unused } } }; /* * Master template for CKO_DOMAIN_PARAMETERS + CKK_DH * */ static const generic_attr_t OBJ_DOM_DH[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_DOMAIN_PARAMETERS, { unused } }, { { CKA_KEY_TYPE, NULL, sizeof (CK_KEY_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKK_DH, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_DOMAIN_ATTRIBUTES, { { CKA_PRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_BASE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_PRIME_BITS, NULL, sizeof (CK_ULONG) }, NotMallocd, NotClone, NotEmptyValue, B_FALSE, unused, 0, { unused } } }; /* * Master template for CKO_DOMAIN_PARAMETERS + CKK_X9_42_DH * */ static const generic_attr_t OBJ_DOM_X942DH[] = { { { CKA_CLASS, NULL, sizeof (CK_OBJECT_CLASS) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKO_DOMAIN_PARAMETERS, { unused } }, { { CKA_KEY_TYPE, NULL, sizeof (CK_KEY_TYPE) }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, CKK_X9_42_DH, { unused } }, COMMON_STORAGE_ATTRIBUTES, COMMON_DOMAIN_ATTRIBUTES, { { CKA_PRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_BASE, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_SUBPRIME, NULL, 0 }, NotMallocd, Clone, NotEmptyValue, B_FALSE, unused, unused, { EMPTY } }, { { CKA_PRIME_BITS, NULL, sizeof (CK_ULONG) }, NotMallocd, NotClone, NotEmptyValue, B_FALSE, unused, 0, { unused } }, { { CKA_SUBPRIME_BITS, NULL, sizeof (CK_ULONG) }, NotMallocd, NotClone, NotEmptyValue, B_FALSE, unused, 0, { unused } } }; #ifdef __cplusplus } #endif #endif /* _META_ATTRMASTERS_H */ /* * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2018, Joyent, Inc. */ /* * Encryption and Decryption Functions * (as defined in PKCS#11 spec sections 11.8 and 11.9) */ #include "metaGlobal.h" /* * meta_EncryptInit * */ CK_RV meta_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { CK_RV rv; meta_session_t *session; meta_object_t *key; if (pMechanism == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_handle2object(hKey, &key); if (rv != CKR_OK) { REFRELEASE(session); return (rv); } rv = meta_operation_init_defer(CKF_ENCRYPT, session, pMechanism, key); OBJRELEASE(key); REFRELEASE(session); return (rv); } /* * meta_Encrypt * */ CK_RV meta_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) { CK_RV rv; meta_session_t *session; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); if (pulEncryptedDataLen == NULL) { meta_operation_cleanup(session, CKF_ENCRYPT, FALSE); REFRELEASE(session); return (CKR_ARGUMENTS_BAD); } /* * Allow pData to be NULL as long as the length is 0 in order to * support ciphers that permit 0 byte inputs (e.g. combined mode * ciphers), otherwise consider pData being NULL as invalid. */ if (pData == NULL && ulDataLen != 0) { meta_operation_cleanup(session, CKF_ENCRYPT, FALSE); REFRELEASE(session); return (CKR_ARGUMENTS_BAD); } rv = meta_do_operation(CKF_ENCRYPT, MODE_SINGLE, session, NULL, pData, ulDataLen, pEncryptedData, pulEncryptedDataLen); REFRELEASE(session); return (rv); } /* * meta_EncryptUpdate * */ CK_RV meta_EncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen) { CK_RV rv; meta_session_t *session; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); if (pPart == NULL || pulEncryptedPartLen == NULL) { meta_operation_cleanup(session, CKF_ENCRYPT, FALSE); REFRELEASE(session); return (CKR_ARGUMENTS_BAD); } rv = meta_do_operation(CKF_ENCRYPT, MODE_UPDATE, session, NULL, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen); REFRELEASE(session); return (rv); } /* * meta_EncryptFinal * */ CK_RV meta_EncryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pulLastEncryptedPartLen) { CK_RV rv; meta_session_t *session; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); if (pulLastEncryptedPartLen == NULL) { meta_operation_cleanup(session, CKF_ENCRYPT, FALSE); REFRELEASE(session); return (CKR_ARGUMENTS_BAD); } rv = meta_do_operation(CKF_ENCRYPT, MODE_FINAL, session, NULL, NULL, 0, pLastEncryptedPart, pulLastEncryptedPartLen); REFRELEASE(session); return (rv); } /* * meta_DecryptInit * */ CK_RV meta_DecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { CK_RV rv; meta_session_t *session; meta_object_t *key; if (pMechanism == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_handle2object(hKey, &key); if (rv != CKR_OK) { REFRELEASE(session); return (rv); } rv = meta_operation_init_defer(CKF_DECRYPT, session, pMechanism, key); OBJRELEASE(key); REFRELEASE(session); return (rv); } /* * meta_Decrypt * */ CK_RV meta_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { CK_RV rv; meta_session_t *session; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); if (pEncryptedData == NULL || pulDataLen == NULL) { meta_operation_cleanup(session, CKF_DECRYPT, FALSE); REFRELEASE(session); return (CKR_ARGUMENTS_BAD); } rv = meta_do_operation(CKF_DECRYPT, MODE_SINGLE, session, NULL, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); REFRELEASE(session); return (rv); } /* * meta_DecryptUpdate * */ CK_RV meta_DecryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) { CK_RV rv; meta_session_t *session; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); if (pEncryptedPart == NULL || pulPartLen == NULL) { meta_operation_cleanup(session, CKF_DECRYPT, FALSE); REFRELEASE(session); return (CKR_ARGUMENTS_BAD); } rv = meta_do_operation(CKF_DECRYPT, MODE_UPDATE, session, NULL, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); REFRELEASE(session); return (rv); } /* * meta_DecryptFinal * */ CK_RV meta_DecryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen) { CK_RV rv; meta_session_t *session; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); if (pulLastPartLen == NULL) { meta_operation_cleanup(session, CKF_DECRYPT, FALSE); REFRELEASE(session); return (CKR_ARGUMENTS_BAD); } rv = meta_do_operation(CKF_DECRYPT, MODE_FINAL, session, NULL, NULL, 0, pLastPart, pulLastPartLen); REFRELEASE(session); return (rv); } /* * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2018, Joyent, Inc. */ /* * Message Digesting Functions * (as defined in PKCS#11 spec section 11.10) */ #include "metaGlobal.h" /* * meta_DigestInit * */ CK_RV meta_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) { CK_RV rv; meta_session_t *session; if (pMechanism == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_operation_init_defer(CKF_DIGEST, session, pMechanism, NULL); REFRELEASE(session); return (rv); } /* * meta_Digest * */ CK_RV meta_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) { CK_RV rv; meta_session_t *session; if ((pData == NULL && ulDataLen != 0) || pulDigestLen == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_do_operation(CKF_DIGEST, MODE_SINGLE, session, NULL, pData, ulDataLen, pDigest, pulDigestLen); REFRELEASE(session); return (rv); } /* * meta_DigestUpdate * */ CK_RV meta_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { CK_RV rv; meta_session_t *session; if (pPart == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_do_operation(CKF_DIGEST, MODE_UPDATE, session, NULL, pPart, ulPartLen, NULL, NULL); REFRELEASE(session); return (rv); } /* * meta_DigestKey * * NOTE: This function can fail under certain circumstances! * Unlike the other crypto functions, we didn't get the key object * when the operation was initialized with C_DigestInit(). * Thus, the slot we're using for the digest operation may * not be the slot containing the key -- if the key is extractible we can * deal with it, but if it's not the operation will FAIL. */ CK_RV meta_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) { CK_RV rv; meta_session_t *session; meta_object_t *key; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_handle2object(hKey, &key); if (rv != CKR_OK) { REFRELEASE(session); return (rv); } /* meta_do_operation() will clone the key, if needed. */ rv = meta_do_operation(CKF_DIGEST, MODE_UPDATE_WITHKEY, session, key, NULL, 0, NULL, NULL); OBJRELEASE(key); REFRELEASE(session); return (rv); } /* * meta_DigestFinal * */ CK_RV meta_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) { CK_RV rv; meta_session_t *session; if (pulDigestLen == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_do_operation(CKF_DIGEST, MODE_FINAL, session, NULL, NULL, 0, pDigest, pulDigestLen); REFRELEASE(session); return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Dual-Function Cryptographic Functions * (as defined in PKCS#11 spec section 11.13) * * These functions will not be supported in the this release. * A call to these functions returns CKR_FUNCTION_NOT_SUPPORTED. * * Providing the support for dual-function crypto functions is * not trivial. C_FooInit() need to be called for the 2 crypto * operations before any of these function can be called. * When C_FooInit() is called, metaslot doesn't know if it is going * to do dual-function crypto or single crypto operation. * So, it has no way to pick the slot that supports both the mechanism * it specified and supports dual-functions. * * In order for these dual functions to be supported in the future, * metaslot need to simulate the dual-function crypto operations * when both operations are not lucky enough be to initialized in * the same slots that supports dual-functions. */ #include "metaGlobal.h" /* * meta_DigestEncryptUpdate * */ /*ARGSUSED*/ CK_RV meta_DigestEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen) { return (CKR_FUNCTION_NOT_SUPPORTED); } /* * meta_DecryptDigestUpdate * */ /*ARGSUSED*/ CK_RV meta_DecryptDigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) { return (CKR_FUNCTION_NOT_SUPPORTED); } /* * meta_SignEncryptUpdate * */ /*ARGSUSED*/ CK_RV meta_SignEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen) { return (CKR_FUNCTION_NOT_SUPPORTED); } /* * meta_DecryptVerifyUpdate * */ /*ARGSUSED*/ CK_RV meta_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) { return (CKR_FUNCTION_NOT_SUPPORTED); } /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved. */ /* * General-Purpose Functions * (as defined in PKCS#11 spec section 11.4) */ #include #include #include #include "metaGlobal.h" extern meta_session_t *meta_sessionlist_head; struct CK_FUNCTION_LIST metaslot_functionList = { { 2, 20 }, /* version */ meta_Initialize, meta_Finalize, meta_GetInfo, meta_GetFunctionList, meta_GetSlotList, meta_GetSlotInfo, meta_GetTokenInfo, meta_GetMechanismList, meta_GetMechanismInfo, meta_InitToken, meta_InitPIN, meta_SetPIN, meta_OpenSession, meta_CloseSession, meta_CloseAllSessions, meta_GetSessionInfo, meta_GetOperationState, meta_SetOperationState, meta_Login, meta_Logout, meta_CreateObject, meta_CopyObject, meta_DestroyObject, meta_GetObjectSize, meta_GetAttributeValue, meta_SetAttributeValue, meta_FindObjectsInit, meta_FindObjects, meta_FindObjectsFinal, meta_EncryptInit, meta_Encrypt, meta_EncryptUpdate, meta_EncryptFinal, meta_DecryptInit, meta_Decrypt, meta_DecryptUpdate, meta_DecryptFinal, meta_DigestInit, meta_Digest, meta_DigestUpdate, meta_DigestKey, meta_DigestFinal, meta_SignInit, meta_Sign, meta_SignUpdate, meta_SignFinal, meta_SignRecoverInit, meta_SignRecover, meta_VerifyInit, meta_Verify, meta_VerifyUpdate, meta_VerifyFinal, meta_VerifyRecoverInit, meta_VerifyRecover, meta_DigestEncryptUpdate, meta_DecryptDigestUpdate, meta_SignEncryptUpdate, meta_DecryptVerifyUpdate, meta_GenerateKey, meta_GenerateKeyPair, meta_WrapKey, meta_UnwrapKey, meta_DeriveKey, meta_SeedRandom, meta_GenerateRandom, meta_GetFunctionStatus, meta_CancelFunction, meta_WaitForSlotEvent }; pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER; ses_to_be_freed_list_t ses_delay_freed; object_to_be_freed_list_t obj_delay_freed; /* * meta_Initialize * * This function is never called by the application. It is only * called by uCF to initialize metaslot. The pInitArgs argument is ignored. * */ /*ARGSUSED*/ CK_RV meta_Initialize(CK_VOID_PTR pInitArgs) { CK_RV rv; /* Make sure function hasn't been called twice */ (void) pthread_mutex_lock(&initmutex); rv = meta_slotManager_initialize(); if (rv != CKR_OK) { (void) pthread_mutex_unlock(&initmutex); return (rv); } rv = meta_mechManager_initialize(); if (rv != CKR_OK) { (void) meta_slotManager_finalize(); (void) pthread_mutex_unlock(&initmutex); return (rv); } rv = meta_objectManager_initialize(); if (rv != CKR_OK) { (void) meta_slotManager_finalize(); (void) meta_mechManager_finalize(); (void) pthread_mutex_unlock(&initmutex); return (rv); } rv = meta_sessionManager_initialize(); if (rv != CKR_OK) { (void) meta_slotManager_finalize(); (void) meta_mechManager_finalize(); (void) meta_objectManager_finalize(); (void) pthread_mutex_unlock(&initmutex); return (rv); } meta_slotManager_find_object_token(); /* Initialize the object_to_be_freed list */ (void) pthread_mutex_init(&obj_delay_freed.obj_to_be_free_mutex, NULL); obj_delay_freed.count = 0; obj_delay_freed.first = NULL; obj_delay_freed.last = NULL; /* Initialize the session_to_be_freed list */ (void) pthread_mutex_init(&ses_delay_freed.ses_to_be_free_mutex, NULL); ses_delay_freed.count = 0; ses_delay_freed.first = NULL; ses_delay_freed.last = NULL; (void) pthread_mutex_unlock(&initmutex); return (CKR_OK); } /* * meta_Finalize * * Called by uCF only, "pReserved" argument is ignored. */ /*ARGSUSED*/ CK_RV meta_Finalize(CK_VOID_PTR pReserved) { CK_RV rv = CKR_OK; meta_object_t *delay_free_obj, *tmpo; meta_session_t *delay_free_ses, *tmps; if (pReserved != NULL) return (CKR_ARGUMENTS_BAD); (void) pthread_mutex_lock(&initmutex); /* * There used to be calls to cleanup libcryptoutil here. Given that * libcryptoutil can be linked and invoked independently of PKCS#11, * cleaning up libcryptoutil here makes no sense. Decoupling these * two also prevent deadlocks and other artificial dependencies. */ meta_objectManager_finalize(); meta_sessionManager_finalize(); meta_mechManager_finalize(); meta_slotManager_finalize(); /* * free all entries in the delay_freed list */ delay_free_obj = obj_delay_freed.first; while (delay_free_obj != NULL) { tmpo = delay_free_obj->next; free(delay_free_obj); delay_free_obj = tmpo; } (void) pthread_mutex_destroy(&obj_delay_freed.obj_to_be_free_mutex); delay_free_ses = ses_delay_freed.first; while (delay_free_ses != NULL) { tmps = delay_free_ses->next; free(delay_free_ses); delay_free_ses = tmps; } (void) pthread_mutex_destroy(&ses_delay_freed.ses_to_be_free_mutex); (void) pthread_mutex_unlock(&initmutex); return (rv); } /* * meta_GetInfo * * NOTE: This function will never be called by applications because it's * hidden behind the uCF C_GetInfo. So, it is not implemented. */ /*ARGSUSED*/ CK_RV meta_GetInfo(CK_INFO_PTR pInfo) { return (CKR_FUNCTION_NOT_SUPPORTED); } /* * meta_GetFunctionList * * This function is not implemented because metaslot is part of the framework, * so, the framework can just do a static assignment to metaslot's * function list instead of calling this function. */ /*ARGSUSED*/ CK_RV meta_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) { return (CKR_FUNCTION_NOT_SUPPORTED); } /* * Parallel Function Management Function * (as defined in PKCS#11 spec section 11.16) */ /* * This function is no longer supported in this revision of the PKCS#11 * standard. It is maintained for backwards compatibility only. */ /* ARGSUSED */ CK_RV meta_GetFunctionStatus(CK_SESSION_HANDLE hSession) { return (CKR_FUNCTION_NOT_PARALLEL); } /* * This function is no longer supported in this revision of the PKCS#11 * standard. It is maintained for backwards compatibility only. */ /* ARGSUSED */ CK_RV meta_CancelFunction(CK_SESSION_HANDLE hSession) { return (CKR_FUNCTION_NOT_PARALLEL); } /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _METAGLOBAL_H #define _METAGLOBAL_H /* * This file contains all the data structures used for the meta slot */ #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include #include #include #include #include /* * In "generic_attr_t", attributes that are not CK_BBOOL and * CK_ULONG, the data will be stored in generic_data. * Currently, 16 bytes will be pre-allocated for this. * This is just a _WILD_ guess. If actual * experience shows that 16 bytes is too small for most of the * data that will be stored here, and cause this * memory to be reallocated all the time, this should be increased. */ #define INITIAL_ATTR_LEN 16 /* We provide one slot, with the following arbitrary identifier. */ #define METASLOT_SLOTID 42 /* Metaslot is always the first slot in the framdwork, with slotID=0 */ #define METASLOT_FRAMEWORK_ID 0 /* * These are the 2 acceptable string values for ${METASLOT_ENABLE} and * ${METASLOT_AUTO_KEY_MIGRATE} environment variable */ #define TRUE_STRING "true" #define FALSE_STRING "false" /* Magic values for different data structures */ #define METASLOT_SESSION_MAGIC 0xECF00004 #define METASLOT_SESSION_BADMAGIC 0xBAD00004 #define METASLOT_OBJECT_MAGIC 0xECF0B004 #define METASLOT_OBJECT_BADMAGIC 0xBAD0B004 #define METASLOT_OPSTATE_MAGIC 0xECF09004 #define METASLOT_OPSTATE_BADMAGIC 0xBAD09004 #define IS_READ_ONLY_SESSION(session_flag) \ (!(session_flag & CKF_RW_SESSION)) /* * Operation modes passed to meta_do_operation() * MODE_UPDATE_WITHKEY is only used for C_DigestKey. */ #define MODE_SINGLE 0x0100 #define MODE_UPDATE 0x0200 #define MODE_UPDATE_WITHKEY 0x0400 #define MODE_FINAL 0x1000 /* CK_INFO: Information about cryptoki */ #define METASLOT_CRYPTOKI_VERSION_MAJOR 2 #define METASLOT_CRYPTOKI_VERSION_MINOR 40 #define METASLOT_MANUFACTURER_ID "Sun Microsystems, Inc. " #define METASLOT_LIBRARY_DESCRIPTION "Sun Metaslot " #define METASLOT_LIBRARY_VERSION_MAJOR 1 #define METASLOT_LIBRARY_VERSION_MINOR 1 /* CK_SLOT_INFO */ #define METASLOT_SLOT_DESCRIPTION "Sun Metaslot " \ " " #define METASLOT_HARDWARE_VERSION_MAJOR 0 #define METASLOT_HARDWARE_VERSION_MINOR 0 #define METASLOT_FIRMWARE_VERSION_MAJOR 0 #define METASLOT_FIRMWARE_VERSION_MINOR 0 /* CK_TOKEN_INFO: More information about token */ #define METASLOT_TOKEN_LABEL "Sun Metaslot " #define METASLOT_TOKEN_MODEL "1.0 " /* * Maximum number of objects and sessions to queue up before actually * freeing them using the free() system. This is necessary to workaround * a problem in which applications re-uses handles that are no longer valid */ #define MAX_OBJ_TO_BE_FREED 300 #define MAX_SESSION_TO_BE_FREED 300 /* * The following 2 functions deals with inserting and deleting * from double linked lists. It can work with any data structure * that have "prev" and "next" defined. */ /* This always inserts into the head of the list */ #define INSERT_INTO_LIST(list, item) \ { \ if ((list) == NULL) { \ (item)->prev = NULL; \ (item)->next = NULL; \ (list) = (item); \ } else { \ (item)->next = (list); \ (item)->prev = NULL; \ (list)->prev = (item); \ (list) = (item); \ } \ } /* * Remove item from list */ #define REMOVE_FROM_LIST(list, item) \ { \ /* item is at the beginning of the list */ \ if ((list) == item) { \ if ((item)->next == NULL) { \ (list) = NULL; \ } else { \ (item)->next->prev = NULL; \ (list) = (item)->next; \ } \ } else { \ /* \ * let the items which are initialized and not \ * connected to the list trip over the asserts \ */ \ if ((item)->next) { \ (item)->next->prev = item->prev; \ assert((item)->prev != NULL); \ (item)->prev->next = (item)->next; \ } else { \ assert((item)->prev != NULL); \ (item)->prev->next = NULL; \ } \ } \ } /* * OBJRELEASE * * Signal that a metaobject is no longer in use (but is still valid). */ #define OBJRELEASE(object) \ if (object != NULL) { \ (void) pthread_rwlock_unlock(&object->object_lock); \ } /* * REFRELEASE * * Signal that a metasession is no longer in use (but is still valid). * */ #define REFRELEASE(session) \ if (session != NULL) { \ (void) pthread_rwlock_unlock(&session->session_lock); \ } /* FreeObject/FreeToken Enumeration */ typedef enum { FREE_UNCHECKED = 0, /* Has not been checked */ FREE_DISABLED = 1, /* No supported provider or key type */ FREE_ALLOWED_KEY = 2, /* Supported key type */ FREE_ENABLED = 3 /* FreeObject/Token enabled */ } freeobject_state_t; /* Generic attribute type, for storing and managing PKCS#11 attributes. */ typedef struct _attr { CK_ATTRIBUTE attribute; boolean_t isMalloced; /* attr is necessary for creating a clone of the object */ boolean_t isCloneAttr; /* * depends on the PKCS#11 implementation, this attr might or might * not have a value. It's OK for it to not have a value * (ie: the default value is empty) */ boolean_t canBeEmptyValue; boolean_t hasValueForClone; CK_BBOOL generic_bbool; CK_ULONG generic_ulong; CK_BYTE generic_data[INITIAL_ATTR_LEN]; } generic_attr_t; /* * These need to be defined here before the actual structures are defined * because they are used in some of the structure definitions. */ typedef struct slotobject slot_object_t; typedef struct metasession meta_session_t; typedef struct metaobject meta_object_t; typedef struct metaopstate meta_opstate_t; /* * slot_session_t * * Wrapper for a session on a provider. This structure is only used internally * in metaslot; it is never revealed to applications. */ typedef struct slotsession { CK_ULONG slotnum; CK_SLOT_ID fw_st_id; /* used for accessing framework's slottable */ CK_SESSION_HANDLE hSession; boolean_t is_dualop_capable; CK_FLAGS session_flags; /* what type of session */ struct slotsession *next; struct slotsession *prev; pthread_rwlock_t object_list_lock; slot_object_t *object_list_head; } slot_session_t; /* * slot_object_t * * Wrapper for an object on a provider. This structure is only used internally * in metaslot; it is never revealed to applications. */ struct slotobject { CK_OBJECT_HANDLE hObject; struct slotobject *next; struct slotobject *prev; slot_session_t *creator_session; boolean_t isToken; }; /* * mechinfo_t * * A mechinfo_t is created for each mechanism on a slot. * * This information is used for selecting which slots support the given * mechanism for a crypto operation. * */ typedef struct mechinfo { CK_ULONG slotnum; boolean_t initialized; boolean_t supported; CK_MECHANISM_INFO mechanism_info; } mechinfo_t; /* * operation_info_t * * Part of a meta_session_t, used to track active operations. */ typedef struct opinfo { CK_FLAGS type; slot_session_t *session; mechinfo_t *stats; } operation_info_t; typedef struct find_objs_info { boolean_t op_active; /* Indicate whether FindObjects is active */ meta_object_t **matched_objs; int num_matched_objs; int next_result_index; /* index of next object to be returned */ } find_objs_info_t; typedef struct mech_support_info { CK_MECHANISM_TYPE mech; /* Array of mechinfo_t allocated based on number of slots */ mechinfo_t **supporting_slots; unsigned long num_supporting_slots; } mech_support_info_t; typedef struct crypto_init { CK_FLAGS optype; /* place holder for init parameters */ struct metasession *session; /* place holder for init parameters */ CK_MECHANISM *pMech; /* place holder for init parameters */ struct metaobject *key; /* place holder for init parameters */ CK_ULONG slotnum; /* slot where the init operation took place */ boolean_t done; /* set when the real init is done */ boolean_t app; /* set when C_xxxInit is called by app */ } crypto_init_t; /* * meta_session_t * * The internal state for a meta-session is kept here. The session handles * given to applications are always pointers to a structure of this type. * */ struct metasession { ulong_t magic_marker; pthread_rwlock_t session_lock; pthread_mutex_t isClosingSession_lock; boolean_t isClosingSession; struct metasession *next; struct metasession *prev; CK_FLAGS session_flags; /* * Could have just declared this as "op", but declaring it as * op1 so that "op2" can be easily added when dual-op support * is implemented in the future */ operation_info_t op1; /* * This is for keeping track of which slots support a particular * mechanism. This information doesn't * have to be kept on a per session bases, but having the * memory pre-allocated per session would make things much simpiler, * because memory doesn't need to be allocated/deallocated everytime * we do an operation. */ mech_support_info_t mech_support_info; /* Session objects created by this session. */ pthread_rwlock_t object_list_lock; meta_object_t *object_list_head; /* C_FindObjects support. */ find_objs_info_t find_objs_info; /* deferred init to be used by digest, encrypt, decrypt */ crypto_init_t init; }; /* * meta_object_t * * The internal state for a meta-object is kept here. The object handles * given to applications are always pointers to a structure of this type. */ struct metaobject { ulong_t magic_marker; pthread_rwlock_t object_lock; pthread_mutex_t isClosingObject_lock; boolean_t isClosingObject; struct metaobject *next; struct metaobject *prev; meta_session_t *creator_session; /* Only set for session objects */ boolean_t isToken; /* alias for CKA_TOKEN */ boolean_t isPrivate; /* alias for CKA_PRIVATE */ boolean_t isSensitive; /* alias for CKA_SENSITIVE */ boolean_t isExtractable; /* alias for CKA_EXTRACTABLE */ freeobject_state_t isFreeToken; freeobject_state_t isFreeObject; CK_ULONG master_clone_slotnum; /* set when object is created */ slot_object_t **clones; /* indicate if tried to create clone object in a slot */ boolean_t *tried_create_clone; pthread_rwlock_t attribute_lock; size_t num_attributes; generic_attr_t *attributes; pthread_mutex_t clone_create_lock; size_t clone_template_size; /* 0 if not yet known. */ CK_ATTRIBUTE *clone_template; /* NULL if not yet known. */ }; /* * struct metaopstate * * Used as the format for the operation state returned via * C_GetOperationState. */ typedef struct opstate_data { CK_FLAGS op_type; CK_ULONG op_slotnum; CK_ULONG op_state_len; boolean_t op_init_app; boolean_t op_init_done; } opstate_data_t; struct metaopstate { ulong_t magic_marker; /* * Could have just declared this as "state", but declaring it like this * so that when dual-op support is implemented in the future, the * changes will be simplier. */ struct opstate_data state[1]; }; /* * session_pool_t * * Used to cache open sessions in a slot. */ typedef struct sessionpool { pthread_mutex_t list_lock; /* list of sessions that's currently in use */ slot_session_t *active_list_head; /* * list of sessions that are not in use, but can't be deleted because * either session/token objects are created using these sessions * or we need to have one session left with the provider to maintain * the logged in state. Any of these sessions could be re-used if * a session is needed to be established with a provider. */ slot_session_t *persist_list_head; /* * List of sessions that are not in use at the moment. We keep * a list of sessions with a particular provider instead of * creating a new session everytime for efficiency */ slot_session_t *idle_list_head; boolean_t keep_one_alive; int num_idle_sessions; /* number of sessions in "idle_list_head" */ } session_pool_t; /* * slot_data_t * * Each slot has a session pool, a collection of persistant sessions to * allow for more efficient operation. Specifically, to allow reuse of * previously session objects (which need the creating session to stick * around), as well as being frugal with creating/closing sessions. */ typedef struct slotdata { CK_SLOT_ID fw_st_id; /* framework slot table ID */ session_pool_t session_pool; pthread_rwlock_t tokenobject_list_lock; slot_object_t *tokenobject_list_head; } slot_data_t; typedef enum { ALL_TOKEN = 0, PUBLIC_TOKEN = 1, PRIVATE_TOKEN = 2 } token_obj_type_t; /* * metaslot_config_t * * This holds the configuration information for meta slot. * It will first be filled with values that users defined * in environment variables. Any value not defined by the user * will be filled with values from the system wide configuration file. */ typedef struct _metaslot_config { /* token to be used as the keystore for metaslot */ boolean_t keystore_token_specified; CK_UTF8CHAR keystore_token[TOKEN_LABEL_SIZE + 1]; /* slot to be used as the keystore for metaslot */ boolean_t keystore_slot_specified; CK_UTF8CHAR keystore_slot[SLOT_DESCRIPTION_SIZE + 1]; /* should meta slot be enabled or not */ boolean_t enabled_specified; boolean_t enabled; /* should auto migration of sensitive token objects be enabled or not */ boolean_t auto_key_migrate_specified; boolean_t auto_key_migrate; } metaslot_config_t; /* * The following 2 structures are used to link the to-be-freed * meta sessions and meta objects into linked lists. * The items on these linked list have not yet been freed via free(); instead * they are added to this list. The actual free will take place when * the number of objects queued reaches MAX_OBJ_TO_BE_FREED or * MAX_SESSION_TO_BE_FREED, at which time the first object in the * list will be freed. */ typedef struct obj_to_be_freed_list { meta_object_t *first; /* points to first obj in the list */ meta_object_t *last; /* points to last obj in the list */ uint32_t count; /* current total objs in the list */ pthread_mutex_t obj_to_be_free_mutex; } object_to_be_freed_list_t; typedef struct ses_to_be_freed_list { meta_session_t *first; /* points to first session in the list */ meta_session_t *last; /* points to last session in the list */ uint32_t count; /* current total session in the list */ pthread_mutex_t ses_to_be_free_mutex; } ses_to_be_freed_list_t; typedef struct cipher_mechs_threshold { int mech_type; uint32_t mech_threshold; } cipher_mechs_threshold_t; /* Global variables */ extern metaslot_config_t metaslot_config; extern boolean_t metaslot_enabled; extern CK_SLOT_ID metaslot_keystore_slotid; extern boolean_t metaslot_auto_key_migrate; extern struct CK_FUNCTION_LIST metaslot_functionList; extern pthread_mutex_t initmutex; extern ses_to_be_freed_list_t ses_delay_freed; extern object_to_be_freed_list_t obj_delay_freed; extern void (*Tmp_GetThreshold)(void *); extern CK_BBOOL falsevalue; extern CK_BBOOL truevalue; /* --- Prototypes --- */ CK_RV meta_slotManager_initialize(); void meta_slotManager_finalize(); void meta_slotManager_find_object_token(); CK_RV meta_get_slot_session(CK_ULONG slotnum, slot_session_t **session, CK_FLAGS flags); void meta_release_slot_session(slot_session_t *session); CK_RV meta_mechManager_initialize(); void meta_mechManager_finalize(); CK_RV meta_mechManager_get_mechs(CK_MECHANISM_TYPE *list, CK_ULONG *listsize); CK_RV meta_mechManager_get_slots(mech_support_info_t *mech_support_info, boolean_t force_update, CK_MECHANISM_INFO *mech_info); CK_RV meta_mechManager_slot_supports_mech(CK_MECHANISM_TYPE mechanism, CK_ULONG slotnum, boolean_t *supports, mechinfo_t **slot_info, boolean_t force_update, CK_MECHANISM_INFO *mech_info); CK_RV meta_operation_init(CK_FLAGS optype, meta_session_t *session, CK_MECHANISM *pMechanism, meta_object_t *key); CK_RV meta_operation_init_defer(CK_FLAGS optype, meta_session_t *session, CK_MECHANISM *pMechanism, meta_object_t *key); CK_RV meta_do_operation(CK_FLAGS optype, int mode, meta_session_t *session, meta_object_t *object, CK_BYTE *in, CK_ULONG inLen, CK_BYTE *out, CK_ULONG *outLen); void meta_operation_cleanup(meta_session_t *session, CK_FLAGS optype, boolean_t finished_normally); CK_RV meta_generate_keys(meta_session_t *session, CK_MECHANISM *pMechanism, CK_ATTRIBUTE *k1Template, CK_ULONG k1AttrCount, meta_object_t *key1, CK_ATTRIBUTE *k2Template, CK_ULONG k2AttrCount, meta_object_t *key2); CK_RV meta_wrap_key(meta_session_t *session, CK_MECHANISM *pMechanism, meta_object_t *wrappingkey, meta_object_t *inputkey, CK_BYTE *wrapped_key, CK_ULONG *wrapped_key_len); CK_RV meta_unwrap_key(meta_session_t *session, CK_MECHANISM *pMechanism, meta_object_t *unwrapping_key, CK_BYTE *wrapped_key, CK_ULONG wrapped_key_len, CK_ATTRIBUTE *template, CK_ULONG template_size, meta_object_t *unwrapped_key); CK_RV meta_derive_key(meta_session_t *session, CK_MECHANISM *pMech, meta_object_t *basekey1, meta_object_t *basekey2, CK_OBJECT_HANDLE *phBaseKey2, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, meta_object_t *newKey1, meta_object_t *newKey2, meta_object_t *newKey3, meta_object_t *newKey4); void get_user_metaslot_config(); CK_RV meta_sessionManager_initialize(); void meta_sessionManager_finalize(); CK_RV meta_handle2session(CK_SESSION_HANDLE hSession, meta_session_t **session_p); CK_RV meta_session_alloc(meta_session_t **newSession); CK_RV meta_session_activate(meta_session_t *session); CK_RV meta_session_deactivate(meta_session_t *session, boolean_t have_sessionlist_lock); void meta_session_dealloc(meta_session_t *session); void meta_session_delay_free(meta_session_t *sp); CK_RV meta_objectManager_initialize(); void meta_objectManager_finalize(); CK_RV meta_handle2object(CK_OBJECT_HANDLE hObject, meta_object_t **object); CK_RV meta_object_alloc(meta_session_t *session, meta_object_t **object); CK_RV meta_object_get_attr(slot_session_t *slot_session, CK_OBJECT_HANDLE hObject, meta_object_t *object); void meta_object_activate(meta_object_t *object); CK_RV meta_object_deactivate(meta_object_t *object, boolean_t have_list_lock, boolean_t have_object_lock); CK_RV meta_object_dealloc(meta_session_t *session, meta_object_t *object, boolean_t nukeSourceObj); CK_RV meta_slot_object_alloc(slot_object_t **object); void meta_slot_object_activate(slot_object_t *object, slot_session_t *session, boolean_t isToken); void meta_slot_object_deactivate(slot_object_t *object); void meta_slot_object_dealloc(slot_object_t *object); CK_RV meta_object_copyin(meta_object_t *object); CK_RV meta_object_get_clone(meta_object_t *object, CK_ULONG slot_num, slot_session_t *slot_session, slot_object_t **clone); meta_object_t *meta_object_find_by_handle(CK_OBJECT_HANDLE hObject, CK_ULONG slotnum, boolean_t token_only); CK_RV meta_token_object_deactivate(token_obj_type_t token_type); void meta_object_delay_free(meta_object_t *objp); boolean_t meta_freeobject_set(meta_object_t *object, CK_ATTRIBUTE *tmpl, CK_ULONG tmpl_len, boolean_t create); CK_RV meta_freetoken_set(CK_ULONG slot_num, CK_BBOOL *current_value, CK_ATTRIBUTE *tmpl, CK_ULONG tmpl_len); boolean_t meta_freeobject_check(meta_session_t *session, meta_object_t *obj, CK_MECHANISM *pMech, CK_ATTRIBUTE *tmpl, CK_ULONG tmpl_len, CK_KEY_TYPE keytype); boolean_t meta_freeobject_clone(meta_session_t *session, meta_object_t *object); CK_RV get_master_attributes_by_object(slot_session_t *session, slot_object_t *slot_object, generic_attr_t **attributes, size_t *num_attributes); CK_RV get_master_attributes_by_template( CK_ATTRIBUTE *template, CK_ULONG template_size, generic_attr_t **attributes, size_t *num_attributes); CK_RV get_master_template_by_type(CK_OBJECT_CLASS class, CK_ULONG subtype, generic_attr_t **attributes, size_t *num_attributes); CK_RV get_master_attributes_by_type(CK_OBJECT_CLASS class, CK_ULONG subtype, generic_attr_t **attributes, size_t *num_attributes); CK_RV get_master_attributes_by_duplication( generic_attr_t *src_attrs, size_t num_src_attrs, generic_attr_t **dst_attrs, size_t *num_dst_attrs); void dealloc_attributes(generic_attr_t *attributes, size_t num_attributes); CK_RV attribute_set_value(CK_ATTRIBUTE *new_attr, generic_attr_t *attributes, size_t num_attributes); boolean_t get_template_ulong(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *attributes, CK_ULONG num_attributes, CK_ULONG *result); boolean_t get_template_boolean(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *attributes, CK_ULONG num_attributes, boolean_t *result); int set_template_boolean(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *attributes, CK_ULONG num_attributes, boolean_t local, CK_BBOOL *value); CK_ULONG get_keystore_slotnum(void); CK_ULONG get_softtoken_slotnum(void); CK_SLOT_ID meta_slotManager_get_framework_table_id(CK_ULONG slotnum); CK_ULONG meta_slotManager_get_slotcount(void); boolean_t meta_slotManager_token_write_protected(void); boolean_t metaslot_logged_in(); void metaslot_set_logged_in_flag(boolean_t value); /* * Prototypes for the various meta_Foo implementations of C_Foo. * */ CK_RV meta_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList); CK_RV meta_Initialize(CK_VOID_PTR pInitArgs); CK_RV meta_Finalize(CK_VOID_PTR pReserved); CK_RV meta_GetInfo(CK_INFO_PTR pInfo); CK_RV meta_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount); CK_RV meta_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo); CK_RV meta_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo); CK_RV meta_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount); CK_RV meta_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo); CK_RV meta_InitToken(CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, CK_UTF8CHAR_PTR pLabel); CK_RV meta_InitPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen); CK_RV meta_SetPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldPinLen, CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewPinLen); CK_RV meta_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession); CK_RV meta_CloseSession(CK_SESSION_HANDLE hSession); CK_RV meta_CloseAllSessions(CK_SLOT_ID slotID); CK_RV meta_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo); CK_RV meta_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG_PTR pulOperationStateLen); CK_RV meta_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey); CK_RV meta_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen); CK_RV meta_Logout(CK_SESSION_HANDLE hSession); CK_RV meta_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject); CK_RV meta_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject); CK_RV meta_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject); CK_RV meta_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize); CK_RV meta_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount); CK_RV meta_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount); CK_RV meta_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount); CK_RV meta_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount); CK_RV meta_FindObjectsFinal(CK_SESSION_HANDLE hSession); CK_RV meta_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); CK_RV meta_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen); CK_RV meta_EncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen); CK_RV meta_EncryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pulLastEncryptedPartLen); CK_RV meta_DecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); CK_RV meta_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen); CK_RV meta_DecryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen); CK_RV meta_DecryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen); CK_RV meta_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism); CK_RV meta_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen); CK_RV meta_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen); CK_RV meta_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey); CK_RV meta_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen); CK_RV meta_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); CK_RV meta_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen); CK_RV meta_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen); CK_RV meta_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen); CK_RV meta_SignRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); CK_RV meta_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen); CK_RV meta_VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); CK_RV meta_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen); CK_RV meta_VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen); CK_RV meta_VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen); CK_RV meta_VerifyRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); CK_RV meta_VerifyRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen); CK_RV meta_DigestEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen); CK_RV meta_DecryptDigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen); CK_RV meta_SignEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen); CK_RV meta_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen); CK_RV meta_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey); CK_RV meta_GenerateKeyPair(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey); CK_RV meta_WrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen); CK_RV meta_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey); CK_RV meta_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey); CK_RV meta_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen); CK_RV meta_GenerateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen); CK_RV meta_GetFunctionStatus(CK_SESSION_HANDLE hSession); CK_RV meta_CancelFunction(CK_SESSION_HANDLE hSession); CK_RV meta_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved); #ifdef __cplusplus } #endif #endif /* _METAGLOBAL_H */ /* * 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 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Key Management Functions * (as defined in PKCS#11 spec section 11.14) */ #include "metaGlobal.h" /* * meta_GenerateKey * */ CK_RV meta_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey) { CK_RV rv; meta_session_t *session; meta_object_t *key = NULL; if (pMechanism == NULL || phKey == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_object_alloc(session, &key); if (rv != CKR_OK) goto finish; rv = meta_generate_keys(session, pMechanism, pTemplate, ulCount, key, NULL, 0, NULL); if (rv != CKR_OK) goto finish; meta_object_activate(key); *phKey = (CK_OBJECT_HANDLE) key; finish: if (rv != CKR_OK) { if (key) (void) meta_object_dealloc(session, key, B_TRUE); } REFRELEASE(session); return (rv); } /* * meta_GenerateKeyPair * */ CK_RV meta_GenerateKeyPair(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey) { CK_RV rv; meta_session_t *session; meta_object_t *key1 = NULL, *key2 = NULL; if (pMechanism == NULL || phPublicKey == NULL || phPrivateKey == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_object_alloc(session, &key1); if (rv != CKR_OK) goto finish; rv = meta_object_alloc(session, &key2); if (rv != CKR_OK) goto finish; rv = meta_generate_keys(session, pMechanism, pPublicKeyTemplate, ulPublicKeyAttributeCount, key1, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, key2); if (rv != CKR_OK) goto finish; meta_object_activate(key1); meta_object_activate(key2); *phPublicKey = (CK_OBJECT_HANDLE) key1; *phPrivateKey = (CK_OBJECT_HANDLE) key2; finish: if (rv != CKR_OK) { if (key1) (void) meta_object_dealloc(session, key1, B_TRUE); if (key2) (void) meta_object_dealloc(session, key2, B_TRUE); } REFRELEASE(session); return (rv); } /* * meta_WrapKey * */ CK_RV meta_WrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen) { CK_RV rv; meta_session_t *session; meta_object_t *wrappingKey, *inputKey; if (pMechanism == NULL || pulWrappedKeyLen == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_handle2object(hKey, &inputKey); if (rv != CKR_OK) { REFRELEASE(session); return (rv); } rv = meta_handle2object(hWrappingKey, &wrappingKey); if (rv != CKR_OK) { OBJRELEASE(inputKey); REFRELEASE(session); return (rv); } rv = meta_wrap_key(session, pMechanism, wrappingKey, inputKey, pWrappedKey, pulWrappedKeyLen); OBJRELEASE(inputKey); OBJRELEASE(wrappingKey); REFRELEASE(session); return (rv); } /* * meta_UnwrapKey * */ CK_RV meta_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) { CK_RV rv; meta_session_t *session; meta_object_t *unwrappingKey, *outputKey = NULL; if (pMechanism == NULL || pWrappedKey == NULL || phKey == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_handle2object(hUnwrappingKey, &unwrappingKey); if (rv != CKR_OK) { REFRELEASE(session); return (rv); } rv = meta_object_alloc(session, &outputKey); if (rv != CKR_OK) goto finish; (void) get_template_boolean(CKA_TOKEN, pTemplate, ulAttributeCount, &(outputKey->isToken)); rv = meta_unwrap_key(session, pMechanism, unwrappingKey, pWrappedKey, ulWrappedKeyLen, pTemplate, ulAttributeCount, outputKey); if (rv != CKR_OK) goto finish; meta_object_activate(outputKey); *phKey = (CK_OBJECT_HANDLE) outputKey; finish: if (rv != CKR_OK) { if (outputKey) (void) meta_object_dealloc(session, outputKey, B_TRUE); } OBJRELEASE(unwrappingKey); REFRELEASE(session); return (rv); } /* * meta_DeriveKey * * This function is a bit gross because of PKCS#11 kludges that pass extra * object handles in some mechanism parameters. It probably needs to be * broken up into more managable pieces. */ CK_RV meta_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) { CK_RV rv; CK_MECHANISM *pMech = pMechanism; meta_session_t *session; meta_object_t *basekey1 = NULL, *basekey2 = NULL; meta_object_t *newKey1 = NULL, *newKey2 = NULL, *newKey3 = NULL, *newKey4 = NULL; boolean_t ssl_keys = B_FALSE; boolean_t tlsprf = B_FALSE; CK_MECHANISM metaMech; CK_OBJECT_HANDLE *phBaseKey2 = NULL; CK_X9_42_DH2_DERIVE_PARAMS x942_params, *x9_tmpptr; CK_ECDH2_DERIVE_PARAMS ecdh_params, *ec_tmpptr; CK_SSL3_KEY_MAT_OUT *ssl_key_mat; CK_SSL3_KEY_MAT_PARAMS *keyparams; if (pMech == NULL) { return (CKR_ARGUMENTS_BAD); } /* * Special case: Normally, the caller must always provide storage * for the derived key handle at phKey. Two (related) mechanisms * are special, in that multiple keys are instead returned via * pMech->pParameter. In these cases the spec says (see 12.38.4 * and 12.39.4) that phKey should be a NULL pointer, as it is not used. */ switch (pMech->mechanism) { case CKM_SSL3_KEY_AND_MAC_DERIVE: case CKM_TLS_KEY_AND_MAC_DERIVE: keyparams = (CK_SSL3_KEY_MAT_PARAMS*)pMech->pParameter; if ((keyparams == NULL) || (pMech->ulParameterLen != sizeof (CK_SSL3_KEY_MAT_PARAMS))) return (CKR_ARGUMENTS_BAD); ssl_key_mat = keyparams->pReturnedKeyMaterial; if (ssl_key_mat == NULL) return (CKR_ARGUMENTS_BAD); ssl_keys = B_TRUE; break; case CKM_TLS_PRF: tlsprf = B_TRUE; break; default: if (phKey == NULL) return (CKR_ARGUMENTS_BAD); }; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_handle2object(hBaseKey, &basekey1); if (rv != CKR_OK) goto finish; /* * A few oddball mechanisms pass a 2nd object handle in the parameters. * Here we validate that handle, and create a duplicate copy of the * mechanism and parameters. This is done because the application * does not expect these values to be changing, and could be using the * same data in multiple threads (eg concurrent calls to C_DeriveKey). * We copy the data to make sure there are no MT-Safe problems. */ switch (pMech->mechanism) { case CKM_ECMQV_DERIVE: /* uses CK_ECDH2_DERIVE_PARAMS struct as the parameter */ if ((pMech->pParameter == NULL) || (pMech->ulParameterLen != sizeof (CK_ECDH2_DERIVE_PARAMS))) { rv = CKR_ARGUMENTS_BAD; goto finish; } /* Duplicate the mechanism and paramaters */ ec_tmpptr = (CK_ECDH2_DERIVE_PARAMS *)pMech->pParameter; ecdh_params = *ec_tmpptr; metaMech = *pMech; metaMech.pParameter = &ecdh_params; pMech = &metaMech; /* Get the key the application is providing */ phBaseKey2 = &ecdh_params.hPrivateData; break; case CKM_X9_42_DH_HYBRID_DERIVE: case CKM_X9_42_MQV_DERIVE: /* both use CK_X9_42_DH2_DERIVE_PARAMS as the parameter */ if ((pMech->pParameter == NULL) || (pMech->ulParameterLen != sizeof (CK_X9_42_DH2_DERIVE_PARAMS))) { rv = CKR_ARGUMENTS_BAD; goto finish; } /* Duplicate the mechanism and paramaters */ x9_tmpptr = (CK_X9_42_DH2_DERIVE_PARAMS *)pMech->pParameter; x942_params = *x9_tmpptr; metaMech = *pMech; metaMech.pParameter = &x942_params; pMech = &metaMech; /* Get the key the application is providing */ phBaseKey2 = &x942_params.hPrivateData; break; case CKM_CONCATENATE_BASE_AND_KEY: /* uses a CK_OBJECT_HANDLE as the parameter */ if ((pMech->pParameter == NULL) || (pMech->ulParameterLen != sizeof (CK_OBJECT_HANDLE))) { rv = CKR_ARGUMENTS_BAD; goto finish; } /* Duplicate the mechanism and paramaters */ metaMech = *pMech; pMech = &metaMech; /* Get the key the application is providing */ phBaseKey2 = (CK_OBJECT_HANDLE *) &metaMech.pParameter; break; default: /* nothing special to do. */ break; } if (phBaseKey2) { rv = meta_handle2object(*phBaseKey2, &basekey2); if (rv != CKR_OK) goto finish; } /* * Allocate meta objects to store the derived key(s). Normally just * a single key is created, but the SSL/TLS mechanisms generate four. */ rv = meta_object_alloc(session, &newKey1); if (rv != CKR_OK) goto finish; if (ssl_keys) { rv = meta_object_alloc(session, &newKey2); if (rv != CKR_OK) goto finish; rv = meta_object_alloc(session, &newKey3); if (rv != CKR_OK) goto finish; rv = meta_object_alloc(session, &newKey4); if (rv != CKR_OK) goto finish; } /* Perform the actual key derive operation. */ rv = meta_derive_key(session, pMech, basekey1, basekey2, phBaseKey2, pTemplate, ulAttributeCount, newKey1, newKey2, newKey3, newKey4); if (rv != CKR_OK) goto finish; if (tlsprf) { (void) meta_object_dealloc(session, newKey1, B_TRUE); newKey1 = NULL; /* phKey isn't used (is NULL) for mechanism CKM_TLS_PRF. */ } else { /* Make derived key(s) active and visible to other threads. */ meta_object_activate(newKey1); if (ssl_keys) { meta_object_activate(newKey2); meta_object_activate(newKey3); meta_object_activate(newKey4); ssl_key_mat->hClientMacSecret = (CK_OBJECT_HANDLE) newKey1; ssl_key_mat->hServerMacSecret = (CK_OBJECT_HANDLE) newKey2; ssl_key_mat->hClientKey = (CK_OBJECT_HANDLE) newKey3; ssl_key_mat->hServerKey = (CK_OBJECT_HANDLE) newKey4; /* phKey isn't used (is NULL) for these SSL/TLS mechs */ } else { *phKey = (CK_OBJECT_HANDLE) newKey1; } } finish: if (rv != CKR_OK) { if (newKey1) (void) meta_object_dealloc(session, newKey1, B_TRUE); if (newKey2) (void) meta_object_dealloc(session, newKey2, B_TRUE); if (newKey3) (void) meta_object_dealloc(session, newKey3, B_TRUE); if (newKey4) (void) meta_object_dealloc(session, newKey4, B_TRUE); } if (basekey1) OBJRELEASE(basekey1); if (basekey2) OBJRELEASE(basekey2); REFRELEASE(session); return (rv); } /* * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Mechanism Manager - centralized knowledge of mechanisms. * * The core of the mechmanager is the "mechlist" data structure. It contains * information about all mechanisms available from providers that have been * exposed to the application. * * Each element in the array represents a particular mechanism type. The * array is sorted by type, so that searching by mechanism can be done * quickly. Each element also contains the mechanism data for each slot. * * The mechlist is constructed on an as-needed basis, entries are not added * until the application triggers an action that requires an entry to be * added (or updated). * */ #include #include #include "pkcs11Conf.h" #include "metaGlobal.h" /* Global data... */ #define INITIAL_MECHLIST_SIZE 256 typedef struct mechliststruct { CK_MECHANISM_TYPE type; mechinfo_t *slots; } mechlist_t; static pthread_rwlock_t mechlist_lock = PTHREAD_RWLOCK_INITIALIZER; static mechlist_t *mechlist; static unsigned long num_mechs; static unsigned long true_mechlist_size; /* Prototypes... */ static CK_RV meta_mechManager_update_mech(CK_MECHANISM_TYPE, boolean_t); static CK_RV meta_mechManager_update_slot(CK_ULONG); static CK_RV update_slotmech(CK_MECHANISM_TYPE, CK_ULONG, unsigned long); static CK_RV meta_mechManager_allocmechs(CK_MECHANISM_TYPE *, unsigned long, unsigned long *); static boolean_t find_mech_index(CK_MECHANISM_TYPE, unsigned long *); static int qsort_mechtypes(const void *, const void *); /* * meta_mechManager_initialize * * Called from C_Initialize. Allocates and initializes storage needed * by the slot manager. */ CK_RV meta_mechManager_initialize() { /* The mechlist can dynamically grow, but let's preallocate space. */ mechlist = calloc(INITIAL_MECHLIST_SIZE, sizeof (mechlist_t)); if (mechlist == NULL) return (CKR_HOST_MEMORY); true_mechlist_size = INITIAL_MECHLIST_SIZE; num_mechs = 0; return (CKR_OK); } /* * meta_mechManager_finalize * * Called from C_Finalize. Deallocates any storage held by the slot manager. */ void meta_mechManager_finalize() { int i; /* No need to lock list, we assume all sessions are closed. */ for (i = 0; i < num_mechs; i++) { free(mechlist[i].slots); } free(mechlist); mechlist = NULL; num_mechs = 0; true_mechlist_size = 0; } /* * meta_mechManager_get_mechs * * Get list of all available mechanisms. * * Follows PKCS#11 semantics, where list may be NULL to only request a * count of available mechanisms. */ CK_RV meta_mechManager_get_mechs(CK_MECHANISM_TYPE *list, CK_ULONG *listsize) { CK_RV rv = CKR_OK; CK_ULONG num_found = 0; CK_ULONG slotnum, num_slots; unsigned long i; /* get number of slots */ num_slots = meta_slotManager_get_slotcount(); /* * Update slot info. Ignore any errors. * * NOTE: Due to the PKCS#11 convention of calling C_GetMechanismList * twice (once to get the count, again to get the actual list), this * is somewhat inefficient... However, I don't see an easy way to fix * that without impacting other cases (eg, when the first call contains * an "optimistic" pre-allocated buffer). */ for (slotnum = 0; slotnum < num_slots; slotnum++) { (void) meta_mechManager_update_slot(slotnum); } /* * Count the number of mechanisms. We can't just use num_mechs, * because some mechs may not currently be supported on any slot. * Also, it may not be allowed based on the mechanism policy. */ (void) pthread_rwlock_rdlock(&mechlist_lock); for (i = 0; i < num_mechs; i++) { CK_ULONG j; boolean_t supported; if (pkcs11_is_dismech(METASLOT_FRAMEWORK_ID, mechlist[i].type)) { /* skip mechs disabled by policy */ continue; } supported = FALSE; for (j = 0; j < num_slots; j++) { if (!mechlist[i].slots[j].initialized) continue; if (mechlist[i].slots[j].supported) { supported = B_TRUE; break; } } if (supported) { num_found++; if (list && *listsize >= num_found) { list[num_found - 1] = mechlist[i].type; } } } (void) pthread_rwlock_unlock(&mechlist_lock); if (num_found > *listsize) rv = CKR_BUFFER_TOO_SMALL; *listsize = num_found; return (rv); } /* * meta_mechManager_get_slots * * Get list of all slots supporting the specified mechanism. * * The "mech_support_info" argument should have allocated enough * space to accomodate the list of slots that supports the * specified mechanism. The "num_supporting_slots" field * in the "mech_support_info" structure will indicate how * many slots are found to support the mechanism. * * If any error occurred in getting the list, info in * mech_support_info argument is not updated. * */ CK_RV meta_mechManager_get_slots(mech_support_info_t *mech_support_info, boolean_t force_update, CK_MECHANISM_INFO *mech_info) { CK_RV rv; boolean_t found; CK_ULONG i, num_slots; unsigned long index, num_found = 0; CK_MECHANISM_INFO info; rv = meta_mechManager_update_mech(mech_support_info->mech, force_update); if (rv != CKR_OK) { return (rv); } (void) pthread_rwlock_rdlock(&mechlist_lock); found = find_mech_index(mech_support_info->mech, &index); if (!found) { goto finish; } num_slots = meta_slotManager_get_slotcount(); for (i = 0; i < num_slots; i++) { if (!mechlist[index].slots[i].initialized || !mechlist[index].slots[i].supported) continue; if (mech_info) { info = mechlist[index].slots[i].mechanism_info; if (!(info.flags & mech_info->flags)) { continue; } } num_found++; (mech_support_info->supporting_slots)[num_found - 1] = &mechlist[index].slots[i]; } finish: (void) pthread_rwlock_unlock(&mechlist_lock); if (num_found == 0) { rv = CKR_MECHANISM_INVALID; } else { mech_support_info->num_supporting_slots = num_found; } return (rv); } /* * meta_mechManager_update_mech * * Updates a mechanism in the mechlist. If the mechanism is not * listed, all providers will be queried. If the mechanism * is present, but not initialized for some providers, those providers * will be queried. Existing entries will not be updated unless the * force_refresh flag is set. * * The force_refresh flag is used by C_GetMechanismInfo, to force an * update. Updates are not forced during the common usage by operations * [eg C_EncryptInit] to avoid poor performance. */ static CK_RV meta_mechManager_update_mech(CK_MECHANISM_TYPE mech, boolean_t force_refresh) { CK_RV rv; CK_ULONG slot, num_slots; unsigned long index = 0; boolean_t found; /* Ensure list contains the mechanism. */ rv = meta_mechManager_allocmechs(&mech, 1, &index); if (rv != CKR_OK) return (rv); (void) pthread_rwlock_wrlock(&mechlist_lock); /* * We didn't retain a lock after the first search, so it's possible * that the mechlist was updated. Search again, but use the last * index as a hint to quickly find the mechanism. */ found = find_mech_index(mech, &index); if (!found) { /* Shouldn't happen - entries are not removed from list. */ rv = CKR_GENERAL_ERROR; goto finish; } num_slots = meta_slotManager_get_slotcount(); for (slot = 0; slot < num_slots; slot++) { if (force_refresh || !mechlist[index].slots[slot].initialized) { rv = update_slotmech(mech, slot, index); if (rv != CKR_OK) { /* Ignore error and continue with next slot. */ rv = CKR_OK; } } } finish: (void) pthread_rwlock_unlock(&mechlist_lock); return (rv); } /* * meta_mechManager_update_slot * * Updates a slot in the mechlist. Called by C_GetMechanismList * [by way of meta_mechManager_get_mechs()]. Unlike * meta_mechManager_get_slots(), the context is always to force a refresh * of the mechlist. * */ static CK_RV meta_mechManager_update_slot(CK_ULONG slotnum) { unsigned long index = 0; CK_MECHANISM_TYPE *slot_mechlist = NULL, *tmp_slot_mechlist = NULL; CK_ULONG slot_mechlistsize, mechnum, tmp_mechlistsize; CK_RV rv; boolean_t found; CK_SLOT_ID fw_st_id, true_id; int i; fw_st_id = meta_slotManager_get_framework_table_id(slotnum); true_id = TRUEID(fw_st_id); /* First, get the count. */ rv = FUNCLIST(fw_st_id)->C_GetMechanismList(true_id, NULL, &slot_mechlistsize); if (rv != CKR_OK) { goto finish; } tmp_slot_mechlist = malloc( slot_mechlistsize * sizeof (CK_MECHANISM_TYPE)); if (tmp_slot_mechlist == NULL) { rv = CKR_HOST_MEMORY; goto finish; } /* Next, get the actual list. */ rv = FUNCLIST(fw_st_id)->C_GetMechanismList(true_id, tmp_slot_mechlist, &slot_mechlistsize); if (rv != CKR_OK) { goto finish; } /* * filter the list of mechanisms returned by the underlying slot * to remove any mechanisms that are explicitly disabled * in the configuration file. */ slot_mechlist = malloc(slot_mechlistsize * sizeof (CK_MECHANISM_TYPE)); if (slot_mechlist == NULL) { rv = CKR_HOST_MEMORY; goto finish; } tmp_mechlistsize = 0; for (i = 0; i < slot_mechlistsize; i++) { /* filter out the disabled mechanisms */ if (pkcs11_is_dismech(fw_st_id, tmp_slot_mechlist[i])) { continue; } slot_mechlist[tmp_mechlistsize] = tmp_slot_mechlist[i]; tmp_mechlistsize++; } slot_mechlistsize = tmp_mechlistsize; /* Sort the mechanisms by value. */ qsort(slot_mechlist, slot_mechlistsize, sizeof (CK_MECHANISM_TYPE), qsort_mechtypes); /* Ensure list contains the mechanisms. */ rv = meta_mechManager_allocmechs(slot_mechlist, slot_mechlistsize, &index); if (rv != CKR_OK) goto finish; /* Update the mechanism info. */ (void) pthread_rwlock_wrlock(&mechlist_lock); for (mechnum = 0; mechnum < slot_mechlistsize; mechnum++) { found = find_mech_index(slot_mechlist[mechnum], &index); if (!found) { /* This shouldn't happen. */ rv = CKR_GENERAL_ERROR; goto finish; } rv = update_slotmech(slot_mechlist[mechnum], slotnum, index); if (rv != CKR_OK) { /* Ignore error, make best effort to finish update. */ rv = CKR_OK; continue; } } (void) pthread_rwlock_unlock(&mechlist_lock); finish: if (slot_mechlist) { free(slot_mechlist); } if (tmp_slot_mechlist) { free(tmp_slot_mechlist); } return (rv); } /* * update_slotmech * * Updates the information for a particular mechanism for a particular slot. * (ie, slotlist[foo].slots[bar]) * * It is assumed that the caller to this function (all of which are * in this file) holds the write-lock to "mechlist_lock". * */ static CK_RV update_slotmech(CK_MECHANISM_TYPE mech, CK_ULONG slotnum, unsigned long index) { CK_RV rv = CKR_OK; CK_MECHANISM_INFO info; CK_SLOT_ID fw_st_id, true_id; mechlist[index].slots[slotnum].slotnum = slotnum; fw_st_id = meta_slotManager_get_framework_table_id(slotnum); true_id = TRUEID(fw_st_id); /* * Check if the specified mechanism is in the disabled list * of the specified slot. If so, we can immediately conclude * that it is not supported by the specified slot. */ if (pkcs11_is_dismech(fw_st_id, mech)) { /* * we mark this as initialized so that we won't try * to do this check later */ mechlist[index].slots[slotnum].initialized = B_TRUE; mechlist[index].slots[slotnum].supported = B_FALSE; bzero(&mechlist[index].slots[slotnum].mechanism_info, sizeof (CK_MECHANISM_INFO)); goto finish; } rv = FUNCLIST(fw_st_id)->C_GetMechanismInfo(true_id, mech, &info); if (rv == CKR_OK) { mechlist[index].slots[slotnum].initialized = B_TRUE; mechlist[index].slots[slotnum].supported = B_TRUE; mechlist[index].slots[slotnum].mechanism_info = info; } else { /* record that the mechanism isn't supported for the slot */ mechlist[index].slots[slotnum].initialized = B_TRUE; mechlist[index].slots[slotnum].supported = B_FALSE; bzero(&mechlist[index].slots[slotnum].mechanism_info, sizeof (CK_MECHANISM_INFO)); } finish: return (rv); } /* * meta_mechManager_allocmechs * * Ensures that all of the specified mechanisms are present in the * mechlist. If a mechanism is not present, an uninitialized entry is * added for it. * * The returned index can be used by the caller as a hint to where the * first mechanism was located. */ static CK_RV meta_mechManager_allocmechs(CK_MECHANISM_TYPE *new_mechs, unsigned long num_new_mechs, unsigned long *index_hint) { CK_RV rv = CKR_OK; unsigned long i, index = 0; boolean_t found; /* The optimistic assumption is that the mech is already present. */ (void) pthread_rwlock_rdlock(&mechlist_lock); for (i = 0; i < num_new_mechs; i++) { found = find_mech_index(new_mechs[i], &index); if (i == 0) *index_hint = index; if (!found) break; } (void) pthread_rwlock_unlock(&mechlist_lock); if (found) { return (CKR_OK); } /* * We stopped searching when the first unknown mech was found. Now * obtain a write-lock, and continue from where we left off, inserting * unknown mechanisms. */ (void) pthread_rwlock_wrlock(&mechlist_lock); for (; i < num_new_mechs; i++) { found = find_mech_index(new_mechs[i], &index); if (!found) { mechinfo_t *new_mechinfos; new_mechinfos = calloc(meta_slotManager_get_slotcount(), sizeof (mechinfo_t)); if (new_mechinfos == NULL) { rv = CKR_HOST_MEMORY; goto finish; } /* * If the current storage for the mechlist is too * small, allocate a new list twice as large. */ if (num_mechs == true_mechlist_size) { mechlist_t *newmechlist; newmechlist = realloc(mechlist, 2 * true_mechlist_size * sizeof (mechlist_t)); if (newmechlist == NULL) { rv = CKR_HOST_MEMORY; free(new_mechinfos); goto finish; } mechlist = newmechlist; true_mechlist_size *= 2; } /* Shift existing entries to make space. */ (void) memmove(&mechlist[index+1], &mechlist[index], (num_mechs - index) * sizeof (mechlist_t)); num_mechs++; mechlist[index].type = new_mechs[i]; mechlist[index].slots = new_mechinfos; } } finish: (void) pthread_rwlock_unlock(&mechlist_lock); return (rv); } /* * find_mech_index * * Performs a search of mechlist for the specified mechanism, and * returns if the mechanism was found or not. The value of the "index" * argument will be where the mech is (if found), or where it should * be (if not found). * * The current value of "index" will be used as a starting point, if the * caller already knows where the mechanism is likely to be. * * The caller is assumed to have a lock on the mechlist, preventing it * from being changed while searching (also to ensure the returned index * will remain valid until the list is unlocked). * * FUTURE: convert to binary search [from O(N) to a O(log(N))]. * * NOTES: * 1) This function assumes that mechMap is a sorted list. */ static boolean_t find_mech_index(CK_MECHANISM_TYPE mechanism, unsigned long *index) { boolean_t found = B_FALSE; unsigned long i; for (i = 0; i < num_mechs; i++) { if (mechlist[i].type == mechanism) { found = B_TRUE; break; } if (mechlist[i].type > mechanism) break; } *index = i; return (found); } static int qsort_mechtypes(const void *arg1, const void *arg2) { CK_MECHANISM_TYPE mech1 = *((CK_MECHANISM_TYPE *)arg1); CK_MECHANISM_TYPE mech2 = *((CK_MECHANISM_TYPE *)arg2); if (mech1 > mech2) return (1); if (mech1 < mech2) return (-1); return (0); } /* * Check if the specified mechanism is supported by the specified slot. * The result is returned in the "supports" argument. If the "slot_info" * argument is not NULL, it will be filled with information about * the slot. */ CK_RV meta_mechManager_slot_supports_mech(CK_MECHANISM_TYPE mechanism, CK_ULONG slotnum, boolean_t *supports, mechinfo_t **slot_info, boolean_t force_update, CK_MECHANISM_INFO *mech_info) { boolean_t found; CK_RV rv; unsigned long index; CK_MECHANISM_INFO info; *supports = B_FALSE; rv = meta_mechManager_update_mech(mechanism, force_update); if (rv != CKR_OK) return (rv); (void) pthread_rwlock_rdlock(&mechlist_lock); found = find_mech_index(mechanism, &index); if (!found) { goto finish; } if ((mechlist[index].slots[slotnum].initialized) && (mechlist[index].slots[slotnum].supported)) { if (mech_info) { info = mechlist[index].slots[slotnum].mechanism_info; if (!(info.flags & mech_info->flags)) { goto finish; } } *supports = B_TRUE; if (slot_info) { *slot_info = &(mechlist[index].slots[slotnum]); } } finish: (void) pthread_rwlock_unlock(&mechlist_lock); return (rv); } /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Object Management Functions * (as defined in PKCS#11 spec section 11.7) */ #include #include "metaGlobal.h" #include #define FIND_OBJ_BUF_SIZE 512 /* size of buf used for C_FindObjects */ /* * Argument related return codes. Will return to the caller immediately, * and not try the operation on another slot. */ static CK_RV stop_rv[] = { CKR_ARGUMENTS_BAD, CKR_ATTRIBUTE_TYPE_INVALID, CKR_DOMAIN_PARAMS_INVALID, CKR_TEMPLATE_INCOMPLETE }; static int num_stop_rv = sizeof (stop_rv) / sizeof (CK_RV); /* * Return codes that are related to a specific slot. * Will try to perform the operation in the next available slot. * If all attempts failed, will return the error code from the first slot. * * This list is here for reference only, it is commented out because * it doesn't need to be used by the code at this point. * * static CK_RV try_again_rv[] = { * CKR_DEVICE_ERROR, * CKR_DEVICE_MEMORY, * CKR_DEVICE_REMOVED, * CKR_FUNCTION_FAILED, * CKR_GENERAL_ERROR, * CKR_HOST_MEMORY, * CKR_TEMPLATE_INCONSISTENT, * CKR_ATTRIBUTE_READ_ONLY, * CKR_ATTRIBUTE_VALUE_INVALID * }; * static int num_try_again_rv = sizeof (try_again_rv) / sizeof (CK_RV); */ /* * We should never get these return codes because * MetaSlot is the one that actually created the * sessions. When we get these errors in C_CreateObject, * will try to create the object in the next available slot. * If all attempts failed, will return CKR_FUNCTION_FAILED * to the caller. */ static CK_RV other_rv[] = { CKR_CRYPTOKI_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_SESSION_READ_ONLY }; static int num_other_rv = sizeof (other_rv) / sizeof (CK_RV); /* * This function is only used by the C_CreateObject and C_CopyObject. * * It is used to determine if the operation should be tried on another slot * based on the return code */ static boolean_t try_again(CK_RV rv) { int i; for (i = 0; i < num_stop_rv; i++) { if (rv == stop_rv[i]) { return (B_FALSE); } } return (B_TRUE); } /* * meta_CreateObject * */ CK_RV meta_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject) { CK_RV rv; meta_session_t *session; slot_session_t *slot_session = NULL; meta_object_t *object = NULL; slot_object_t *slot_object = NULL; CK_OBJECT_HANDLE hNewObject; CK_ULONG slot_num, keystore_slotnum; CK_RV first_rv; if (pTemplate == NULL || ulCount < 1 || phObject == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_object_alloc(session, &object); if (rv != CKR_OK) goto cleanup; /* * Create a clone of the object */ rv = meta_slot_object_alloc(&slot_object); if (rv != CKR_OK) goto cleanup; /* * Set to true (token object) if template has CKA_TOKEN=true; * otherwise, it is false (session object). */ (void) get_template_boolean(CKA_TOKEN, pTemplate, ulCount, &(object->isToken)); /* Can't create token objects in a read-only session. */ if ((IS_READ_ONLY_SESSION(session->session_flags)) && object->isToken) { rv = CKR_SESSION_READ_ONLY; goto cleanup; } /* * Set to true (private object) if template has CKA_PRIVATE=true; * otherwise, it is false (public object). */ (void) get_template_boolean(CKA_PRIVATE, pTemplate, ulCount, &(object->isPrivate)); /* Assume object is extractable unless template has otherwise */ object->isExtractable = B_TRUE; (void) get_template_boolean(CKA_EXTRACTABLE, pTemplate, ulCount, &(object->isExtractable)); /* * Set to true (sensitive object) if template has CKA_SENSITIVE=true; * otherwise, it is false. */ (void) get_template_boolean(CKA_SENSITIVE, pTemplate, ulCount, &(object->isSensitive)); /* * Check if this can be a FreeObject. * * For creating objects, this check is mostly for preventing * non-keystore hardware from creating CKA_PRIVATE objects without * logging in. */ if (meta_freeobject_check(session, object, NULL, pTemplate, ulCount, 0)) { /* * Make sure we are logged into the keystore if this is a * private freetoken object. */ if (object->isPrivate && !metaslot_logged_in()) return (CKR_USER_NOT_LOGGED_IN); if (!meta_freeobject_set(object, pTemplate, ulCount, B_TRUE)) goto cleanup; } keystore_slotnum = get_keystore_slotnum(); if (object->isToken || object->isFreeToken == FREE_ENABLED) { /* * If this is a token object or a FreeToken then create it * on the keystore slot. */ slot_num = keystore_slotnum; rv = meta_get_slot_session(slot_num, &slot_session, session->session_flags); if (rv != CKR_OK) goto cleanup; object->tried_create_clone[slot_num] = B_TRUE; rv = FUNCLIST(slot_session->fw_st_id)->C_CreateObject( slot_session->hSession, pTemplate, ulCount, &hNewObject); if (rv != CKR_OK) goto cleanup; } else { /* * Create a clone of the object in the first available slot. * * If creating a clone in a specific slot failed, it will * either stop and return the error to the user, or try * again in the next available slot until it succeeds. The * decision to stop or continue is made based on the return * code. */ CK_ULONG num_slots = meta_slotManager_get_slotcount(); for (slot_num = 0; slot_num < num_slots; slot_num++) { /* * If this is a free token and we are on the keystore * slot, bypass this because it was already created */ rv = meta_get_slot_session(slot_num, &slot_session, session->session_flags); if (rv != CKR_OK) goto cleanup; object->tried_create_clone[slot_num] = B_TRUE; rv = FUNCLIST(slot_session->fw_st_id)->C_CreateObject( slot_session->hSession, pTemplate, ulCount, &hNewObject); if (rv == CKR_OK) break; if (!try_again(rv)) goto cleanup; /* save first rv for other errors */ if (slot_num == 0) first_rv = rv; meta_release_slot_session(slot_session); slot_session = NULL; } } if (rv == CKR_OK) { slot_object->hObject = hNewObject; object->clones[slot_num] = slot_object; object->master_clone_slotnum = slot_num; /* Allow FreeToken to activate onto token obj list */ if (object->isFreeToken == FREE_ENABLED) object->isToken = B_TRUE; meta_slot_object_activate(slot_object, slot_session, object->isToken); slot_object = NULL; meta_release_slot_session(slot_session); slot_session = NULL; } else { /* * return either first error code or * CKR_FUNCTION_FAILED depending on the failure */ int i; for (i = 0; i < num_other_rv; i++) { if (rv == other_rv[i]) { rv = CKR_FUNCTION_FAILED; goto cleanup; } } /* need to return first rv */ rv = first_rv; goto cleanup; } /* * always keep a copy of the template for C_CreateObject, * so clones can be created on other slots if necessary. * This is done even when the CKA_EXTRACTABLE=FALSE flag * is set for the object. The supplied template is * "owned" by metaslot. The application should not be * penalized just because metaslot choose to try creating * the object in a slot that's not capable of performing * any future operation. */ rv = get_master_attributes_by_template(pTemplate, ulCount, &object->attributes, &object->num_attributes); if (rv == CKR_OK) { CK_ULONG i; for (i = 0; i < ulCount; i++) { rv = attribute_set_value(&(pTemplate[i]), object->attributes, object->num_attributes); } } meta_object_activate(object); *phObject = (CK_OBJECT_HANDLE) object; REFRELEASE(session); return (CKR_OK); cleanup: if (slot_object) meta_slot_object_dealloc(slot_object); if (slot_session) meta_release_slot_session(slot_session); if (object) (void) meta_object_dealloc(session, object, B_TRUE); REFRELEASE(session); return (rv); } /* * meta_CopyObject * */ CK_RV meta_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject) { CK_RV rv, first_rv; meta_session_t *session; meta_object_t *src_object, *dst_object = NULL; slot_session_t *slot_session = NULL; slot_object_t *dst_slot_object = NULL; CK_ULONG i; slot_object_t *src_slot_object; CK_ULONG slotnum, num_slots; boolean_t found; if (pTemplate == NULL && ulCount != 0) return (CKR_ARGUMENTS_BAD); if (phNewObject == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_handle2object(hObject, &src_object); if (rv != CKR_OK) { REFRELEASE(session); return (rv); } rv = meta_object_alloc(session, &dst_object); if (rv != CKR_OK) goto finish; found = get_template_boolean(CKA_TOKEN, pTemplate, ulCount, &(dst_object->isToken)); if (!found) { dst_object->isToken = src_object->isToken; if (src_object->isFreeToken == FREE_ENABLED) dst_object->isToken = TRUE; else dst_object->isToken = src_object->isToken; } /* Can't create token objects in a read-only session. */ if ((IS_READ_ONLY_SESSION(session->session_flags)) && (dst_object->isToken)) { rv = CKR_SESSION_READ_ONLY; goto finish; } if (dst_object->isToken) { /* * if the dst object is a token object, and the source * object is not, the source object needs to be extractable. * Otherwise, the source object needs to reside in the * token object slot */ if ((!src_object->isExtractable) && (src_object->master_clone_slotnum != get_keystore_slotnum())) { rv = CKR_FUNCTION_FAILED; goto finish; } /* determine if dst is going to be private object or not */ found = get_template_boolean(CKA_PRIVATE, pTemplate, ulCount, &(dst_object->isPrivate)); if (!found) { /* will be the same as the source object */ dst_object->isPrivate = src_object->isPrivate; } slotnum = get_keystore_slotnum(); } else { /* try create the obj in the same slot as the source obj */ slotnum = src_object->master_clone_slotnum; } rv = meta_slot_object_alloc(&dst_slot_object); if (rv != CKR_OK) goto finish; rv = meta_get_slot_session(slotnum, &slot_session, session->session_flags); if (rv != CKR_OK) goto finish; rv = meta_object_get_clone(src_object, slotnum, slot_session, &src_slot_object); if (rv != CKR_OK) goto finish; dst_object->tried_create_clone[slotnum] = B_TRUE; rv = FUNCLIST(slot_session->fw_st_id)->C_CopyObject( slot_session->hSession, src_slot_object->hObject, pTemplate, ulCount, &(dst_slot_object->hObject)); if (rv != CKR_OK) { if (dst_object->isToken) { /* * token obj can only be created in the * token slot. No need to try anywhere else */ goto finish; } if ((!src_object->isExtractable) || ((src_object->isSensitive) && (src_object->isToken) && (!metaslot_auto_key_migrate))) { /* source object isn't clonable in another slot */ goto finish; } if (!try_again(rv)) { goto finish; } first_rv = rv; meta_release_slot_session(slot_session); slot_session = NULL; num_slots = meta_slotManager_get_slotcount(); /* Try operation on other slots if the object is clonable */ for (slotnum = 0; slotnum < num_slots; slotnum++) { if (slotnum == src_object->master_clone_slotnum) { /* already tried, don't need to try again */ continue; } rv = meta_get_slot_session(slotnum, &slot_session, session->session_flags); if (rv != CKR_OK) { goto finish; } rv = meta_object_get_clone(src_object, slotnum, slot_session, &src_slot_object); if (rv != CKR_OK) goto finish; dst_object->tried_create_clone[slotnum] = B_TRUE; rv = FUNCLIST(slot_session->fw_st_id)->C_CopyObject( slot_session->hSession, src_slot_object->hObject, pTemplate, ulCount, &dst_slot_object->hObject); if (rv == CKR_OK) { break; } if (!try_again(rv)) { goto finish; } meta_release_slot_session(slot_session); slot_session = NULL; } } if (rv == CKR_OK) { rv = meta_object_get_attr(slot_session, dst_slot_object->hObject, dst_object); if (rv != CKR_OK) { goto finish; } if (src_object->attributes != NULL) { /* Keep a copy of the template for the future */ /* * Don't allow attributes to change while * we look at them. */ (void) pthread_rwlock_rdlock( &src_object->attribute_lock); rv = get_master_attributes_by_duplication( src_object->attributes, src_object->num_attributes, &dst_object->attributes, &dst_object->num_attributes); (void) pthread_rwlock_unlock( &src_object->attribute_lock); if (rv != CKR_OK) goto finish; for (i = 0; i < ulCount; i++) { rv = attribute_set_value(pTemplate + i, dst_object->attributes, dst_object->num_attributes); if (rv != CKR_OK) goto finish; } } /* Allow FreeToken to activate onto token obj list */ if (dst_object->isFreeToken == FREE_ENABLED) dst_object->isToken = TRUE; meta_slot_object_activate(dst_slot_object, slot_session, dst_object->isToken); dst_object->clones[slotnum] = dst_slot_object; dst_object->master_clone_slotnum = slotnum; dst_slot_object = NULL; /* for error cleanup */ meta_release_slot_session(slot_session); slot_session = NULL; /* for error cleanup */ } else { /* * return either first error code or * CKR_FUNCTION_FAILED depending on the failure */ int j; for (j = 0; j < num_other_rv; j++) { if (rv == other_rv[j]) { rv = CKR_FUNCTION_FAILED; goto finish; } } /* need to return first rv */ rv = first_rv; goto finish; } meta_object_activate(dst_object); *phNewObject = (CK_OBJECT_HANDLE) dst_object; finish: if (rv != CKR_OK) { if (dst_slot_object) meta_slot_object_dealloc(dst_slot_object); if (dst_object) (void) meta_object_dealloc(session, dst_object, B_TRUE); if (slot_session) meta_release_slot_session(slot_session); } OBJRELEASE(src_object); REFRELEASE(session); return (rv); } /* * meta_DestroyObject * * This function destroys an object by first removing it from the * list of valid objects for a given session (if session object) or * the global token object list. And then, calling C_DestroyObject * on all the slots on which we have created a clone of this object. */ CK_RV meta_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) { CK_RV rv; meta_session_t *session; meta_object_t *object; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_handle2object(hObject, &object); if (rv != CKR_OK) { REFRELEASE(session); return (rv); } /* Can't delete token objects from a read-only session. */ if ((IS_READ_ONLY_SESSION(session->session_flags)) && (object->isToken || object->isFreeToken == FREE_ENABLED)) { OBJRELEASE(object); REFRELEASE(session); return (CKR_SESSION_READ_ONLY); } /* Remove object from list of valid meta_objects */ rv = meta_object_deactivate(object, B_FALSE, B_TRUE); /* * Actually call C_DestroyObject on all the slots on which we have * created a clone of this object. */ if (rv == CKR_OK) rv = meta_object_dealloc(session, object, B_TRUE); REFRELEASE(session); return (rv); } /* * meta_GetObjectSize * * NOTES: * 1) Because the "size" is so poorly defined in the spec, we have deemed * it useless and won't support it. This is especially true for the * metaslot, because the mulitple providers it uses may each interpret * the size differently. */ /* ARGSUSED */ CK_RV meta_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize) { return (CKR_FUNCTION_NOT_SUPPORTED); } /* * meta_GetAttributeValue * */ CK_RV meta_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { CK_RV rv; meta_session_t *session; meta_object_t *object; CK_ULONG slotnum; slot_session_t *slot_session; if (pTemplate == NULL || ulCount < 1) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_handle2object(hObject, &object); if (rv != CKR_OK) { REFRELEASE(session); return (rv); } slotnum = object->master_clone_slotnum; rv = meta_get_slot_session(slotnum, &slot_session, session->session_flags); if (rv == CKR_OK) { rv = FUNCLIST(slot_session->fw_st_id)->C_GetAttributeValue( slot_session->hSession, object->clones[slotnum]->hObject, pTemplate, ulCount); meta_release_slot_session(slot_session); } OBJRELEASE(object); REFRELEASE(session); return (rv); } /* * meta_SetAttributeValue * * Call C_SetAttributeValue on all the clones. If the operation fails on * all clones, return the failure. * * If the operation fails on some clones and not the others, delete all the * clones that have failed the operation. If any of the deleted clone is the * master clone, use one of the remaining clone as the master clone. * * If the operation is successful and the master template already exists, * update the master template with new values. */ CK_RV meta_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { CK_RV rv = CKR_OK, save_rv = CKR_OK; meta_session_t *session; meta_object_t *object; CK_ULONG slotnum, num_slots; /* Keep track of which slot's SetAttributeValue failed */ boolean_t *clone_failed_op = NULL; int num_clones = 0, num_clones_failed = 0; slot_session_t *slot_session; slot_object_t *slot_object; boolean_t need_update_master_clone = B_FALSE; if (pTemplate == NULL || ulCount < 1) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_handle2object(hObject, &object); if (rv != CKR_OK) { REFRELEASE(session); return (rv); } if ((IS_READ_ONLY_SESSION(session->session_flags)) && (object->isToken || object->isFreeToken == FREE_ENABLED)) { rv = CKR_SESSION_READ_ONLY; goto finish; } if ((!object->isExtractable) && (object->attributes == NULL)) { /* * object has no clone, just need to do the operation * in the master clone slot */ slot_session_t *slot_session; slotnum = object->master_clone_slotnum; rv = meta_get_slot_session(slotnum, &slot_session, session->session_flags); if (rv == CKR_OK) { rv = FUNCLIST(slot_session->fw_st_id)->\ C_SetAttributeValue(slot_session->hSession, object->clones[slotnum]->hObject, pTemplate, ulCount); meta_release_slot_session(slot_session); } goto finish; } num_slots = meta_slotManager_get_slotcount(); /* * object might have clones, need to do operation in all clones * * If the C_SetAttributeValue() call fails in a clone, the * clone that failed the operation can not be deleted right * away. The clone with the failed operation is recorded, and * the deletion will happen in a separate loop. * * This is necessary because if ALL the clones failed * C_SetAttributeVAlue(), then, the app's call to C_SetAttributeValue() * is considered failed, and there shouldn't be any changes to the * object, none of the clones should be deleted. * On the other hand, if C_SetAttributeValue() fails in some clones * and succeeds in other clones, the C_SetAttributeValue() operation * is considered successful, and those clones that failed the * operation is deleted. */ clone_failed_op = calloc(num_slots, sizeof (boolean_t)); if (clone_failed_op == NULL) { rv = CKR_HOST_MEMORY; goto finish; } for (slotnum = 0; slotnum < num_slots; slotnum++) { if (object->clones[slotnum] != NULL) { num_clones++; rv = meta_get_slot_session(slotnum, &slot_session, session->session_flags); if (rv != CKR_OK) { goto finish; } rv = FUNCLIST(slot_session->fw_st_id)->\ C_SetAttributeValue(slot_session->hSession, object->clones[slotnum]->hObject, pTemplate, ulCount); if (rv != CKR_OK) { num_clones_failed++; clone_failed_op[slotnum] = B_TRUE; if (save_rv == CKR_OK) { save_rv = rv; } } meta_release_slot_session(slot_session); } } if (num_clones_failed == num_clones) { /* all operations failed */ rv = save_rv; goto finish; } if (num_clones_failed > 0) { /* * C_SetAttributeValue in some of the clones failed. * Find out which ones failed, and delete the clones * in those failed slots */ for (slotnum = 0; slotnum < num_slots; slotnum++) { if (clone_failed_op[slotnum]) { slot_object_t *clone = object->clones[slotnum]; rv = meta_get_slot_session(slotnum, &slot_session, session->session_flags); if (rv == CKR_OK) { (void) FUNCLIST( slot_session->fw_st_id)-> C_DestroyObject( slot_session->hSession, clone->hObject); meta_release_slot_session(slot_session); } meta_slot_object_deactivate(clone); meta_slot_object_dealloc(clone); object->clones[slotnum] = NULL; if (slotnum == object->master_clone_slotnum) { need_update_master_clone = B_TRUE; } } } if (need_update_master_clone) { /* make first available clone the master */ for (slotnum = 0; slotnum < num_slots; slotnum++) { if (object->clones[slotnum]) { object->master_clone_slotnum = slotnum; need_update_master_clone = B_FALSE; break; } } } if (need_update_master_clone) { /* * something is very wrong, can't continue * it should never be this case. */ rv = CKR_FUNCTION_FAILED; goto finish; } rv = CKR_OK; } /* * Update the attribute information we keep in our metaslot object */ slot_object = object->clones[object->master_clone_slotnum]; rv = meta_get_slot_session(object->master_clone_slotnum, &slot_session, session->session_flags); if (rv == CKR_OK) { (void) meta_object_get_attr(slot_session, slot_object->hObject, object); meta_release_slot_session(slot_session); } /* if there's a copy of the attributes, keep it up to date */ if (object->attributes != NULL) { CK_ULONG i; /* Make sure no one else is looking at attributes. */ (void) pthread_rwlock_wrlock(&object->attribute_lock); for (i = 0; i < ulCount; i++) { (void) attribute_set_value(pTemplate + i, object->attributes, object->num_attributes); } (void) pthread_rwlock_unlock(&object->attribute_lock); } finish: if (clone_failed_op) { free(clone_failed_op); } OBJRELEASE(object); REFRELEASE(session); return (rv); } static boolean_t meta_object_in_list(meta_object_t *obj, meta_object_t **objs_list, int num_objs) { int i; for (i = 0; i < num_objs; i++) { if (objs_list[i] == obj) { return (B_TRUE); } } return (B_FALSE); } static CK_RV add_to_search_result(meta_object_t *object, find_objs_info_t *info, int *num_results_alloc) { /* * allocate space for storing results if the currently * allocated space is not enough */ if (*num_results_alloc <= info->num_matched_objs) { *num_results_alloc += FIND_OBJ_BUF_SIZE; info->matched_objs = realloc(info->matched_objs, sizeof (meta_object_t *) * (*num_results_alloc)); if (info->matched_objs == NULL) { return (CKR_HOST_MEMORY); } } (info->matched_objs)[(info->num_matched_objs)++] = object; return (CKR_OK); } static CK_RV process_find_results(CK_OBJECT_HANDLE *results, CK_ULONG num_results, int *num_results_allocated, find_objs_info_t *info, CK_ULONG slotnum, boolean_t token_only, slot_session_t *slot_session, meta_session_t *session) { CK_ULONG i; meta_object_t *object; CK_RV rv; for (i = 0; i < num_results; i++) { object = meta_object_find_by_handle(results[i], slotnum, token_only); /* * a token object is found from the keystore, * need to create a meta object for it */ if (object == NULL) { slot_object_t *slot_object; rv = meta_object_alloc(session, &object); if (rv != CKR_OK) { return (rv); } rv = meta_slot_object_alloc(&slot_object); if (rv != CKR_OK) { (void) meta_object_dealloc(session, object, B_TRUE); return (rv); } slot_object->hObject = results[i]; object->master_clone_slotnum = slotnum; object->clones[slotnum] = slot_object; /* get in the attributes we keep in meta_object */ rv = meta_object_get_attr(slot_session, slot_object->hObject, object); if (rv != CKR_OK) { (void) meta_object_dealloc(session, object, B_TRUE); return (rv); } meta_slot_object_activate(slot_object, slot_session, B_TRUE); meta_object_activate(object); slot_object = NULL; } if (!meta_object_in_list(object, info->matched_objs, info->num_matched_objs)) { rv = add_to_search_result(object, info, num_results_allocated); if (rv != CKR_OK) { return (rv); } } } return (CKR_OK); } static CK_RV meta_search_for_objects(meta_session_t *session, find_objs_info_t *info, slot_session_t *slot_session, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_ULONG slotnum, boolean_t token_only, int *num_results_alloc) { CK_ULONG tmp_num_results; CK_OBJECT_HANDLE tmp_results[FIND_OBJ_BUF_SIZE]; CK_SESSION_HANDLE hSession = slot_session->hSession; CK_RV rv; CK_SLOT_ID fw_st_id = slot_session->fw_st_id; rv = FUNCLIST(fw_st_id)->C_FindObjectsInit(hSession, pTemplate, ulCount); if (rv != CKR_OK) { return (rv); } tmp_num_results = 0; rv = FUNCLIST(fw_st_id)->C_FindObjects(hSession, tmp_results, FIND_OBJ_BUF_SIZE, &tmp_num_results); if (rv != CKR_OK) { return (rv); } rv = process_find_results(tmp_results, tmp_num_results, num_results_alloc, info, slotnum, token_only, slot_session, session); if (rv != CKR_OK) { return (rv); } while (tmp_num_results == FIND_OBJ_BUF_SIZE) { /* might be more results, need to call C_FindObjects again */ rv = FUNCLIST(fw_st_id)->C_FindObjects(hSession, tmp_results, FIND_OBJ_BUF_SIZE, &tmp_num_results); if (rv != CKR_OK) { return (rv); } rv = process_find_results(tmp_results, tmp_num_results, num_results_alloc, info, slotnum, token_only, slot_session, session); if (rv != CKR_OK) { return (rv); } } rv = FUNCLIST(fw_st_id)->C_FindObjectsFinal(hSession); return (rv); } /* * meta_FindObjectsInit * * This function actually will do ALL the work of searching for objects * that match all requirements specified in the template. * * Objects that matched the template will be stored in the * session's data structure. When the subsequent C_FindObjects() * calls are made, results saved will be returned. * */ CK_RV meta_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { CK_RV rv; meta_session_t *session; CK_ULONG slot_num = 0; boolean_t have_token_attr, tokenTrue = B_FALSE; slot_session_t *slot_find_session = NULL; int num_results_allocated = 0; CK_ULONG keystore_slotnum; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); if ((session->find_objs_info).op_active) { REFRELEASE(session); return (CKR_OPERATION_ACTIVE); } (session->find_objs_info).op_active = B_TRUE; REFRELEASE(session); /* see if the template indicates token object only or not */ have_token_attr = get_template_boolean(CKA_TOKEN, pTemplate, ulCount, &tokenTrue); keystore_slotnum = get_keystore_slotnum(); if (have_token_attr && tokenTrue) { /* * only interested in token objects, just need to search * token object slot */ rv = meta_get_slot_session(keystore_slotnum, &slot_find_session, session->session_flags); if (rv != CKR_OK) { goto finish; } rv = meta_search_for_objects(session, &(session->find_objs_info), slot_find_session, pTemplate, ulCount, keystore_slotnum, B_TRUE, &num_results_allocated); if (rv != CKR_OK) { goto finish; } } else { CK_ULONG num_slots = meta_slotManager_get_slotcount(); for (slot_num = 0; slot_num < num_slots; slot_num++) { rv = meta_get_slot_session(slot_num, &slot_find_session, session->session_flags); if (rv != CKR_OK) { goto finish; } /* * if the slot is NOT the token object slot, and * CKA_TOKEN is not specified, need to specified * it to be false explicitly. This will prevent * us from using token objects that doesn't * belong to the token slot in the case that * more than one slot supports token objects. */ if ((slot_num != keystore_slotnum) && (!have_token_attr)) { CK_BBOOL false = FALSE; CK_ATTRIBUTE_PTR newTemplate; newTemplate = malloc((ulCount + 1) * sizeof (CK_ATTRIBUTE)); if (newTemplate == NULL) { rv = CKR_HOST_MEMORY; goto finish; } (void) memcpy(newTemplate + 1, pTemplate, ulCount * sizeof (CK_ATTRIBUTE)); newTemplate[0].type = CKA_TOKEN; newTemplate[0].pValue = &false; newTemplate[0].ulValueLen = sizeof (false); rv = meta_search_for_objects(session, &(session->find_objs_info), slot_find_session, newTemplate, ulCount+1, slot_num, B_FALSE, &num_results_allocated); free(newTemplate); } else { rv = meta_search_for_objects(session, &(session->find_objs_info), slot_find_session, pTemplate, ulCount, slot_num, B_FALSE, &num_results_allocated); } if (rv != CKR_OK) { goto finish; } meta_release_slot_session(slot_find_session); slot_find_session = NULL; } } finish: if (slot_find_session != NULL) { meta_release_slot_session(slot_find_session); } if (rv != CKR_OK) { (void) pthread_rwlock_wrlock(&session->session_lock); if (((session->find_objs_info).matched_objs) != NULL) { free((session->find_objs_info).matched_objs); } bzero(&(session->find_objs_info), sizeof (find_objs_info_t)); (void) pthread_rwlock_unlock(&(session->session_lock)); } return (rv); } /* * meta_FindObjects * * This function actually doesn't do any real work in search for the * matching object. All the work is done in FindObjectsInit(). This * function will only return the matching objects store in the session's * "find_objs_info" variable. * */ CK_RV meta_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount) { CK_RV rv; find_objs_info_t *info; CK_ULONG num_objs_found = 0; meta_object_t *obj; meta_session_t *session; int i; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); info = &(session->find_objs_info); if (!(info->op_active)) { REFRELEASE(session); return (CKR_OPERATION_NOT_INITIALIZED); } for (i = info->next_result_index; ((num_objs_found < ulMaxObjectCount) && (i < info->num_matched_objs)); i++) { obj = info->matched_objs[i]; if (obj != NULL) { /* sanity check to see if object is still valid */ (void) pthread_rwlock_rdlock(&obj->object_lock); if (obj->magic_marker == METASLOT_OBJECT_MAGIC) { phObject[num_objs_found++] = (CK_OBJECT_HANDLE)obj; } (void) pthread_rwlock_unlock(&obj->object_lock); } } info->next_result_index = i; *pulObjectCount = num_objs_found; REFRELEASE(session); return (rv); } /* * meta_FindObjectsFinal * */ CK_RV meta_FindObjectsFinal(CK_SESSION_HANDLE hSession) { CK_RV rv; find_objs_info_t *info; meta_session_t *session; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); info = &(session->find_objs_info); if (!info->op_active) { REFRELEASE(session); return (CKR_OPERATION_NOT_INITIALIZED); } if (info->matched_objs) { free(info->matched_objs); } bzero(info, sizeof (find_objs_info_t)); REFRELEASE(session); return (rv); } /* * 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 (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, Joyent, Inc. */ #include #include #include #include #include #include #include #include "metaGlobal.h" /* Size of the template for creating key used for wrap/unwrap */ #define WRAP_KEY_TEMPLATE_SIZE 7 /* * Information necessary to create keys for C_WrapKey/C_UnwrapKey */ typedef struct _wrap_info { CK_OBJECT_CLASS class; /* class of the key for wrap/unwrap */ CK_KEY_TYPE key_type; /* key type of key for wrap/unwrap */ CK_ULONG key_length; /* length of key */ CK_MECHANISM_TYPE mech_type; /* mech used for wrap/unwrap */ CK_ULONG iv_length; /* length of iv for mech */ boolean_t src_supports; boolean_t dst_supports; } wrap_info_t; extern pthread_rwlock_t meta_sessionlist_lock; extern meta_session_t *meta_sessionlist_head; static wrap_info_t common_wrap_info[] = { {CKO_SECRET_KEY, CKK_AES, 16, CKM_AES_CBC_PAD, 16, B_FALSE, B_FALSE}, {CKO_SECRET_KEY, CKK_DES3, 24, CKM_DES3_CBC_PAD, 8, B_FALSE, B_FALSE}, {CKO_SECRET_KEY, CKK_DES, 8, CKM_DES_CBC_PAD, 8, B_FALSE, B_FALSE}, }; static unsigned int num_common_wrap_info = sizeof (common_wrap_info) / sizeof (wrap_info_t); static wrap_info_t special_wrap_info[] = { {CKO_SECRET_KEY, CKK_SKIPJACK, 12, CKM_SKIPJACK_WRAP, 0, B_FALSE, B_FALSE}, {CKO_SECRET_KEY, CKK_BATON, 40, CKM_BATON_WRAP, 0, B_FALSE, B_FALSE}, {CKO_SECRET_KEY, CKK_JUNIPER, 40, CKM_JUNIPER_WRAP, 0, B_FALSE, B_FALSE}, }; static unsigned int num_special_wrap_info = sizeof (special_wrap_info) / sizeof (wrap_info_t); static wrap_info_t rsa_wrap_info[] = { {CKO_PUBLIC_KEY, CKK_RSA, 0, CKM_RSA_PKCS, 0, B_FALSE, B_FALSE}, {CKO_PUBLIC_KEY, CKK_RSA, 0, CKM_RSA_X_509, 0, B_FALSE, B_FALSE}, }; static unsigned int num_rsa_wrap_info = sizeof (rsa_wrap_info) / sizeof (wrap_info_t); static pthread_rwlock_t meta_objectclose_lock; static pthread_rwlock_t tokenobject_list_lock; static meta_object_t *tokenobject_list_head; CK_BBOOL falsevalue = FALSE; CK_BBOOL truevalue = TRUE; /* * Public and private exponent, and Module value for * creating the RSA public/private key. * */ static CK_BYTE PubExpo[3] = {0x01, 0x00, 0x01}; CK_BYTE PriExpo[128] = { 0x8e, 0xc9, 0x70, 0x57, 0x6b, 0xcd, 0xfb, 0xa9, 0x19, 0xad, 0xcd, 0x91, 0x69, 0xd5, 0x52, 0xec, 0x72, 0x1e, 0x45, 0x15, 0x06, 0xdc, 0x65, 0x2d, 0x98, 0xc4, 0xce, 0x33, 0x54, 0x15, 0x70, 0x8d, 0xfa, 0x65, 0xea, 0x53, 0x44, 0xf3, 0x3e, 0x3f, 0xb4, 0x4c, 0x60, 0xd5, 0x01, 0x2d, 0xa4, 0x12, 0x99, 0xbf, 0x3f, 0x0b, 0xcd, 0xbb, 0x24, 0x10, 0x60, 0x30, 0x5e, 0x58, 0xf8, 0x59, 0xaa, 0xd1, 0x63, 0x3b, 0xbc, 0xcb, 0x94, 0x58, 0x38, 0x24, 0xfc, 0x65, 0x25, 0xc5, 0xa6, 0x51, 0xa2, 0x2e, 0xf1, 0x5e, 0xf5, 0xc1, 0xf5, 0x46, 0xf7, 0xbd, 0xc7, 0x62, 0xa8, 0xe2, 0x27, 0xd6, 0x94, 0x5b, 0xd3, 0xa2, 0xb5, 0x76, 0x42, 0x67, 0x6b, 0x86, 0x91, 0x97, 0x4d, 0x07, 0x92, 0x00, 0x4a, 0xdf, 0x0b, 0x65, 0x64, 0x05, 0x03, 0x48, 0x27, 0xeb, 0xce, 0x9a, 0x49, 0x7f, 0x3e, 0x10, 0xe0, 0x01}; static CK_BYTE Modulus[128] = { 0x94, 0x32, 0xb9, 0x12, 0x1d, 0x68, 0x2c, 0xda, 0x2b, 0xe0, 0xe4, 0x97, 0x1b, 0x4d, 0xdc, 0x43, 0xdf, 0x38, 0x6e, 0x7b, 0x9f, 0x07, 0x58, 0xae, 0x9d, 0x82, 0x1e, 0xc7, 0xbc, 0x92, 0xbf, 0xd3, 0xce, 0x00, 0xbb, 0x91, 0xc9, 0x79, 0x06, 0x03, 0x1f, 0xbc, 0x9f, 0x94, 0x75, 0x29, 0x5f, 0xd7, 0xc5, 0xf3, 0x73, 0x8a, 0xa4, 0x35, 0x43, 0x7a, 0x00, 0x32, 0x97, 0x3e, 0x86, 0xef, 0x70, 0x6f, 0x18, 0x56, 0x15, 0xaa, 0x6a, 0x87, 0xe7, 0x8d, 0x7d, 0xdd, 0x1f, 0xa4, 0xe4, 0x31, 0xd4, 0x7a, 0x8c, 0x0e, 0x20, 0xd2, 0x23, 0xf5, 0x57, 0x3c, 0x1b, 0xa8, 0x44, 0xa4, 0x57, 0x8f, 0x33, 0x52, 0xad, 0x83, 0xae, 0x4a, 0x97, 0xa6, 0x1e, 0xa6, 0x2b, 0xfa, 0xea, 0xeb, 0x6e, 0x71, 0xb8, 0xb6, 0x0a, 0x36, 0xed, 0x83, 0xce, 0xb0, 0xdf, 0xc1, 0xd4, 0x3a, 0xe9, 0x99, 0x6f, 0xf3, 0x96, 0xb7}; static CK_RV meta_clone_template_setup(meta_object_t *object, const generic_attr_t *attributes, size_t num_attributes); /* * meta_objectManager_initialize * * Called from meta_Initialize. Initializes all the variables used * by the object manager. */ CK_RV meta_objectManager_initialize() { if (pthread_rwlock_init(&meta_objectclose_lock, NULL) != 0) { return (CKR_FUNCTION_FAILED); } if (pthread_rwlock_init(&tokenobject_list_lock, NULL) != 0) { (void) pthread_rwlock_destroy(&meta_objectclose_lock); return (CKR_FUNCTION_FAILED); } tokenobject_list_head = NULL; return (CKR_OK); } void meta_objectManager_finalize() { /* * If there are still any token object in the list, need to * deactivate all of them. */ (void) meta_token_object_deactivate(ALL_TOKEN); (void) pthread_rwlock_destroy(&meta_objectclose_lock); (void) pthread_rwlock_destroy(&tokenobject_list_lock); } /* * meta_handle2object * * Convert a CK_OBJECT_HANDLE to the corresponding metaobject. If * successful, a reader-lock on the object will be held to indicate * that it's in use. Call OBJRELEASE() when finished. * */ CK_RV meta_handle2object(CK_OBJECT_HANDLE hObject, meta_object_t **object) { meta_object_t *tmp_object = (meta_object_t *)(hObject); /* Check for bad args (eg CK_INVALID_HANDLE, which is 0/NULL). */ if (tmp_object == NULL) { *object = NULL; return (CKR_OBJECT_HANDLE_INVALID); } /* Lock to ensure the magic-check + read-lock is atomic. */ (void) pthread_rwlock_rdlock(&meta_objectclose_lock); if (tmp_object->magic_marker != METASLOT_OBJECT_MAGIC) { (void) pthread_rwlock_unlock(&meta_objectclose_lock); *object = NULL; return (CKR_OBJECT_HANDLE_INVALID); } (void) pthread_rwlock_rdlock(&tmp_object->object_lock); (void) pthread_rwlock_unlock(&meta_objectclose_lock); *object = tmp_object; return (CKR_OK); } /* * meta_object_alloc * * Creates a new metaobject, but does not yet add it to the object list. * Once the caller has finished initializing the object (by setting * object attributes), meta_object_add should be called. This two-step * process prevents others from seeing the object until fully intitialized. * */ CK_RV meta_object_alloc(meta_session_t *session, meta_object_t **object) { meta_object_t *new_object; CK_ULONG num_slots; /* Allocate memory for the object. */ new_object = calloc(1, sizeof (meta_object_t)); if (new_object == NULL) return (CKR_HOST_MEMORY); num_slots = meta_slotManager_get_slotcount(); new_object->clones = calloc(num_slots, sizeof (slot_object_t *)); if (new_object->clones == NULL) { free(new_object); return (CKR_HOST_MEMORY); } new_object->tried_create_clone = calloc(num_slots, sizeof (boolean_t)); if (new_object->tried_create_clone == NULL) { free(new_object->clones); free(new_object); return (CKR_HOST_MEMORY); } /* Initialize the object fields. */ new_object->magic_marker = METASLOT_OBJECT_MAGIC; (void) pthread_rwlock_init(&new_object->object_lock, NULL); (void) pthread_rwlock_init(&new_object->attribute_lock, NULL); (void) pthread_mutex_init(&new_object->clone_create_lock, NULL); (void) pthread_mutex_init(&new_object->isClosingObject_lock, NULL); new_object->creator_session = session; *object = new_object; return (CKR_OK); } /* * meta_object_get_attr * * Get attribute values to fill in attribute values * being kept in the metaslot object. The following 4 attributes * in the meta_object_t structure will be filled in: * isToken, isPrivate, isSensitive, isExtractable * * It's basically an easy way to do a C_GetAttributeValue. * So, the hSession argument is assumed * to be valid, and the pointer to meta_object_t is also assumed * to be valid. */ CK_RV meta_object_get_attr(slot_session_t *slot_session, CK_OBJECT_HANDLE hObject, meta_object_t *object) { CK_BBOOL is_sensitive = object->isSensitive; CK_BBOOL is_extractable = object->isExtractable; CK_BBOOL is_token = B_FALSE, is_private = B_FALSE; CK_KEY_TYPE keytype; CK_OBJECT_CLASS class; CK_ATTRIBUTE attrs[3]; CK_RV rv; CK_SESSION_HANDLE hSession = slot_session->hSession; CK_SLOT_ID fw_st_id = slot_session->fw_st_id; int count = 1; attrs[0].type = CKA_CLASS; attrs[0].pValue = &class; attrs[0].ulValueLen = sizeof (class); if (object->isFreeObject != FREE_ENABLED) { attrs[1].type = CKA_TOKEN; attrs[1].pValue = &is_token; attrs[1].ulValueLen = sizeof (is_token); count++; } /* * If this is a freeobject, we already know the Private value * and we don't want to overwrite it with the wrong value */ if (object->isFreeObject <= FREE_DISABLED) { attrs[count].type = CKA_PRIVATE; attrs[count].pValue = &is_private; attrs[count].ulValueLen = sizeof (is_private); count++; } else is_private = object->isPrivate; rv = FUNCLIST(fw_st_id)->C_GetAttributeValue(hSession, hObject, attrs, count); if (rv != CKR_OK) { return (rv); } count = 0; switch (class) { case CKO_PRIVATE_KEY: case CKO_SECRET_KEY: /* Only need to check these for private & secret keys */ attrs[0].type = CKA_EXTRACTABLE; attrs[0].pValue = &is_extractable; attrs[0].ulValueLen = sizeof (is_extractable); count = 1; /* * If this is a freeobject, we already know the Sensitive * value and we don't want to overwrite it with the wrong * value. */ if (object->isFreeObject <= FREE_DISABLED) { attrs[1].type = CKA_SENSITIVE; attrs[1].pValue = &is_sensitive; attrs[1].ulValueLen = sizeof (is_sensitive); count = 2; /* * We only need the key type if this is the first * time we've looked at the object */ if (object->isFreeObject == FREE_UNCHECKED) { attrs[2].type = CKA_KEY_TYPE; attrs[2].pValue = &keytype; attrs[2].ulValueLen = sizeof (keytype); count = 3; } } break; case CKO_PUBLIC_KEY: if (object->isFreeObject == FREE_UNCHECKED) { attrs[count].type = CKA_KEY_TYPE; attrs[count].pValue = &keytype; attrs[count].ulValueLen = sizeof (keytype); count++; } is_sensitive = CK_FALSE; is_extractable = CK_TRUE; break; default: object->isFreeObject = FREE_DISABLED; is_sensitive = CK_FALSE; is_extractable = CK_TRUE; }; if (count > 0) { rv = FUNCLIST(fw_st_id)->C_GetAttributeValue(hSession, hObject, attrs, count); if (rv != CKR_OK) { return (rv); } if (object->isFreeObject == FREE_UNCHECKED) { if (keytype == CKK_EC || keytype == CKK_RSA || keytype == CKK_DH) { if (metaslot_config.auto_key_migrate) { object->isFreeObject = FREE_DISABLED; object->isFreeToken = FREE_DISABLED; } object->isFreeObject = FREE_ENABLED; if (is_token) object->isFreeToken = FREE_ENABLED; } else object->isFreeObject = FREE_DISABLED; } } object->isToken = is_token; object->isPrivate = is_private; object->isSensitive = is_sensitive; object->isExtractable = is_extractable; return (CKR_OK); } /* * meta_object_activate * * Add a new metaobject to the list of objects. See also meta_object_create, * which would be called to create an object before it is added. */ void meta_object_activate(meta_object_t *new_object) { pthread_rwlock_t *list_lock; meta_object_t **list_head; /* * For session objects, we keep the list in the session that created * this object, because this object will be destroyed when that session * is closed. * * For token objects, the list is global (ie, not associated with any * particular session). */ if (new_object->isToken) { list_lock = &tokenobject_list_lock; list_head = &tokenobject_list_head; } else { list_lock = &new_object->creator_session->object_list_lock; list_head = &new_object->creator_session->object_list_head; } /* Add object to the list of objects. */ (void) pthread_rwlock_wrlock(list_lock); INSERT_INTO_LIST(*list_head, new_object); (void) pthread_rwlock_unlock(list_lock); } /* * meta_object_deactivate * * Removes the object from the list of valid meta objects. Note * that this function does not clean up any allocated * resources (memory, object clones, etc). Cleaning up of * allocated resources is done by calling the meta_object_dealloc() * */ CK_RV meta_object_deactivate(meta_object_t *object, boolean_t have_list_lock, boolean_t have_object_lock) { pthread_rwlock_t *list_lock; meta_object_t **list_head; if (!have_object_lock) { (void) pthread_rwlock_rdlock(&object->object_lock); } (void) pthread_mutex_lock(&object->isClosingObject_lock); if (object->isClosingObject) { /* Lost a delete race. */ (void) pthread_mutex_unlock(&object->isClosingObject_lock); OBJRELEASE(object); return (CKR_OBJECT_HANDLE_INVALID); } object->isClosingObject = B_TRUE; (void) pthread_mutex_unlock(&object->isClosingObject_lock); if (object->isToken || (object->isFreeToken == FREE_ENABLED)) { list_lock = &tokenobject_list_lock; list_head = &tokenobject_list_head; } else { list_lock = &object->creator_session->object_list_lock; list_head = &object->creator_session->object_list_head; } /* * Remove object from the object list. Once removed, it will not * be possible for another thread to begin using the object. */ (void) pthread_rwlock_wrlock(&meta_objectclose_lock); if (!have_list_lock) { (void) pthread_rwlock_wrlock(list_lock); } object->magic_marker = METASLOT_OBJECT_BADMAGIC; /* * Can't use the regular REMOVE_FROM_LIST() function because * that will miss the "error cleanup" situation where object is not yet * in the list (object->next == NULL && object->prev == NULL) */ if (*list_head == object) { /* Object is the first one in the list */ if (object->next) { *list_head = object->next; object->next->prev = NULL; } else { /* Object is the only one in the list */ *list_head = NULL; } } else if (object->next != NULL || object->prev != NULL) { if (object->next) { object->prev->next = object->next; object->next->prev = object->prev; } else { /* Object is the last one in the list */ object->prev->next = NULL; } } if (!have_list_lock) { (void) pthread_rwlock_unlock(list_lock); } (void) pthread_rwlock_unlock(&meta_objectclose_lock); /* * Wait for anyone already using object to finish, by obtaining * a writer-lock (need to release our reader-lock first). Once we * get the write lock, we can just release it and finish cleaning * up the object. */ (void) pthread_rwlock_unlock(&object->object_lock); /* rdlock */ (void) pthread_rwlock_wrlock(&object->object_lock); (void) pthread_rwlock_unlock(&object->object_lock); /* wrlock */ return (CKR_OK); } /* * meta_object_dealloc * * Performs final object cleanup, releasing any allocated memory and * destroying any clones on other slots. Caller is assumed to have * called meta_object_deactivate() before this function. * * Caller is assumed to have only reference to object, but should have * released any lock. * * If "nukeSourceObj" argument is true, we will actually delete the * object from the underlying slot. */ CK_RV meta_object_dealloc(meta_session_t *session, meta_object_t *object, boolean_t nukeSourceObj) { CK_RV rv, save_rv = CKR_OK; CK_ULONG slotnum, num_slots; CK_ULONG i; /* First, delete all the clones of this object on other slots. */ num_slots = meta_slotManager_get_slotcount(); for (slotnum = 0; slotnum < num_slots; slotnum++) { slot_session_t *obj_session; slot_object_t *clone; clone = object->clones[slotnum]; if (clone == NULL) continue; if (nukeSourceObj || (!object->isToken && !(object->isFreeToken == FREE_ENABLED && get_keystore_slotnum() == slotnum))) { rv = meta_get_slot_session(slotnum, &obj_session, (session == NULL) ? object->creator_session->session_flags : session->session_flags); if (rv == CKR_OK) { rv = FUNCLIST(obj_session->fw_st_id)->\ C_DestroyObject(obj_session->hSession, clone->hObject); meta_release_slot_session(obj_session); if ((rv != CKR_OK) && (save_rv == CKR_OK)) { save_rv = rv; } } } meta_slot_object_deactivate(clone); meta_slot_object_dealloc(clone); object->clones[slotnum] = NULL; } /* Now erase and delete any attributes in the metaobject. */ dealloc_attributes(object->attributes, object->num_attributes); free(object->clones); free(object->tried_create_clone); if (object->clone_template) { for (i = 0; i < object->clone_template_size; i++) { freezero((object->clone_template)[i].pValue, (object->clone_template)[i].ulValueLen); } free(object->clone_template); } /* Cleanup remaining object fields. */ (void) pthread_rwlock_destroy(&object->object_lock); (void) pthread_rwlock_destroy(&object->attribute_lock); (void) pthread_mutex_destroy(&object->isClosingObject_lock); (void) pthread_mutex_destroy(&object->clone_create_lock); meta_object_delay_free(object); return (save_rv); } /* * meta_slot_object_alloc */ CK_RV meta_slot_object_alloc(slot_object_t **object) { slot_object_t *new_object; new_object = calloc(1, sizeof (slot_object_t)); if (new_object == NULL) return (CKR_HOST_MEMORY); *object = new_object; return (CKR_OK); } /* * meta_slot_object_activate */ void meta_slot_object_activate(slot_object_t *object, slot_session_t *creator_session, boolean_t isToken) { object->creator_session = creator_session; if (isToken) { extern slot_data_t *slots; slot_data_t *slot; slot = &(slots[object->creator_session->slotnum]); (void) pthread_rwlock_wrlock(&slot->tokenobject_list_lock); INSERT_INTO_LIST(slot->tokenobject_list_head, object); (void) pthread_rwlock_unlock(&slot->tokenobject_list_lock); } else { slot_session_t *session = object->creator_session; /* Add to session's list of session objects. */ (void) pthread_rwlock_wrlock(&session->object_list_lock); INSERT_INTO_LIST(session->object_list_head, object); (void) pthread_rwlock_unlock(&session->object_list_lock); } /* * This set tells the slot object that we are in the token list, * but does not cause harm with the metaobject knowing the object * isn't a token, but a freetoken */ object->isToken = isToken; } /* * meta_slot_object_deactivate * * Remove the specified slot object from the appropriate object list. */ void meta_slot_object_deactivate(slot_object_t *object) { slot_object_t **list_head; pthread_rwlock_t *list_lock; if (object->isToken) { extern slot_data_t *slots; slot_data_t *slot; slot = &(slots[object->creator_session->slotnum]); list_head = &slot->tokenobject_list_head; list_lock = &slot->tokenobject_list_lock; } else { list_head = &object->creator_session->object_list_head; list_lock = &object->creator_session->object_list_lock; } (void) pthread_rwlock_wrlock(list_lock); REMOVE_FROM_LIST(*list_head, object); (void) pthread_rwlock_unlock(list_lock); } /* * meta_slot_object_dealloc */ void meta_slot_object_dealloc(slot_object_t *object) { /* Not much cleanup for slot objects, unlike meta objects... */ free(object); } /* * meta_object_copyin * * When a key is generated/derived/unwrapped, the attribute values * created by the token are not immediately read into our copy of the * attributes. We defer this work until we actually need to know. */ CK_RV meta_object_copyin(meta_object_t *object) { CK_RV rv = CKR_OK; slot_session_t *session = NULL; CK_ATTRIBUTE *attrs = NULL, *attrs_with_val = NULL; slot_object_t *slot_object = NULL; CK_ULONG num_attrs = 0, i, num_attrs_with_val; CK_SESSION_HANDLE hSession; CK_SLOT_ID fw_st_id; /* Make sure no one else is looking at attributes. */ (void) pthread_rwlock_wrlock(&object->attribute_lock); /* Did we just lose a copyin race with another thread */ if (object->attributes != NULL) { goto finish; } slot_object = object->clones[object->master_clone_slotnum]; rv = meta_get_slot_session(object->master_clone_slotnum, &session, object->creator_session->session_flags); if (rv != CKR_OK) { goto finish; } /* * first, get the master template of all the attributes * for this object */ rv = get_master_attributes_by_object(session, slot_object, &(object->attributes), &(object->num_attributes)); if (rv != CKR_OK) { goto finish; } /* * Get value for each attribute items. * * Some attributes are required by the given object type. * Some are optional. Get all the values first, and then * make sure we have value for all required values, */ attrs = calloc(object->num_attributes, sizeof (CK_ATTRIBUTE)); if (attrs == NULL) { rv = CKR_HOST_MEMORY; goto finish; } for (i = 0; i < object->num_attributes; i++) { attrs[i].type = ((object->attributes[i]).attribute).type; } num_attrs = object->num_attributes; hSession = session->hSession; fw_st_id = session->fw_st_id; /* first, call C_GetAttributeValue() to get size for each attribute */ rv = FUNCLIST(fw_st_id)->C_GetAttributeValue(hSession, slot_object->hObject, attrs, num_attrs); /* * If the return value is not CKR_OK, allow it to be * CKR_ATTRIBUTE_TYPE_INVALID for now. * Some attributes defined in PKCS#11 version 2.11 * might not be defined in earlier versions. We will * TRY to work with those providers if the attribute * is optional. */ if ((rv != CKR_OK) && (rv != CKR_ATTRIBUTE_TYPE_INVALID)) { rv = CKR_FUNCTION_FAILED; /* make sure rv is appropriate */ goto finish; } /* * allocate space. * Since we don't know how many attributes have * values at this time, just assume all of them * have values so we save one loop to count the number * of attributes that have value. */ attrs_with_val = calloc(num_attrs, sizeof (CK_ATTRIBUTE)); if (attrs_with_val == NULL) { rv = CKR_HOST_MEMORY; goto finish; } num_attrs_with_val = 0; for (i = 0; i < num_attrs; i++) { if (!(((CK_LONG)(attrs[i].ulValueLen)) > 0)) { /* if it isn't an optional attr, len should be > 0 */ if (!object->attributes[i].canBeEmptyValue) { rv = CKR_FUNCTION_FAILED; goto finish; } } else { attrs_with_val[num_attrs_with_val].type = attrs[i].type; attrs_with_val[num_attrs_with_val].ulValueLen = attrs[i].ulValueLen; attrs_with_val[num_attrs_with_val].pValue = malloc(attrs[i].ulValueLen); if (attrs_with_val[num_attrs_with_val].pValue == NULL) { rv = CKR_HOST_MEMORY; goto finish; } num_attrs_with_val++; } } rv = FUNCLIST(fw_st_id)->C_GetAttributeValue(hSession, slot_object->hObject, attrs_with_val, num_attrs_with_val); if (rv != CKR_OK) { goto finish; } /* store these values into the meta object */ for (i = 0; i < num_attrs_with_val; i++) { rv = attribute_set_value(&(attrs_with_val[i]), object->attributes, object->num_attributes); if (rv != CKR_OK) { goto finish; } } finish: (void) pthread_rwlock_unlock(&object->attribute_lock); if (session) meta_release_slot_session(session); if (attrs) { for (i = 0; i < num_attrs; i++) { if (attrs[i].pValue != NULL) { free(attrs[i].pValue); } } free(attrs); } if (attrs_with_val) { for (i = 0; i < num_attrs; i++) { if (attrs_with_val[i].pValue != NULL) { freezero(attrs_with_val[i].pValue, attrs_with_val[i].ulValueLen); } } free(attrs_with_val); } return (rv); } /* * Create an object to be used for wrapping and unwrapping. * The same template will be used for all wrapping/unwrapping keys all * the time */ static CK_RV create_wrap_unwrap_key(slot_session_t *slot_session, CK_OBJECT_HANDLE *hObject, wrap_info_t *wrap_info, char *key_data, CK_ULONG key_len) { CK_OBJECT_CLASS objclass; CK_KEY_TYPE keytype; CK_RV rv = CKR_OK; int i; CK_ATTRIBUTE template[WRAP_KEY_TEMPLATE_SIZE]; i = 0; objclass = wrap_info->class; template[i].type = CKA_CLASS; template[i].pValue = &objclass; template[i].ulValueLen = sizeof (objclass); i++; keytype = wrap_info->key_type; template[i].type = CKA_KEY_TYPE; template[i].pValue = &keytype; template[i].ulValueLen = sizeof (keytype); i++; template[i].type = CKA_TOKEN; template[i].pValue = &falsevalue; template[i].ulValueLen = sizeof (falsevalue); if (objclass == CKO_SECRET_KEY) { i++; template[i].type = CKA_VALUE; template[i].pValue = key_data; template[i].ulValueLen = key_len; i++; template[i].type = CKA_WRAP; template[i].pValue = &truevalue; template[i].ulValueLen = sizeof (truevalue); i++; template[i].type = CKA_UNWRAP; template[i].pValue = &truevalue; template[i].ulValueLen = sizeof (truevalue); } else { /* Modulus is the same for rsa public and private key */ i++; template[i].type = CKA_MODULUS; template[i].pValue = Modulus; template[i].ulValueLen = sizeof (Modulus); if (objclass == CKO_PUBLIC_KEY) { /* RSA public key */ i++; template[i].type = CKA_PUBLIC_EXPONENT; template[i].pValue = PubExpo; template[i].ulValueLen = sizeof (PubExpo); i++; template[i].type = CKA_WRAP; template[i].pValue = &truevalue; template[i].ulValueLen = sizeof (truevalue); } else { /* RSA private key */ i++; template[i].type = CKA_PRIVATE_EXPONENT; template[i].pValue = PriExpo; template[i].ulValueLen = sizeof (PriExpo); i++; template[i].type = CKA_UNWRAP; template[i].pValue = &truevalue; template[i].ulValueLen = sizeof (truevalue); } } rv = FUNCLIST(slot_session->fw_st_id)->C_CreateObject( slot_session->hSession, template, i + 1, hObject); return (rv); } /* * Create a clone of a non-sensitive and extractable object. * If the template required for creating the clone doesn't exist, * it will be retrieved from the master clone. */ static CK_RV clone_by_create(meta_object_t *object, slot_object_t *new_clone, slot_session_t *dst_slot_session) { CK_RV rv; int free_token_index = -1; if (object->attributes == NULL) { rv = meta_object_copyin(object); if (rv != CKR_OK) { return (rv); } } if (object->clone_template == NULL) { rv = meta_clone_template_setup(object, object->attributes, object->num_attributes); if (rv != CKR_OK) { return (rv); } } if (object->isFreeToken == FREE_ENABLED) { if (dst_slot_session->slotnum == get_keystore_slotnum()) free_token_index = set_template_boolean(CKA_TOKEN, object->clone_template, object->clone_template_size, B_FALSE, &truevalue); else free_token_index = set_template_boolean(CKA_TOKEN, object->clone_template, object->clone_template_size, B_FALSE, &falsevalue); } /* Create the clone... */ rv = FUNCLIST(dst_slot_session->fw_st_id)->C_CreateObject( dst_slot_session->hSession, object->clone_template, object->clone_template_size, &(new_clone->hObject)); if (free_token_index != -1) { free_token_index = set_template_boolean(CKA_TOKEN, object->clone_template, object->clone_template_size, B_FALSE, &falsevalue); } if (rv != CKR_OK) { return (rv); } return (CKR_OK); } /* * Goes through the list of wraping mechanisms, and returns the first * one that is supported by both the source and the destination slot. * If none of the mechanisms are supported by both slot, return the * first mechanism that's supported by the source slot */ static CK_RV find_best_match_wrap_mech(wrap_info_t *wrap_info, int num_info, CK_ULONG src_slotnum, CK_ULONG dst_slotnum, int *first_both_mech, int *first_src_mech) { int i; boolean_t src_supports, dst_supports; CK_RV rv; CK_MECHANISM_INFO mech_info; mech_info.flags = CKF_WRAP; for (i = 0; i < num_info; i++) { src_supports = B_FALSE; dst_supports = B_FALSE; rv = meta_mechManager_slot_supports_mech( (wrap_info[i]).mech_type, src_slotnum, &src_supports, NULL, B_FALSE, &mech_info); if (rv != CKR_OK) { return (rv); } rv = meta_mechManager_slot_supports_mech( (wrap_info[i]).mech_type, dst_slotnum, &dst_supports, NULL, B_FALSE, &mech_info); if (rv != CKR_OK) { return (rv); } /* both source and destination supports the mech */ if ((src_supports) && (dst_supports)) { *first_both_mech = i; return (CKR_OK); } if ((src_supports) && (*first_src_mech == -1)) { *first_src_mech = i; } } return (CKR_OK); } /* * Determine the wrapping/unwrapping mechanism to be used * * If possible, select a mechanism that's supported by both source * and destination slot. If none of the mechanisms are supported * by both slot, then, select the first one supported by * the source slot. */ static CK_RV get_wrap_mechanism(CK_OBJECT_CLASS obj_class, CK_KEY_TYPE key_type, CK_ULONG src_slotnum, CK_ULONG dst_slotnum, wrap_info_t *wrap_info) { wrap_info_t *wrap_info_to_search = NULL; unsigned int num_wrap_info; CK_RV rv; int i; boolean_t src_supports = B_FALSE, dst_supports = B_FALSE; int first_src_mech, rsa_first_src_mech, first_both_mech; CK_MECHANISM_INFO mech_info; mech_info.flags = CKF_WRAP; if ((obj_class == CKO_PRIVATE_KEY) && (key_type == CKK_KEA)) { /* * only SKIPJACK keys can be used for wrapping * KEA private keys */ for (i = 0; i < num_special_wrap_info; i++) { if ((special_wrap_info[i]).mech_type != CKM_SKIPJACK_WRAP) { continue; } src_supports = B_FALSE; dst_supports = B_FALSE; rv = meta_mechManager_slot_supports_mech( (special_wrap_info[i]).mech_type, src_slotnum, &src_supports, NULL, B_FALSE, &mech_info); if (rv != CKR_OK) { goto finish; } rv = meta_mechManager_slot_supports_mech( (special_wrap_info[i]).mech_type, dst_slotnum, &dst_supports, NULL, B_FALSE, &mech_info); if (rv != CKR_OK) { goto finish; } if (src_supports) { /* * both src and dst supports the mech or * only the src supports the mech */ (void) memcpy(wrap_info, &(special_wrap_info[i]), sizeof (wrap_info_t)); wrap_info->src_supports = src_supports; wrap_info->dst_supports = dst_supports; rv = CKR_OK; goto finish; } } /* * if we are here, that means neither the source slot * nor the destination slots supports CKM_SKIPJACK_WRAP. */ rv = CKR_FUNCTION_FAILED; goto finish; } if ((key_type == CKK_SKIPJACK) || (key_type == CKK_BATON) || (key_type == CKK_JUNIPER)) { /* special key types */ wrap_info_to_search = special_wrap_info; num_wrap_info = num_special_wrap_info; } else { /* use the regular wrapping mechanisms */ wrap_info_to_search = common_wrap_info; num_wrap_info = num_common_wrap_info; } first_both_mech = -1; first_src_mech = -1; rv = find_best_match_wrap_mech(wrap_info_to_search, num_wrap_info, src_slotnum, dst_slotnum, &first_both_mech, &first_src_mech); if (rv != CKR_OK) { goto finish; } if (first_both_mech != -1) { (void) memcpy(wrap_info, &(wrap_info_to_search[first_both_mech]), sizeof (wrap_info_t)); wrap_info->src_supports = B_TRUE; wrap_info->dst_supports = B_TRUE; rv = CKR_OK; goto finish; } /* * If we are here, we did not find a mechanism that's supported * by both source and destination slot. * * If it is a secret key, can also try to wrap it with * a RSA public key */ if (obj_class == CKO_SECRET_KEY) { first_both_mech = -1; rsa_first_src_mech = -1; rv = find_best_match_wrap_mech(rsa_wrap_info, num_rsa_wrap_info, src_slotnum, dst_slotnum, &first_both_mech, &rsa_first_src_mech); if (rv != CKR_OK) { goto finish; } if (first_both_mech > -1) { (void) memcpy(wrap_info, &(rsa_wrap_info[first_both_mech]), sizeof (wrap_info_t)); wrap_info->src_supports = B_TRUE; wrap_info->dst_supports = B_TRUE; rv = CKR_OK; goto finish; } } /* * if we are here, that means none of the mechanisms are supported * by both the source and the destination */ if (first_src_mech > -1) { /* source slot support one of the secret key mechs */ (void) memcpy(wrap_info, &(wrap_info_to_search[first_src_mech]), sizeof (wrap_info_t)); wrap_info->src_supports = B_TRUE; wrap_info->dst_supports = B_FALSE; rv = CKR_OK; } else if (rsa_first_src_mech > -1) { /* source slot support one of the RSA mechs */ (void) memcpy(wrap_info, &(rsa_wrap_info[rsa_first_src_mech]), sizeof (wrap_info_t)); wrap_info->src_supports = B_TRUE; wrap_info->dst_supports = B_FALSE; rv = CKR_OK; } else { /* neither source nor destination support any wrap mechs */ rv = CKR_FUNCTION_FAILED; } finish: return (rv); } /* * This is called if the object to be cloned is a sensitive object */ static CK_RV clone_by_wrap(meta_object_t *object, slot_object_t *new_clone, slot_session_t *dst_slot_session) { slot_session_t *src_slot_session = NULL; CK_OBJECT_HANDLE wrappingKey = 0, unwrappingKey = 0; CK_MECHANISM wrappingMech; CK_BYTE *wrappedKey = NULL; CK_ULONG wrappedKeyLen = 0; slot_object_t *slot_object = NULL; CK_RV rv = CKR_OK; CK_OBJECT_HANDLE unwrapped_obj; meta_object_t *tmp_meta_obj = NULL; slot_object_t *tmp_slot_obj = NULL; CK_OBJECT_CLASS obj_class; CK_KEY_TYPE key_type; meta_session_t *tmp_meta_session = NULL; CK_ATTRIBUTE unwrap_template[4]; char key_data[1024]; /* should be big enough for any key size */ char ivbuf[1024]; /* should be big enough for any mech */ wrap_info_t wrap_info; CK_ULONG key_len, unwrap_template_size; slot_object = object->clones[object->master_clone_slotnum]; rv = meta_get_slot_session(object->master_clone_slotnum, &src_slot_session, object->creator_session->session_flags); if (rv != CKR_OK) { return (rv); } /* * get the object class and key type for unwrap template * This information will also be used for determining * which wrap mechanism and which key to use for * doing the wrapping */ unwrap_template[0].type = CKA_CLASS; unwrap_template[0].pValue = &obj_class; unwrap_template[0].ulValueLen = sizeof (obj_class); unwrap_template[1].type = CKA_KEY_TYPE; unwrap_template[1].pValue = &key_type; unwrap_template[1].ulValueLen = sizeof (key_type); rv = FUNCLIST(src_slot_session->fw_st_id)->C_GetAttributeValue( src_slot_session->hSession, slot_object->hObject, unwrap_template, 2); if (rv != CKR_OK) { goto finish; } rv = get_wrap_mechanism(obj_class, key_type, src_slot_session->slotnum, dst_slot_session->slotnum, &wrap_info); if (rv != CKR_OK) { goto finish; } /* * read number of bytes required from random device for * creating a secret key for wrapping and unwrapping */ if (wrap_info.class == CKO_SECRET_KEY) { /* * /dev/urandom will be used for generating the key used * for doing the wrap/unwrap. It's should be ok to * use /dev/urandom because this key is used for this * one time operation only. It doesn't need to be stored. */ key_len = wrap_info.key_length; if (pkcs11_get_urandom(key_data, key_len) < 0) { rv = CKR_FUNCTION_FAILED; goto finish; } if (wrap_info.iv_length > 0) { if (pkcs11_get_urandom( ivbuf, wrap_info.iv_length) < 0) { rv = CKR_FUNCTION_FAILED; goto finish; } } } /* create the wrapping key */ rv = create_wrap_unwrap_key(src_slot_session, &wrappingKey, &wrap_info, key_data, key_len); if (rv != CKR_OK) { goto finish; } wrappingMech.mechanism = wrap_info.mech_type; wrappingMech.pParameter = ((wrap_info.iv_length > 0) ? ivbuf : NULL); wrappingMech.ulParameterLen = wrap_info.iv_length; /* get the size of the wrapped key */ rv = FUNCLIST(src_slot_session->fw_st_id)->C_WrapKey( src_slot_session->hSession, &wrappingMech, wrappingKey, slot_object->hObject, NULL, &wrappedKeyLen); if (rv != CKR_OK) { goto finish; } wrappedKey = malloc(wrappedKeyLen * sizeof (CK_BYTE)); if (wrappedKey == NULL) { rv = CKR_HOST_MEMORY; goto finish; } /* do the actual key wrapping */ rv = FUNCLIST(src_slot_session->fw_st_id)->C_WrapKey( src_slot_session->hSession, &wrappingMech, wrappingKey, slot_object->hObject, wrappedKey, &wrappedKeyLen); if (rv != CKR_OK) { goto finish; } /* explicitly force the unwrapped object to be not sensitive */ unwrap_template[2].type = CKA_SENSITIVE; unwrap_template[2].pValue = &falsevalue; unwrap_template[2].ulValueLen = sizeof (falsevalue); unwrap_template[3].type = CKA_TOKEN; unwrap_template[3].pValue = &falsevalue; unwrap_template[3].ulValueLen = sizeof (falsevalue); unwrap_template_size = sizeof (unwrap_template) / sizeof (CK_ATTRIBUTE); if (!wrap_info.dst_supports) { /* * if we know for sure that the destination slot doesn't * support the wrapping mechanism, no point in trying. * go directly to unwrap in source slot, and create key * in destination */ goto unwrap_in_source; } /* create the unwrapping key in destination slot */ if (wrap_info.key_type == CKK_RSA) { /* for RSA key, the unwrapping key need to be private key */ wrap_info.class = CKO_PRIVATE_KEY; } rv = create_wrap_unwrap_key(dst_slot_session, &unwrappingKey, &wrap_info, key_data, key_len); if (rv != CKR_OK) { goto finish; } rv = FUNCLIST(dst_slot_session->fw_st_id)->C_UnwrapKey( dst_slot_session->hSession, &wrappingMech, unwrappingKey, wrappedKey, wrappedKeyLen, unwrap_template, unwrap_template_size, &(new_clone->hObject)); if (rv != CKR_OK) { unwrap_in_source: /* * There seemed to be a problem with unwrapping in the * destination slot. * Try to do the unwrap in the src slot so it becomes * a non-sensitive object, then, get all the attributes * and create the object in the destination slot */ if (wrap_info.class == CKO_SECRET_KEY) { /* unwrap with same key used for wrapping */ rv = FUNCLIST(src_slot_session->fw_st_id)->C_UnwrapKey( src_slot_session->hSession, &wrappingMech, wrappingKey, wrappedKey, wrappedKeyLen, unwrap_template, unwrap_template_size, &(unwrapped_obj)); } else { /* * If the object is wrapping with RSA public key, need * need to create RSA private key for unwrapping */ wrap_info.class = CKO_PRIVATE_KEY; rv = create_wrap_unwrap_key(src_slot_session, &unwrappingKey, &wrap_info, key_data, key_len); if (rv != CKR_OK) { goto finish; } rv = FUNCLIST(src_slot_session->fw_st_id)->C_UnwrapKey( src_slot_session->hSession, &wrappingMech, unwrappingKey, wrappedKey, wrappedKeyLen, unwrap_template, unwrap_template_size, &(unwrapped_obj)); } if (rv != CKR_OK) { goto finish; } rv = meta_session_alloc(&tmp_meta_session); if (rv != CKR_OK) { goto finish; } tmp_meta_session->session_flags = CKF_SERIAL_SESSION; rv = meta_object_alloc(tmp_meta_session, &tmp_meta_obj); if (rv != CKR_OK) { goto finish; } rv = meta_slot_object_alloc(&tmp_slot_obj); if (rv != CKR_OK) { goto finish; } tmp_meta_obj->master_clone_slotnum = src_slot_session->slotnum; tmp_slot_obj->hObject = unwrapped_obj; tmp_meta_obj->clones[tmp_meta_obj->master_clone_slotnum] = tmp_slot_obj; meta_slot_object_activate(tmp_slot_obj, src_slot_session, B_FALSE); tmp_slot_obj = NULL; rv = clone_by_create(tmp_meta_obj, new_clone, dst_slot_session); if (rv != CKR_OK) { goto finish; } } finish: if (unwrappingKey) { (void) FUNCLIST(dst_slot_session->fw_st_id)->C_DestroyObject( dst_slot_session->hSession, unwrappingKey); } if (wrappingKey) { (void) FUNCLIST(src_slot_session->fw_st_id)->C_DestroyObject( src_slot_session->hSession, wrappingKey); } if (tmp_slot_obj) { (void) meta_slot_object_dealloc(tmp_slot_obj); } if (tmp_meta_obj) { (void) meta_object_dealloc(tmp_meta_session, tmp_meta_obj, B_TRUE); } if (tmp_meta_session) { (void) meta_session_dealloc(tmp_meta_session); } if (wrappedKey) { freezero(wrappedKey, wrappedKeyLen); } if (src_slot_session) { meta_release_slot_session(src_slot_session); } return (rv); } /* * meta_object_get_clone * * Creates a "clone" of a metaobject on the specified slot. A clone is a * copy of the object. * * Clones are cached, so that they can be reused with subsequent operations. */ CK_RV meta_object_get_clone(meta_object_t *object, CK_ULONG slot_num, slot_session_t *slot_session, slot_object_t **clone) { CK_RV rv = CKR_OK; slot_object_t *newclone = NULL; /* Does a clone already exist? */ if (object->clones[slot_num] != NULL) { *clone = object->clones[slot_num]; return (CKR_OK); } if ((object->isSensitive) && (object->isToken) && (!metaslot_auto_key_migrate)) { /* * if the object is a sensitive token object, and auto * key migrate is not allowed, will not create the clone * in another slot */ return (CKR_FUNCTION_FAILED); } /* object attributes can't be extracted and attributes are not known */ if ((!object->isExtractable) && (object->attributes == NULL)) { return (CKR_FUNCTION_FAILED); } (void) pthread_mutex_lock(&object->clone_create_lock); /* Maybe someone just created one? */ if (object->clones[slot_num] != NULL) { *clone = object->clones[slot_num]; goto finish; } /* * has an attempt already been made to create this object in * slot? If yes, and there's no clone, as indicated above, * that means this object can't be created in this slot. */ if (object->tried_create_clone[slot_num]) { (void) pthread_mutex_unlock(&object->clone_create_lock); return (CKR_FUNCTION_FAILED); } rv = meta_slot_object_alloc(&newclone); if (rv != CKR_OK) goto finish; object->tried_create_clone[slot_num] = B_TRUE; /* * If this object is sensitive and we do not have not copied in the * attributes via FreeObject functionality, then we need to wrap it off * the provider. If we do have attributes, we can just create the * clone */ if (object->isSensitive && object->attributes == NULL) { rv = clone_by_wrap(object, newclone, slot_session); } else { rv = clone_by_create(object, newclone, slot_session); } if (rv != CKR_OK) { goto finish; } object->clones[slot_num] = newclone; meta_slot_object_activate(newclone, slot_session, object->isToken); *clone = newclone; newclone = NULL; finish: (void) pthread_mutex_unlock(&object->clone_create_lock); if (newclone) meta_slot_object_dealloc(newclone); return (rv); } /* * meta_setup_clone_template * * Create a clone template for the specified object. */ static CK_RV meta_clone_template_setup(meta_object_t *object, const generic_attr_t *attributes, size_t num_attributes) { CK_RV rv = CKR_OK; CK_ATTRIBUTE *clone_template; size_t i, c = 0; clone_template = malloc(num_attributes * sizeof (CK_ATTRIBUTE)); if (clone_template == NULL) { rv = CKR_HOST_MEMORY; goto finish; } /* Don't allow attributes to change while we look at them. */ (void) pthread_rwlock_rdlock(&object->attribute_lock); for (i = 0; i < num_attributes; i++) { if (!attributes[i].isCloneAttr || (attributes[i].attribute.type == CKA_TOKEN && object->isFreeToken == FREE_DISABLED)) { continue; } if ((!(attributes[i].hasValueForClone)) && (attributes[i].canBeEmptyValue)) { continue; } clone_template[c].type = attributes[i].attribute.type; clone_template[c].ulValueLen = attributes[i].attribute.ulValueLen; /* Allocate space to store the attribute value. */ clone_template[c].pValue = malloc(clone_template[c].ulValueLen); if (clone_template[c].pValue == NULL) { free(clone_template); rv = CKR_HOST_MEMORY; (void) pthread_rwlock_unlock(&object->attribute_lock); goto finish; } (void) memcpy(clone_template[c].pValue, object->attributes[i].attribute.pValue, clone_template[c].ulValueLen); c++; } (void) pthread_rwlock_unlock(&object->attribute_lock); object->clone_template = clone_template; object->clone_template_size = c; finish: return (rv); } /* * meta_object_find_by_handle * * Search for an existing metaobject, using the object handle of a clone * on a particular slot. * * Returns a matching metaobject, or NULL if no match was found. */ meta_object_t * meta_object_find_by_handle(CK_OBJECT_HANDLE hObject, CK_ULONG slotnum, boolean_t token_only) { meta_object_t *object = NULL, *tmp_obj; meta_session_t *session; if (!token_only) { (void) pthread_rwlock_rdlock(&meta_sessionlist_lock); session = meta_sessionlist_head; while (session != NULL) { /* lock the objects list while we look at it */ (void) pthread_rwlock_rdlock( &(session->object_list_lock)); tmp_obj = session->object_list_head; while (tmp_obj != NULL) { slot_object_t *slot_object; (void) pthread_rwlock_rdlock( &(tmp_obj->object_lock)); slot_object = tmp_obj->clones[slotnum]; if (slot_object != NULL) { if (slot_object->hObject == hObject) { object = tmp_obj; } } (void) pthread_rwlock_unlock( &(tmp_obj->object_lock)); if (object != NULL) { break; } tmp_obj = tmp_obj->next; } (void) pthread_rwlock_unlock( &(session->object_list_lock)); if (object != NULL) { break; } session = session->next; } (void) pthread_rwlock_unlock(&meta_sessionlist_lock); } if (object != NULL) { /* found the object, no need to look further */ return (object); } /* * Look at list of token objects */ (void) pthread_rwlock_rdlock(&tokenobject_list_lock); tmp_obj = tokenobject_list_head; while (tmp_obj != NULL) { slot_object_t *slot_object; (void) pthread_rwlock_rdlock(&(tmp_obj->object_lock)); slot_object = tmp_obj->clones[slotnum]; if (slot_object != NULL) { if (slot_object->hObject == hObject) object = tmp_obj; } (void) pthread_rwlock_unlock(&(tmp_obj->object_lock)); if (object != NULL) { break; } tmp_obj = tmp_obj->next; } (void) pthread_rwlock_unlock(&tokenobject_list_lock); return (object); } CK_RV meta_token_object_deactivate(token_obj_type_t token_type) { meta_object_t *object, *tmp_object; CK_RV save_rv = CKR_OK, rv; /* get a write lock on the token object list */ (void) pthread_rwlock_wrlock(&tokenobject_list_lock); object = tokenobject_list_head; /* go through each object and delete the one with matching type */ while (object != NULL) { tmp_object = object->next; if ((token_type == ALL_TOKEN) || ((object->isPrivate) && (token_type == PRIVATE_TOKEN)) || ((!object->isPrivate) && (token_type == PUBLIC_TOKEN))) { rv = meta_object_deactivate(object, B_TRUE, B_FALSE); if ((rv != CKR_OK) && (save_rv == CKR_OK)) { save_rv = rv; goto finish; } rv = meta_object_dealloc(NULL, object, B_FALSE); if ((rv != CKR_OK) && (save_rv == CKR_OK)) { save_rv = rv; goto finish; } } object = tmp_object; } finish: (void) pthread_rwlock_unlock(&tokenobject_list_lock); return (save_rv); } /* * This function adds the to-be-freed meta object to a linked list. * When the number of objects queued in the linked list reaches the * maximum threshold MAX_OBJ_TO_BE_FREED, it will free the first * object (FIFO) in the list. */ void meta_object_delay_free(meta_object_t *objp) { meta_object_t *tmp; (void) pthread_mutex_lock(&obj_delay_freed.obj_to_be_free_mutex); /* Add the newly deleted object at the end of the list */ objp->next = NULL; if (obj_delay_freed.first == NULL) { obj_delay_freed.last = objp; obj_delay_freed.first = objp; } else { obj_delay_freed.last->next = objp; obj_delay_freed.last = objp; } if (++obj_delay_freed.count >= MAX_OBJ_TO_BE_FREED) { /* * Free the first object in the list only if * the total count reaches maximum threshold. */ obj_delay_freed.count--; tmp = obj_delay_freed.first->next; free(obj_delay_freed.first); obj_delay_freed.first = tmp; } (void) pthread_mutex_unlock(&obj_delay_freed.obj_to_be_free_mutex); } /* * This function checks if the object passed can be a freeobject. * * If there is more than one provider that supports the supported freeobject * mechanisms then allow freeobjects to be an option. */ boolean_t meta_freeobject_check(meta_session_t *session, meta_object_t *object, CK_MECHANISM *pMech, CK_ATTRIBUTE *tmpl, CK_ULONG tmpl_len, CK_KEY_TYPE keytype) { mech_support_info_t *info = &(session->mech_support_info); /* * If key migration is turned off, or the object does not has any of * the required flags and there is only one slot, then we don't need * FreeObjects. */ if (!metaslot_auto_key_migrate || (!object->isToken && !object->isSensitive && meta_slotManager_get_slotcount() < 2)) goto failure; /* * If this call is for key generation, check pMech for supported * FreeObject mechs */ if (pMech != NULL) { if (pMech->mechanism == CKM_RSA_PKCS_KEY_PAIR_GEN || pMech->mechanism == CKM_EC_KEY_PAIR_GEN || pMech->mechanism == CKM_DH_PKCS_KEY_PAIR_GEN || pMech->mechanism == CKM_DH_PKCS_DERIVE) info->mech = pMech->mechanism; else goto failure; /* * If this call is for an object creation, look inside the template * for supported FreeObject mechs */ } else if (tmpl_len > 0) { if (!get_template_ulong(CKA_KEY_TYPE, tmpl, tmpl_len, &keytype)) goto failure; switch (keytype) { case CKK_RSA: info->mech = CKM_RSA_PKCS_KEY_PAIR_GEN; break; case CKK_EC: info->mech = CKM_EC_KEY_PAIR_GEN; break; case CKK_DH: info->mech = CKM_DH_PKCS_KEY_PAIR_GEN; break; default: goto failure; } } else goto failure; /* Get the slot that support this mech... */ if (meta_mechManager_get_slots(info, B_FALSE, NULL) != CKR_OK) goto failure; /* * If there is only one slot with the mech or the first slot in * the list is the keystore slot, we should bail. */ if (info->num_supporting_slots < 2 && info->supporting_slots[0]->slotnum == get_keystore_slotnum()) goto failure; if (object->isToken) object->isFreeToken = FREE_ALLOWED_KEY; else object->isFreeToken = FREE_DISABLED; object->isFreeObject = FREE_ALLOWED_KEY; return (B_TRUE); failure: object->isFreeToken = FREE_DISABLED; object->isFreeObject = FREE_DISABLED; return (B_FALSE); } /* * This function assumes meta_freeobject_check() has just been called and set * the isFreeObject and/or isFreeToken vars to FREE_ALLOWED_KEY. * * If the template value for CKA_PRIVATE, CKA_SENSITIVE and/or CKA_TOKEN are * true, then isFreeObject is fully enabled. In addition isFreeToken is * enabled if is CKA_TOKEN true. * * If create is true, we are doing a C_CreateObject operation and don't * handle CKA_PRIVATE & CKA_SENSITIVE flags, we only care about CKA_TOKEN. */ boolean_t meta_freeobject_set(meta_object_t *object, CK_ATTRIBUTE *tmpl, CK_ULONG tmpl_len, boolean_t create) { /* This check should never be true, if it is, it's a bug */ if (object->isFreeObject < FREE_ALLOWED_KEY) return (B_FALSE); if (!create) { /* Turn off the Sensitive flag */ if (object->isSensitive) { if (set_template_boolean(CKA_SENSITIVE, tmpl, tmpl_len, B_TRUE, &falsevalue) == -1) goto failure; object->isFreeObject = FREE_ENABLED; } /* Turn off the Private flag */ if (object->isPrivate) { if (set_template_boolean(CKA_PRIVATE, tmpl, tmpl_len, B_TRUE, &falsevalue) == -1) goto failure; object->isFreeObject = FREE_ENABLED; } } if (object->isToken) { object->isToken = B_FALSE; object->isFreeToken = FREE_ENABLED; object->isFreeObject = FREE_ENABLED; } else object->isFreeToken = FREE_DISABLED; /* * If isFreeObject is not in the FREE_ENABLED state yet, it can be * turned off because the object doesn't not need to be a FreeObject. */ if (object->isFreeObject == FREE_ALLOWED_KEY) object->isFreeObject = FREE_DISABLED; return (B_TRUE); failure: object->isFreeToken = FREE_DISABLED; object->isFreeObject = FREE_DISABLED; return (B_FALSE); } /* * This function sets the CKA_TOKEN flag on a given object template depending * if the slot being used is a keystore. * * If the object is a token, but the slot is not the system keystore or has * no keystore, then set the template to token = false; otherwise it's true. * In addition we know ahead of time what the value is, so if the value is * already correct, bypass the setting function */ CK_RV meta_freetoken_set(CK_ULONG slot_num, CK_BBOOL *current_value, CK_ATTRIBUTE *tmpl, CK_ULONG tmpl_len) { if (slot_num == get_keystore_slotnum()) { if (*current_value == TRUE) return (CKR_OK); if (set_template_boolean(CKA_TOKEN, tmpl, tmpl_len, B_TRUE, &truevalue) == -1) return (CKR_FUNCTION_FAILED); } else { if (*current_value == FALSE) return (CKR_OK); if (set_template_boolean(CKA_TOKEN, tmpl, tmpl_len, B_TRUE, &falsevalue) == -1) return (CKR_FUNCTION_FAILED); *current_value = FALSE; } return (CKR_OK); } /* * Cloning function for meta_freeobject_clone() to use. This function * is streamlined because we know what the object is and this should * not be called as a generic cloner. */ static CK_RV meta_freeobject_clone_maker(meta_session_t *session, meta_object_t *object, CK_ULONG slotnum) { slot_object_t *slot_object = NULL; slot_session_t *slot_session = NULL; CK_RV rv; rv = meta_slot_object_alloc(&slot_object); if (rv != CKR_OK) goto cleanup; rv = meta_get_slot_session(slotnum, &slot_session, session->session_flags); if (rv != CKR_OK) goto cleanup; rv = clone_by_create(object, slot_object, slot_session); if (rv == CKR_OK) { object->clones[slotnum] = slot_object; meta_slot_object_activate(slot_object, slot_session, B_TRUE); } cleanup: meta_release_slot_session(slot_session); return (rv); } /* * This function is called when a object is a FreeObject. * * What we are given is an object that has been generated on a provider * that is not its final usage place. That maybe because: * 1) it's a token and needs to be stored in keystore. * 2) it was to be a private/sensitive object that we modified so we could know * the important attributes for cloning before we make it private/sensitive. */ boolean_t meta_freeobject_clone(meta_session_t *session, meta_object_t *object) { CK_RV rv; CK_ULONG keystore_slotnum; CK_ATTRIBUTE attr[2]; boolean_t failover = B_FALSE; if (object->attributes == NULL) { rv = meta_object_copyin(object); if (rv != CKR_OK) return (rv); } if (object->isPrivate) { CK_OBJECT_HANDLE new_clone; CK_ULONG slotnum = object->master_clone_slotnum; slot_session_t *slot_session; attr[0].type = CKA_PRIVATE; attr[0].pValue = &truevalue; attr[0].ulValueLen = sizeof (truevalue); /* Set the master attribute list */ rv = attribute_set_value(attr, object->attributes, object->num_attributes); if (rv > 0) return (CKR_FUNCTION_FAILED); /* Get a slot session */ rv = meta_get_slot_session(slotnum, &slot_session, session->session_flags); if (rv > 0) return (rv); /* Create the new CKA_PRIVATE one */ rv = FUNCLIST(slot_session->fw_st_id)->\ C_CopyObject(slot_session->hSession, object->clones[slotnum]->hObject, attr, 1, &new_clone); if (rv == CKR_USER_NOT_LOGGED_IN) { /* * If the CopyObject fails, we may be using a provider * that has a keystore that is not the default * keystore set in metaslot or has object management * abilities. In which case we should write this * object to metaslot's keystore and let the failover. * rest of the function know we've changed providers. */ failover = B_TRUE; keystore_slotnum = get_keystore_slotnum(); if (object->clones[keystore_slotnum] == NULL) { rv = meta_freeobject_clone_maker(session, object, keystore_slotnum); if (rv != CKR_OK) { goto failure; } } object->master_clone_slotnum = keystore_slotnum; } else if (rv != CKR_OK) { meta_release_slot_session(slot_session); goto failure; } /* Remove the old object */ rv = FUNCLIST(slot_session->fw_st_id)-> \ C_DestroyObject(slot_session->hSession, object->clones[slotnum]->hObject); if (rv != CKR_OK) { meta_release_slot_session(slot_session); goto failure; } if (!failover) object->clones[slotnum]->hObject = new_clone; else object->clones[slotnum] = NULL; meta_release_slot_session(slot_session); } if (object->isSensitive) { slot_session_t *slot_session; CK_ULONG slotnum = object->master_clone_slotnum; attr[0].type = CKA_SENSITIVE; attr[0].pValue = &truevalue; attr[0].ulValueLen = sizeof (truevalue); rv = attribute_set_value(attr, object->attributes, object->num_attributes); if (rv != CKR_OK) goto failure; rv = meta_get_slot_session(slotnum, &slot_session, session->session_flags); if (rv == CKR_OK) { rv = FUNCLIST(slot_session->fw_st_id)-> \ C_SetAttributeValue(slot_session->hSession, object->clones[slotnum]->hObject, attr, 1); meta_release_slot_session(slot_session); } } if (object->isFreeToken == FREE_ENABLED || failover) { keystore_slotnum = get_keystore_slotnum(); if (object->clones[keystore_slotnum] == NULL) { rv = meta_freeobject_clone_maker(session, object, keystore_slotnum); if (rv != CKR_OK) goto failure; object->master_clone_slotnum = keystore_slotnum; } object->isFreeToken = FREE_ENABLED; } object->isFreeObject = FREE_ENABLED; return (CKR_OK); failure: object->isFreeToken = FREE_DISABLED; object->isFreeObject = FREE_DISABLED; return (rv); } /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Random Number Generation Functions * (as defined in PKCS#11 spec section 11.15) * */ #include #include #include #include #include #include "metaGlobal.h" /* * meta_SeedRandom * * Unlike most other metaslot functions, meta_SeedRandom does not distribute * the call to a specific provider. Rather, we assume that the /dev/urandom * implementation is a kCF consumer, and is pulling randomness from everywhere * it can. Thus, by seeding /dev/urandom we let kCF potentially do all the * work. * * NOTES: * 1) /dev/urandom vs. /dev/random... Unfortunately P11 does not allow app * to request a "quality", so we'll just assume urandom is good enough. * Concerned apps can pull hardcore randomness from specific places they * trust (eg by checking for CKF_HW?).. * */ CK_RV meta_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen) { CK_RV rv; meta_session_t *session; if (pSeed == NULL || ulSeedLen == 0) return (CKR_ARGUMENTS_BAD); /* Just check handle for validity, we don't need it for anything. */ rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); REFRELEASE(session); if (pkcs11_seed_urandom(pSeed, ulSeedLen) < 0) { if (errno == EACCES) return (CKR_RANDOM_SEED_NOT_SUPPORTED); return (CKR_DEVICE_ERROR); } return (CKR_OK); } /* * meta_GenerateRandom * * Unlike most other metaslot functions, meta_GenerateRandom does not distribute * the call to a specific provider. Rather, we assume that the /dev/urandom * implementation is a kCF consumer, and is pulling randomness from everywhere * it can. Thus, by reading /dev/urandom we let kCF potentially do all the * work. * */ CK_RV meta_GenerateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen) { CK_RV rv; meta_session_t *session; if (pRandomData == NULL || ulRandomLen < 1) return (CKR_ARGUMENTS_BAD); /* Just check handle for validity, we don't need it for anything. */ rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); REFRELEASE(session); if (pkcs11_get_urandom(pRandomData, ulRandomLen) < 0) { return (CKR_DEVICE_ERROR); } return (CKR_OK); } /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Session Management Functions * (as defined in PKCS#11 spec spection 11.6) */ #include #include "metaGlobal.h" extern meta_session_t *meta_sessionlist_head; extern pthread_rwlock_t meta_sessionlist_lock; extern CK_ULONG num_meta_sessions; extern CK_ULONG num_rw_meta_sessions; /* * meta_OpenSession * * NOTES: * 1) The pApplication and Notify args are not used, as the metaslot does not * support application callbacks. * 2) the slotID argument is not checked or used because this function * is only called from the framework. */ /* ARGSUSED */ CK_RV meta_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession) { meta_session_t *new_session; CK_RV rv; if (!metaslot_enabled) { return (CKR_SLOT_ID_INVALID); } if (phSession == NULL) { return (CKR_ARGUMENTS_BAD); } /* Check for any unknown flags. */ if (flags & ~(CKF_SERIAL_SESSION | CKF_RW_SESSION)) { return (CKR_ARGUMENTS_BAD); } if (!(flags & CKF_SERIAL_SESSION)) { return (CKR_SESSION_PARALLEL_NOT_SUPPORTED); } if (meta_slotManager_token_write_protected() && (flags & CKF_RW_SESSION)) { return (CKR_TOKEN_WRITE_PROTECTED); } rv = meta_session_alloc(&new_session); if (rv != CKR_OK) return (rv); new_session->session_flags = flags; rv = meta_session_activate(new_session); if (rv != CKR_OK) { meta_session_dealloc(new_session); return (rv); } *phSession = (CK_SESSION_HANDLE) new_session; num_meta_sessions++; if (flags & CKF_RW_SESSION) { num_rw_meta_sessions++; } return (CKR_OK); } /* * meta_CloseSession * */ CK_RV meta_CloseSession(CK_SESSION_HANDLE hSession) { CK_RV rv; meta_session_t *session; CK_FLAGS flags; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); /* save info about session flags before they are destroyed */ flags = session->session_flags; rv = meta_session_deactivate(session, B_FALSE); if (rv == CKR_OK) meta_session_dealloc(session); num_meta_sessions--; if (flags & CKF_RW_SESSION) { num_rw_meta_sessions--; } return (rv); } /* * meta_CloseAllSessions * * This is a simple loop that closes the sessionlist head (resulting in a * new list head) until the list is empty. * */ CK_RV meta_CloseAllSessions(CK_SLOT_ID slotID) { CK_RV rv; meta_session_t *session; if (!metaslot_enabled) { return (CKR_SLOT_ID_INVALID); } if (slotID != METASLOT_SLOTID) return (CKR_SLOT_ID_INVALID); (void) pthread_rwlock_wrlock(&meta_sessionlist_lock); while ((session = meta_sessionlist_head) != NULL) { rv = meta_handle2session((CK_SESSION_HANDLE)session, &session); if (rv != CKR_OK) { /*NOTREACHED*/ (void) pthread_rwlock_unlock(&meta_sessionlist_lock); return (CKR_FUNCTION_FAILED); } (void) meta_session_deactivate(session, B_TRUE); meta_session_dealloc(session); } (void) pthread_rwlock_unlock(&meta_sessionlist_lock); /* All open sessions should be closed, just reset the variables */ num_meta_sessions = 0; num_rw_meta_sessions = 0; return (CKR_OK); } /* * meta_GetSessionInfo * */ CK_RV meta_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) { CK_RV rv; meta_session_t *session; if (pInfo == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); pInfo->slotID = METASLOT_SLOTID; pInfo->flags = session->session_flags; if (metaslot_logged_in()) { if (IS_READ_ONLY_SESSION(session->session_flags)) { pInfo->state = CKS_RO_USER_FUNCTIONS; } else { pInfo->state = CKS_RW_USER_FUNCTIONS; } } else { if (IS_READ_ONLY_SESSION(session->session_flags)) { pInfo->state = CKS_RO_PUBLIC_SESSION; } else { pInfo->state = CKS_RW_PUBLIC_SESSION; } } pInfo->ulDeviceError = 0; REFRELEASE(session); return (CKR_OK); } CK_RV meta_getopstatelen(meta_session_t *session, CK_ULONG *out_length) { CK_RV rv = CKR_OK; slot_session_t *slot_session; CK_ULONG length; *out_length = sizeof (meta_opstate_t); if (session->op1.type != 0) { slot_session = session->op1.session; rv = FUNCLIST(slot_session->fw_st_id)->C_GetOperationState( slot_session->hSession, NULL, &length); if (rv == CKR_OK) *out_length += length; } return (rv); } /* * meta_GetOperationState * */ CK_RV meta_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG_PTR pulOperationStateLen) { CK_RV rv; meta_session_t *session; slot_session_t *slot_session = NULL; meta_opstate_t opstate; if (pulOperationStateLen == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); /* * If no operation is active, then bail out. */ if (session->op1.type == 0) { rv = CKR_OPERATION_NOT_INITIALIZED; goto endgetopstate; } /* * If the caller did not give an OpState buffer, * shortcut and just return the size needed to hold * a metaslot OpState record later. * The actual size of the returned state will be the * sizeof(meta_opstate_t) + SIZE (op1 state), * so we have to get the size of * the operation states now. */ if (pOperationState == NULL) { rv = meta_getopstatelen(session, pulOperationStateLen); REFRELEASE(session); return (rv); } /* * To be here, the caller must have supplied an * already initialized meta_opstate_t pointer. * Use it to get the real state info from the operation(s). * * The format of the Metaslot Opstate record: * { * struct metaopstate * [ op1 state data ] * } */ /* * If the buffer is not even big enough for the metaslot * opstate data, return error and set the returned * state length to indicate the minimum needed. */ if (*pulOperationStateLen < sizeof (meta_opstate_t)) { rv = meta_getopstatelen(session, pulOperationStateLen); /* * Remap the error so the caller knows that they * used an invalid buffer size in the first place. */ if (rv == CKR_OK) rv = CKR_BUFFER_TOO_SMALL; goto endgetopstate; } (void) memset(&opstate, 0, sizeof (meta_opstate_t)); opstate.magic_marker = METASLOT_OPSTATE_MAGIC; if (session->op1.type != 0) { slot_session = session->op1.session; opstate.state[0].op_type = session->op1.type; opstate.state[0].op_slotnum = slot_session->slotnum; opstate.state[0].op_state_len = *pulOperationStateLen - sizeof (meta_opstate_t); opstate.state[0].op_init_app = session->init.app; opstate.state[0].op_init_done = session->init.done; rv = FUNCLIST(slot_session->fw_st_id)->C_GetOperationState( slot_session->hSession, pOperationState + sizeof (meta_opstate_t), &(opstate.state[0].op_state_len)); if (rv == CKR_BUFFER_TOO_SMALL) { /* * This should not happen, but if it does, * recalculate the entire size needed * and return the error. */ rv = meta_getopstatelen(session, pulOperationStateLen); if (rv == CKR_OK) rv = CKR_BUFFER_TOO_SMALL; } if (rv != CKR_OK) goto endgetopstate; } endgetopstate: if (rv == CKR_OK && pOperationState != NULL) { (void) memcpy(pOperationState, (void *)&opstate, sizeof (meta_opstate_t)); *pulOperationStateLen = sizeof (meta_opstate_t) + opstate.state[0].op_state_len; } REFRELEASE(session); return (rv); } static CK_RV meta_set_opstate(slot_session_t *slot_session, meta_object_t *meta_enc_key, meta_object_t *meta_auth_key, struct opstate_data *state, CK_BYTE *databuf) { CK_RV rv; static CK_ULONG encrypt_optypes = (CKF_ENCRYPT | CKF_DECRYPT); static CK_ULONG sign_optypes = (CKF_SIGN | CKF_VERIFY | CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER); slot_object_t *enc_key_obj = NULL, *auth_key_obj = NULL; if (state->op_type & encrypt_optypes) { rv = meta_object_get_clone(meta_enc_key, slot_session->slotnum, slot_session, &enc_key_obj); if (rv != CKR_OK) { return (rv); } } if (state->op_type & sign_optypes) { rv = meta_object_get_clone(meta_auth_key, slot_session->slotnum, slot_session, &auth_key_obj); if (rv != CKR_OK) { return (rv); } } /* * Check to see if the keys are needed to restore the * state on the first operation. */ rv = FUNCLIST(slot_session->fw_st_id)->C_SetOperationState( slot_session->hSession, databuf, state->op_state_len, enc_key_obj ? enc_key_obj->hObject : CK_INVALID_HANDLE, auth_key_obj ? auth_key_obj->hObject : CK_INVALID_HANDLE); /* * If the operation did not need a key, try again. */ if (rv == CKR_KEY_NOT_NEEDED) { rv = FUNCLIST(slot_session->fw_st_id)->C_SetOperationState( slot_session->hSession, databuf, state->op_state_len, CK_INVALID_HANDLE, CK_INVALID_HANDLE); /* * Strange case... If the first try returned * KEY_NOT_NEEDED, and this one returns KEY_NEEDED, * we want to remap the return so the caller sees * the original "CKR_KEY_NOT_NEEDED" return value. * This ensures that a correct caller will retry * without the unnecessary key argument and this * 2nd attempt will not happen again. */ if (rv == CKR_KEY_NEEDED) { rv = CKR_KEY_NOT_NEEDED; } } return (rv); } /* * meta_SetOperationState * */ CK_RV meta_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey) { CK_RV rv = CKR_OK; meta_session_t *session; slot_session_t *slot_session = NULL; meta_opstate_t opstate; meta_object_t *meta_enc_key = NULL, *meta_auth_key = NULL; /* * Make sure the opstate info buffer is big enough to be valid. */ if (ulOperationStateLen < sizeof (meta_opstate_t) || pOperationState == NULL) return (CKR_ARGUMENTS_BAD); /* Copy the opstate info into the structure */ (void) memcpy(&opstate, pOperationState, sizeof (meta_opstate_t)); /* verify that a metaslot operation state was supplied */ if (opstate.magic_marker != METASLOT_OPSTATE_MAGIC) return (CKR_SAVED_STATE_INVALID); /* * Now, check the size again to make sure the "real" state * data is present. Length of state provided must be exact. */ if (ulOperationStateLen != (sizeof (meta_opstate_t) + opstate.state[0].op_state_len)) return (CKR_SAVED_STATE_INVALID); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); if (hEncryptionKey != CK_INVALID_HANDLE) { rv = meta_handle2object(hEncryptionKey, &meta_enc_key); if (rv != CKR_OK) goto cleanup; } if (hAuthenticationKey != CK_INVALID_HANDLE) { rv = meta_handle2object(hAuthenticationKey, &meta_auth_key); if (rv != CKR_OK) goto cleanup; } if (opstate.state[0].op_type != 0) { if (session->op1.type != 0) meta_operation_cleanup(session, session->op1.type, B_FALSE); if (session->op1.session != NULL) { slot_session = session->op1.session; } else { rv = meta_get_slot_session(opstate.state[0].op_slotnum, &slot_session, session->session_flags); if (rv != CKR_OK) goto cleanup; } session->op1.type = opstate.state[0].op_type; session->op1.session = slot_session; session->init.app = opstate.state[0].op_init_app; session->init.done = opstate.state[0].op_init_done; rv = meta_set_opstate(slot_session, meta_enc_key, meta_auth_key, &(opstate.state[0]), pOperationState + sizeof (meta_opstate_t)); if (rv != CKR_OK) { meta_operation_cleanup(session, session->op1.type, FALSE); goto cleanup; } } cleanup: if (meta_enc_key != NULL) OBJRELEASE(meta_enc_key); if (meta_auth_key != NULL) OBJRELEASE(meta_auth_key); REFRELEASE(session); return (rv); } /* * meta_Login * * This allows the user to login to the object token. The metaslot itself * does not have any kind of PIN. * */ CK_RV meta_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) { CK_RV rv; meta_session_t *session; slot_session_t *login_session = NULL; CK_TOKEN_INFO token_info; CK_SLOT_ID true_id, fw_st_id; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); if (metaslot_logged_in()) { rv = CKR_USER_ALREADY_LOGGED_IN; goto finish; } /* Note: CKU_SO is not supported. */ if (userType != CKU_USER) { rv = CKR_USER_TYPE_INVALID; goto finish; } rv = meta_get_slot_session(get_keystore_slotnum(), &login_session, session->session_flags); if (rv != CKR_OK) goto finish; fw_st_id = login_session->fw_st_id; rv = FUNCLIST(fw_st_id)->C_Login(login_session->hSession, userType, pPin, ulPinLen); if (rv != CKR_OK) { goto finish; } /* * Note: * * For some slots (eg: the pkcs11_softtoken.so), C_Login() * returning OK don't mean that the login is truely * successful. For pkcs11_softtoken.so, the CKF_USER_PIN_TO_BE_CHANGED * is set to indicate that the pin needs to be changed, and * the login is not really successful. We will check * that flag for this special condition. Checking for * this flag shouldn't be harmful for other slots that doesn't * behave like pkcs11_softtoken.so. */ true_id = TRUEID(fw_st_id); rv = FUNCLIST(fw_st_id)->C_GetTokenInfo(true_id, &token_info); if (rv != CKR_OK) { goto finish; } metaslot_set_logged_in_flag(B_TRUE); if (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED) { metaslot_set_logged_in_flag(B_FALSE); } finish: if (login_session) meta_release_slot_session(login_session); REFRELEASE(session); return (rv); } /* * meta_Logout * */ CK_RV meta_Logout(CK_SESSION_HANDLE hSession) { CK_RV rv = CKR_OK; meta_session_t *session; slot_session_t *logout_session = NULL; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); if (!metaslot_logged_in()) { rv = CKR_USER_NOT_LOGGED_IN; goto finish; } rv = meta_get_slot_session(get_keystore_slotnum(), &logout_session, session->session_flags); if (rv != CKR_OK) goto finish; rv = FUNCLIST(logout_session->fw_st_id)->C_Logout( logout_session->hSession); /* If the C_Logout fails, just ignore the error. */ metaslot_set_logged_in_flag(B_FALSE); (void) meta_token_object_deactivate(PRIVATE_TOKEN); finish: if (logout_session) meta_release_slot_session(logout_session); REFRELEASE(session); return (rv); } /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include "metaGlobal.h" /* * The list and the list lock are global for two external uses: * 1) C_CloseAllSessions need to close the head (repeatedly, * until no more sessions exist). * 2) meta_object_find_by_handle needs to walk all sessions, * searching each session object list for matching objects. */ pthread_rwlock_t meta_sessionlist_lock; meta_session_t *meta_sessionlist_head; /* * The following 2 variables are used for tracking the number of * sessions and number of rw sessios that are currently open * * They are being manipulated in the metaSession.c file, and being * referenced in the metaSlotToken.c file */ CK_ULONG num_meta_sessions; CK_ULONG num_rw_meta_sessions; static pthread_rwlock_t meta_sessionclose_lock; /* * meta_sessionManager_initialize * * Called from meta_Initialize. Initializes all the variables used * by the session manager. */ CK_RV meta_sessionManager_initialize() { if (pthread_rwlock_init(&meta_sessionlist_lock, NULL) != 0) { return (CKR_FUNCTION_FAILED); } if (pthread_rwlock_init(&meta_sessionclose_lock, NULL) != 0) { (void) pthread_rwlock_destroy(&meta_sessionlist_lock); return (CKR_FUNCTION_FAILED); } meta_sessionlist_head = NULL; num_meta_sessions = 0; num_rw_meta_sessions = 0; return (CKR_OK); } /* * meta_sessionManager_finalize * * Close all sessions, and destroy all the locks */ void meta_sessionManager_finalize() { /* * Close any remaining metasessions, can just simply call * meta_CloseAllSessions. The METASLOT_SLOTID argument is * not used, but need to be passed in. */ (void) meta_CloseAllSessions(METASLOT_SLOTID); (void) pthread_rwlock_destroy(&meta_sessionclose_lock); (void) pthread_rwlock_destroy(&meta_sessionlist_lock); } /* * meta_handle2session * * Convert a CK_SESSION_HANDLE to the corresponding metasession. If * successful, a write-lock on the session will be held to indicate * that it's in use. Call REFRELEASE() when finished. * */ CK_RV meta_handle2session(CK_SESSION_HANDLE hSession, meta_session_t **session) { meta_session_t *tmp_session = (meta_session_t *)(hSession); /* Check for bad args (eg CK_INVALID_HANDLE, which is 0/NULL). */ if (tmp_session == NULL || tmp_session->magic_marker != METASLOT_SESSION_MAGIC) { return (CKR_SESSION_HANDLE_INVALID); } /* * sessions can only be used by a single thread at a time. * So, we need to get a write-lock. */ (void) pthread_rwlock_wrlock(&tmp_session->session_lock); /* Make sure this session is not in the process of being deleted */ (void) pthread_mutex_lock(&tmp_session->isClosingSession_lock); if (tmp_session->isClosingSession) { (void) pthread_mutex_unlock( &tmp_session->isClosingSession_lock); (void) pthread_rwlock_unlock(&tmp_session->session_lock); return (CKR_SESSION_HANDLE_INVALID); } (void) pthread_mutex_unlock(&tmp_session->isClosingSession_lock); *session = tmp_session; return (CKR_OK); } /* * meta_session_alloc */ CK_RV meta_session_alloc(meta_session_t **session) { meta_session_t *new_session; /* Allocate memory for the session. */ new_session = calloc(1, sizeof (meta_session_t)); if (new_session == NULL) return (CKR_HOST_MEMORY); (new_session->mech_support_info).supporting_slots = malloc(meta_slotManager_get_slotcount() * sizeof (mechinfo_t *)); if ((new_session->mech_support_info).supporting_slots == NULL) { free(new_session); return (CKR_HOST_MEMORY); } (new_session->mech_support_info).num_supporting_slots = 0; new_session->magic_marker = METASLOT_SESSION_MAGIC; (void) pthread_rwlock_init(&new_session->session_lock, NULL); (void) pthread_mutex_init(&new_session->isClosingSession_lock, NULL); (void) pthread_rwlock_init(&new_session->object_list_lock, NULL); *session = new_session; return (CKR_OK); } /* * meta_session_activate * * Create and add a session to the list of active meta sessions. */ CK_RV meta_session_activate(meta_session_t *session) { CK_RV rv = CKR_OK; /* Add session to the list of sessions. */ (void) pthread_rwlock_wrlock(&meta_sessionlist_lock); INSERT_INTO_LIST(meta_sessionlist_head, session); (void) pthread_rwlock_unlock(&meta_sessionlist_lock); return (rv); } /* * meta_session_deactivate * * */ CK_RV meta_session_deactivate(meta_session_t *session, boolean_t have_sessionlist_lock) { boolean_t isLastSession = B_FALSE; meta_object_t *object; /* Safely resolve attempts of concurrent-close */ (void) pthread_mutex_lock(&session->isClosingSession_lock); if (session->isClosingSession) { /* Lost a delete race. */ (void) pthread_mutex_unlock(&session->isClosingSession_lock); REFRELEASE(session); return (CKR_SESSION_HANDLE_INVALID); } session->isClosingSession = B_TRUE; session->magic_marker = METASLOT_SESSION_BADMAGIC; (void) pthread_mutex_unlock(&session->isClosingSession_lock); /* * Remove session from the session list. Once removed, it will not * be possible for another thread to begin using the session. */ (void) pthread_rwlock_wrlock(&meta_sessionclose_lock); if (!have_sessionlist_lock) { (void) pthread_rwlock_wrlock(&meta_sessionlist_lock); } REMOVE_FROM_LIST(meta_sessionlist_head, session); if (meta_sessionlist_head == NULL) { isLastSession = B_TRUE; } if (!have_sessionlist_lock) { (void) pthread_rwlock_unlock(&meta_sessionlist_lock); } (void) pthread_rwlock_unlock(&meta_sessionclose_lock); (void) pthread_rwlock_unlock(&session->session_lock); /* Cleanup any in-progress operations. */ if (session->op1.type != 0) { meta_operation_cleanup(session, session->op1.type, FALSE); } if (session->op1.session != NULL) { meta_release_slot_session(session->op1.session); session->op1.session = NULL; } /* Remove all the session metaobjects created in this session. */ /* Basically, emulate C_DestroyObject, including safety h2s */ while ((object = session->object_list_head) != NULL) { CK_RV rv; rv = meta_handle2object((CK_OBJECT_HANDLE)object, &object); if (rv != CKR_OK) { /* Can only happen if someone else just closed it. */ continue; } rv = meta_object_deactivate(object, B_FALSE, B_TRUE); if (rv != CKR_OK) { continue; } rv = meta_object_dealloc(NULL, object, B_FALSE); if (rv != CKR_OK) { continue; } } if ((isLastSession) && (metaslot_logged_in())) { slot_session_t *slotsessp; CK_RV rv; rv = meta_get_slot_session(get_keystore_slotnum(), &slotsessp, session->session_flags); if (rv != CKR_OK) return (rv); rv = FUNCLIST(slotsessp->fw_st_id)->C_Logout( slotsessp->hSession); meta_release_slot_session(slotsessp); /* if C_Logout fails, just ignore the error */ metaslot_set_logged_in_flag(B_FALSE); if (rv != CKR_OK) return (rv); /* need to deactivate all the PRIVATE token objects */ rv = meta_token_object_deactivate(PRIVATE_TOKEN); if (rv != CKR_OK) { return (rv); } } return (CKR_OK); } /* * meta_session_dealloc * * Release the resources held by a metasession. If the session has been * activated, it must be deactivated first. */ void meta_session_dealloc(meta_session_t *session) { if ((session->find_objs_info).matched_objs) { free((session->find_objs_info).matched_objs); } free((session->mech_support_info).supporting_slots); /* * If there were active operations, cleanup the slot session so that * it can be reused (otherwise provider might complain that an * operation is active). */ if (session->op1.type != 0) meta_operation_cleanup(session, session->op1.type, FALSE); /* Final object cleanup. */ (void) pthread_rwlock_destroy(&session->session_lock); (void) pthread_mutex_destroy(&session->isClosingSession_lock); (void) pthread_rwlock_destroy(&session->object_list_lock); meta_session_delay_free(session); } /* * This function adds the to-be-freed meta session to a linked list. * When the number of sessions queued in the linked list reaches the * maximum threshold MAX_SESSION_TO_BE_FREED, it will free the first * session (FIFO) in the list. */ void meta_session_delay_free(meta_session_t *sp) { meta_session_t *tmp; (void) pthread_mutex_lock(&ses_delay_freed.ses_to_be_free_mutex); /* Add the newly deleted session at the end of the list */ sp->next = NULL; if (ses_delay_freed.first == NULL) { ses_delay_freed.last = sp; ses_delay_freed.first = sp; } else { ses_delay_freed.last->next = sp; ses_delay_freed.last = sp; } if (++ses_delay_freed.count >= MAX_SESSION_TO_BE_FREED) { /* * Free the first session in the list only if * the total count reaches maximum threshold. */ ses_delay_freed.count--; tmp = ses_delay_freed.first->next; free(ses_delay_freed.first); ses_delay_freed.first = tmp; } (void) pthread_mutex_unlock(&ses_delay_freed.ses_to_be_free_mutex); } /* * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Signing and MACing Functions * (as defined in PKCs#11 spec section 11.11) */ #include "metaGlobal.h" /* * meta_SignInit * */ CK_RV meta_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { CK_RV rv; meta_session_t *session; meta_object_t *key; if (pMechanism == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_handle2object(hKey, &key); if (rv != CKR_OK) { REFRELEASE(session); return (rv); } rv = meta_operation_init(CKF_SIGN, session, pMechanism, key); OBJRELEASE(key); REFRELEASE(session); return (rv); } /* * meta_Sign * */ CK_RV meta_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { CK_RV rv; meta_session_t *session; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); if (pData == NULL || pulSignatureLen == NULL) { meta_operation_cleanup(session, CKF_SIGN, FALSE); REFRELEASE(session); return (CKR_ARGUMENTS_BAD); } rv = meta_do_operation(CKF_SIGN, MODE_SINGLE, session, NULL, pData, ulDataLen, pSignature, pulSignatureLen); REFRELEASE(session); return (rv); } /* * meta_SignUpdate * */ CK_RV meta_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { CK_RV rv; meta_session_t *session; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); if (pPart == NULL) { meta_operation_cleanup(session, CKF_SIGN, FALSE); REFRELEASE(session); return (CKR_ARGUMENTS_BAD); } rv = meta_do_operation(CKF_SIGN, MODE_UPDATE, session, NULL, pPart, ulPartLen, NULL, NULL); REFRELEASE(session); return (rv); } /* * meta_SignFinal * */ CK_RV meta_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { CK_RV rv; meta_session_t *session; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); if (pulSignatureLen == NULL) { meta_operation_cleanup(session, CKF_SIGN, FALSE); REFRELEASE(session); return (CKR_ARGUMENTS_BAD); } rv = meta_do_operation(CKF_SIGN, MODE_FINAL, session, NULL, NULL, 0, pSignature, pulSignatureLen); REFRELEASE(session); return (rv); } /* * meta_SignRecoverInit * */ CK_RV meta_SignRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { CK_RV rv; meta_session_t *session; meta_object_t *key; if (pMechanism == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_handle2object(hKey, &key); if (rv != CKR_OK) { REFRELEASE(session); return (rv); } rv = meta_operation_init(CKF_SIGN_RECOVER, session, pMechanism, key); OBJRELEASE(key); REFRELEASE(session); return (rv); } /* * meta_SignRecover * */ CK_RV meta_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { CK_RV rv; meta_session_t *session; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); if (pData == NULL || pulSignatureLen == NULL) { meta_operation_cleanup(session, CKF_SIGN_RECOVER, FALSE); REFRELEASE(session); return (CKR_ARGUMENTS_BAD); } rv = meta_do_operation(CKF_SIGN_RECOVER, MODE_SINGLE, session, NULL, pData, ulDataLen, pSignature, pulSignatureLen); REFRELEASE(session); return (rv); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Functions for dealing with provider sessions */ #include #include #include "metaGlobal.h" #include "pkcs11Session.h" #include "pkcs11Global.h" /* * This is just a **WILD** guess for the maximum idle sessions to * keep for each slot. This number should probably be adjusted * when there's more data from actual application use */ #define MAX_IDLE_SESSIONS 100 /* * The following 5 variables are initialized at the time metaslot * is initialized. They are not modified after they are initialized * * During initialization time, they are protected by the "initmutex" * defined in metaGeneral.c */ slot_data_t *slots; CK_SLOT_ID metaslot_keystore_slotid; static CK_ULONG num_slots; static CK_ULONG objtok_slotnum; static CK_ULONG softtoken_slotnum; static boolean_t write_protected; /* protects the "metaslotLoggedIn" variable */ static pthread_mutex_t metaslotLoggedIn_mutex = PTHREAD_MUTEX_INITIALIZER; static boolean_t metaslotLoggedIn; /* * meta_slotManager_initialize * * Called from C_Initialize. Allocates and initializes the storage needed * by the slot manager. */ CK_RV meta_slotManager_initialize() { CK_ULONG slot_count = 0; CK_RV rv; CK_SLOT_ID i; /* Initialize the static variables */ write_protected = B_FALSE; metaslotLoggedIn = B_FALSE; /* * Count the number of slots in the framework. * We start at ((slottable->st_first) + 1) instead of * slottable->st_first because when we are here, metaslot is * enabled, and st_first is always metaslot, which doesn't * need to be counted. */ for (i = (slottable->st_first) + 1; i <= slottable->st_last; i++) { slot_count++; } /* * This shouldn't happen, because there should at least * be 1 other slot besides metaslot. */ if (slot_count < 1) { rv = CKR_FUNCTION_FAILED; goto clean_exit; } slots = calloc(slot_count, sizeof (slot_data_t)); if (slots == NULL) { rv = CKR_HOST_MEMORY; goto clean_exit; } /* * Store the slot IDs. Adjust for the fact that the first slot is * actually us (metaslot). */ for (i = 0; i < slot_count; i++) { slots[i].fw_st_id = i + 1; (void) pthread_rwlock_init( &(slots[i].tokenobject_list_lock), NULL); } num_slots = slot_count; return (CKR_OK); clean_exit: if (slots) { free(slots); slots = NULL; } num_slots = 0; return (rv); } /* * meta_slotManager_finalize * * Called from C_Finalize. Deallocates any storage held by the slot manager. */ void meta_slotManager_finalize() { CK_ULONG slot; /* If no slots to free, return */ if (slots == NULL) return; /* * No need to lock pool, we assume all meta sessions are closed. * * Close all sessions in the idle and persist list. * The active list is empty. It doesn't need to be checked. */ for (slot = 0; slot < num_slots; slot++) { slot_session_t *session, *next_session; /* * The slotobjects associated with the session should have * been closed when the metaobjects were closed. Thus, no * need to do anything here. */ session = slots[slot].session_pool.idle_list_head; while (session) { next_session = session->next; (void) FUNCLIST(session->fw_st_id)->C_CloseSession( session->hSession); (void) pthread_rwlock_destroy( &session->object_list_lock); free(session); session = next_session; } session = slots[slot].session_pool.persist_list_head; while (session) { next_session = session->next; (void) FUNCLIST(session->fw_st_id)->C_CloseSession( session->hSession); (void) pthread_rwlock_destroy( &session->object_list_lock); free(session); session = next_session; } (void) pthread_rwlock_destroy( &slots[slot].tokenobject_list_lock); } free(slots); slots = NULL; num_slots = 0; } /* * meta_slotManager_find_object_token() * * Called from meta_Initialize. Searches for the "object token," which is used * for storing token objects and loging into. * * We do the search using the following algorithm. * * If either ${METASLOT_OBJECTSTORE_SLOT} or ${METASLOT_OBJECTSTORE_TOKEN} * environment variable is defined, the value of the defined variable(s) * will be used for the match. All token and slot values defined system-wide * will be ignored. * * If neither variables above are defined, the system-wide values defined * in pkcs11.conf are used. * * If neither environment variables or system-wide values are defined, * or if none of the existing slots/tokens match the defined * values, the first slot after metaslot will be used as the default. * */ void meta_slotManager_find_object_token() { CK_ULONG slot; boolean_t found = B_FALSE; CK_RV rv; unsigned int num_match_needed = 0; CK_SLOT_INFO slotinfo; CK_TOKEN_INFO tokeninfo; if (metaslot_config.keystore_token_specified) { num_match_needed++; } if (metaslot_config.keystore_slot_specified) { num_match_needed++; } if (num_match_needed == 0) { goto skip_search; } for (slot = 0; slot < num_slots; slot++) { unsigned int num_matched = 0; boolean_t have_tokeninfo = B_FALSE; CK_SLOT_ID true_id, fw_st_id; fw_st_id = slots[slot].fw_st_id; true_id = TRUEID(fw_st_id); (void) memset(&slotinfo, 0, sizeof (CK_SLOT_INFO)); rv = FUNCLIST(fw_st_id)->C_GetSlotInfo(true_id, &slotinfo); if (rv != CKR_OK) continue; if (strncmp((char *)SOFT_SLOT_DESCRIPTION, (char *)slotinfo.slotDescription, SLOT_DESCRIPTION_SIZE) == 0) { softtoken_slotnum = slot; } if (metaslot_config.keystore_slot_specified) { unsigned char *slot; size_t slot_str_len; rv = FUNCLIST(fw_st_id)->C_GetSlotInfo(true_id, &slotinfo); if (rv != CKR_OK) continue; /* * pad slot description from user/system configuration * with spaces */ slot = metaslot_config.keystore_slot; slot_str_len = strlen((char *)slot); (void) memset(slot + slot_str_len, ' ', SLOT_DESCRIPTION_SIZE - slot_str_len); /* * The PKCS#11 strings are not null-terminated, so, * we just compare SLOT_DESCRIPTION_SIZE bytes */ if (strncmp((char *)slot, (char *)slotinfo.slotDescription, SLOT_DESCRIPTION_SIZE) == 0) { num_matched++; } } if (metaslot_config.keystore_token_specified) { unsigned char *token; size_t token_str_len; rv = FUNCLIST(fw_st_id)->C_GetTokenInfo(true_id, &tokeninfo); if (rv != CKR_OK) { continue; } have_tokeninfo = B_TRUE; /* * pad slot description from user/system configuration * with spaces */ token = metaslot_config.keystore_token; token_str_len = strlen((char *)token); (void) memset(token + token_str_len, ' ', TOKEN_LABEL_SIZE - token_str_len); /* * The PKCS#11 strings are not null-terminated. * So, just compare TOKEN_LABEL_SIZE bytes */ if (strncmp((char *)token, (char *)tokeninfo.label, TOKEN_LABEL_SIZE) == 0) { num_matched++; } } if (num_match_needed == num_matched) { /* match is found */ if (!have_tokeninfo) { rv = FUNCLIST(fw_st_id)->C_GetTokenInfo(true_id, &tokeninfo); if (rv != CKR_OK) { continue; } } if (tokeninfo.flags & CKF_WRITE_PROTECTED) { /* * Currently this is the only time that * the write_protected state is set, and * it is never cleared. The token could * clear (or set!) this flag later on. * We might want to adjust the state * of metaslot, but there's know way to know * when a token changes this flag. */ write_protected = B_TRUE; } found = B_TRUE; break; } } skip_search: if (found) { objtok_slotnum = slot; } else { /* * if slot and/or token is not defined for the keystore, * just use the first available slot as keystore */ objtok_slotnum = 0; } slots[objtok_slotnum].session_pool.keep_one_alive = B_TRUE; metaslot_keystore_slotid = slots[objtok_slotnum].fw_st_id; } CK_ULONG get_keystore_slotnum() { return (objtok_slotnum); } CK_ULONG get_softtoken_slotnum() { return (softtoken_slotnum); } CK_SLOT_ID meta_slotManager_get_framework_table_id(CK_ULONG slotnum) { /* * This is only used internally, and so the slotnum should always * be valid. */ return (slots[slotnum].fw_st_id); } CK_ULONG meta_slotManager_get_slotcount() { return (num_slots); } boolean_t meta_slotManager_token_write_protected() { return (write_protected); } /* * Find a session in the given list that matches the specified flags. * If such a session is found, it will be removed from the list, and * returned to the caller. If such a session is not found, will * return NULL */ static slot_session_t * get_session(slot_session_t **session_list, CK_FLAGS flags) { slot_session_t *tmp_session; tmp_session = *session_list; while (tmp_session != NULL) { if (tmp_session->session_flags == flags) { break; } else { tmp_session = tmp_session->next; } } if (tmp_session == NULL) { /* no match */ return (NULL); } /* Remove from list */ REMOVE_FROM_LIST(*session_list, tmp_session); return (tmp_session); } /* * meta_get_slot_session * * Call to get a session with a specific slot/token. * * NOTE - We assume the slot allows an unlimited number of sessions. We * could look at what's reported in the token info, but that information is * not always set. It's also unclear when we should (A) wait for one to become * available, (B) skip the slot for now or (C) return a fatal error. The * extra complexity is not worth it. * */ CK_RV meta_get_slot_session(CK_ULONG slotnum, slot_session_t **session, CK_FLAGS flags) { session_pool_t *pool; slot_session_t *new_session, *tmp_session; CK_RV rv; CK_SLOT_ID fw_st_id, true_id; if (slotnum >= num_slots) { return (CKR_SLOT_ID_INVALID); } pool = &slots[slotnum].session_pool; /* * Try to reuse an existing session. */ (void) pthread_mutex_lock(&pool->list_lock); if (pool->idle_list_head != NULL) { tmp_session = get_session(&(pool->idle_list_head), flags); if (tmp_session != NULL) { /* Add to active list */ INSERT_INTO_LIST(pool->active_list_head, tmp_session); *session = tmp_session; pool->num_idle_sessions--; (void) pthread_mutex_unlock(&pool->list_lock); return (CKR_OK); } } if (pool->persist_list_head != NULL) { tmp_session = get_session(&(pool->persist_list_head), flags); if (tmp_session != NULL) { /* Add to active list */ INSERT_INTO_LIST(pool->active_list_head, tmp_session); *session = tmp_session; (void) pthread_mutex_unlock(&pool->list_lock); return (CKR_OK); } } (void) pthread_mutex_unlock(&pool->list_lock); fw_st_id = slots[slotnum].fw_st_id; true_id = TRUEID(fw_st_id); new_session = calloc(1, sizeof (slot_session_t)); if (new_session == NULL) { return (CKR_HOST_MEMORY); } /* initialize slotsession */ new_session->slotnum = slotnum; new_session->fw_st_id = fw_st_id; new_session->object_list_head = NULL; new_session->session_flags = flags; (void) pthread_rwlock_init(&new_session->object_list_lock, NULL); rv = FUNCLIST(fw_st_id)->C_OpenSession(true_id, flags, NULL, NULL, &new_session->hSession); if (rv == CKR_TOKEN_WRITE_PROTECTED) { /* Retry with a RO session. */ new_session->session_flags &= ~CKF_SERIAL_SESSION; rv = FUNCLIST(fw_st_id)->C_OpenSession(true_id, new_session->session_flags, NULL, NULL, &new_session->hSession); } if (rv != CKR_OK) { free(new_session); return (CKR_FUNCTION_FAILED); } /* Insert session into active list */ (void) pthread_mutex_lock(&pool->list_lock); INSERT_INTO_LIST(pool->active_list_head, new_session); (void) pthread_mutex_unlock(&pool->list_lock); *session = new_session; return (CKR_OK); } /* * meta_release_slot_session * * Call to release a session obtained via meta_get_slot_session() */ void meta_release_slot_session(slot_session_t *session) { session_pool_t *pool; boolean_t must_retain, can_close = B_FALSE; boolean_t this_is_last_session = B_FALSE; pool = &slots[session->slotnum].session_pool; /* Note that the active_list must have >= 1 entry (this session) */ if (pool->persist_list_head == NULL && pool->idle_list_head == NULL && pool->active_list_head->next == NULL) this_is_last_session = B_TRUE; /* * If the session has session objects, we need to retain it. Also * retain it if it's the only session holding login state (or handles * to public token objects) */ must_retain = session->object_list_head != NULL || (pool->keep_one_alive && this_is_last_session); if ((!must_retain) && (pool->num_idle_sessions > MAX_IDLE_SESSIONS)) { can_close = B_TRUE; } (void) pthread_mutex_lock(&pool->list_lock); /* remove from active list */ REMOVE_FROM_LIST(pool->active_list_head, session); if (must_retain) { /* insert into persist list */ INSERT_INTO_LIST(pool->persist_list_head, session); (void) pthread_mutex_unlock(&pool->list_lock); return; } else if (!can_close) { /* insert into idle list */ INSERT_INTO_LIST(pool->idle_list_head, session); pool->num_idle_sessions++; (void) pthread_mutex_unlock(&pool->list_lock); return; } (void) pthread_mutex_unlock(&pool->list_lock); (void) FUNCLIST(session->fw_st_id)->C_CloseSession(session->hSession); (void) pthread_rwlock_destroy(&session->object_list_lock); free(session); } /* * Returns whether metaslot has directly logged in */ boolean_t metaslot_logged_in() { return (metaslotLoggedIn); } void metaslot_set_logged_in_flag(boolean_t value) { (void) pthread_mutex_lock(&metaslotLoggedIn_mutex); metaslotLoggedIn = value; (void) pthread_mutex_unlock(&metaslotLoggedIn_mutex); } /* * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Slot and Token Management functions * (as defined in PKCS#11 spec section 11.5) */ #include #include #include #include "metaGlobal.h" extern CK_ULONG num_meta_sessions; extern CK_ULONG num_rw_meta_sessions; /* * meta_GetSlotList * * For the metaslot, this is a trivial function. The metaslot module, * by defination, provides exactly one slot. The token is always present. * * This function is actually not called. */ /* ARGSUSED */ CK_RV meta_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount) { CK_RV rv; if (pulCount == NULL) return (CKR_ARGUMENTS_BAD); if (pSlotList == NULL) { *pulCount = 1; return (CKR_OK); } if (*pulCount < 1) { rv = CKR_BUFFER_TOO_SMALL; } else { pSlotList[0] = METASLOT_SLOTID; rv = CKR_OK; } *pulCount = 1; return (rv); } /* * meta_GetSlotInfo * * Returns basic information about the metaslot. * * The slotID argument is ignored. */ /*ARGSUSED*/ CK_RV meta_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { CK_SLOT_INFO slotinfo; CK_SLOT_ID true_id; CK_RV rv; if (!metaslot_enabled) { return (CKR_SLOT_ID_INVALID); } if (pInfo == NULL) { return (CKR_ARGUMENTS_BAD); } /* Provide information about the slot in the provided buffer */ (void) memcpy(pInfo->slotDescription, METASLOT_SLOT_DESCRIPTION, 64); (void) memcpy(pInfo->manufacturerID, METASLOT_MANUFACTURER_ID, 32); pInfo->hardwareVersion.major = METASLOT_HARDWARE_VERSION_MAJOR; pInfo->hardwareVersion.minor = METASLOT_HARDWARE_VERSION_MINOR; pInfo->firmwareVersion.major = METASLOT_FIRMWARE_VERSION_MAJOR; pInfo->firmwareVersion.minor = METASLOT_FIRMWARE_VERSION_MINOR; /* Find out token is present in the underlying keystore */ true_id = TRUEID(metaslot_keystore_slotid); rv = FUNCLIST(metaslot_keystore_slotid)->C_GetSlotInfo(true_id, &slotinfo); if ((rv == CKR_OK) && (slotinfo.flags & CKF_TOKEN_PRESENT)) { /* * store the token present flag if it is successfully * received from the keystore slot. * If not, this flag will not be set. */ pInfo->flags = CKF_TOKEN_PRESENT; } return (CKR_OK); } /* * meta_GetTokenInfo * * Returns basic information about the metaslot "token." * * The slotID argument is ignored. * */ /*ARGSUSED*/ CK_RV meta_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) { CK_RV rv; CK_TOKEN_INFO metainfo; CK_SLOT_ID true_id; if (!metaslot_enabled) { return (CKR_SLOT_ID_INVALID); } if (pInfo == NULL) return (CKR_ARGUMENTS_BAD); true_id = TRUEID(metaslot_keystore_slotid); rv = FUNCLIST(metaslot_keystore_slotid)->C_GetTokenInfo(true_id, &metainfo); /* * If we could not get information about the object token, use * default values. This allows metaslot to be used even if there * are problems with the object token (eg, it's not present). */ if (rv != CKR_OK) { metainfo.ulTotalPublicMemory = CK_UNAVAILABLE_INFORMATION; metainfo.ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION; metainfo.ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION; metainfo.ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION; metainfo.flags = CKF_WRITE_PROTECTED; metainfo.ulMaxPinLen = 0; metainfo.ulMinPinLen = 0; metainfo.hardwareVersion.major = METASLOT_HARDWARE_VERSION_MAJOR; metainfo.hardwareVersion.minor = METASLOT_HARDWARE_VERSION_MINOR; metainfo.firmwareVersion.major = METASLOT_FIRMWARE_VERSION_MAJOR; metainfo.firmwareVersion.minor = METASLOT_FIRMWARE_VERSION_MINOR; } /* * Override some values that the object token may have set. They * can be inappropriate/misleading when used in the context of * metaslot. */ (void) memcpy(metainfo.label, METASLOT_TOKEN_LABEL, 32); (void) memcpy(metainfo.manufacturerID, METASLOT_MANUFACTURER_ID, 32); (void) memcpy(metainfo.model, METASLOT_TOKEN_MODEL, 16); (void) memset(metainfo.serialNumber, ' ', 16); metainfo.ulMaxSessionCount = CK_EFFECTIVELY_INFINITE; metainfo.ulSessionCount = num_meta_sessions; metainfo.ulMaxRwSessionCount = CK_EFFECTIVELY_INFINITE; metainfo.ulRwSessionCount = num_rw_meta_sessions; metainfo.flags |= CKF_RNG; metainfo.flags &= ~CKF_RESTORE_KEY_NOT_NEEDED; metainfo.flags |= CKF_TOKEN_INITIALIZED; metainfo.flags &= ~CKF_SECONDARY_AUTHENTICATION; /* Clear the time field if the token does not have a clock. */ if (!(metainfo.flags & CKF_CLOCK_ON_TOKEN)) (void) memset(metainfo.utcTime, ' ', 16); *pInfo = metainfo; return (CKR_OK); } /* * meta_WaitForSlotEvent * * The metaslot never generates events, so this function doesn't do anything * useful. We do not pass on provider events because we want to hide details * of the providers. * * If CKF_DONT_BLOCK flag is turned on, CKR_NO_EVENT will be return. * Otherwise, return CKR_FUNCTION_FAILED. * */ /* ARGSUSED */ CK_RV meta_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved) { if (flags & CKF_DONT_BLOCK) { return (CKR_NO_EVENT); } else { return (CKR_FUNCTION_FAILED); } } /* * meta_GetMechanismList * * The slotID argument is not used. * */ /*ARGSUSED*/ CK_RV meta_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount) { CK_RV rv; if (!metaslot_enabled) { return (CKR_SLOT_ID_INVALID); } if (pulCount == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_mechManager_get_mechs(pMechanismList, pulCount); if ((rv == CKR_BUFFER_TOO_SMALL) && (pMechanismList == NULL)) { /* * if pMechanismList is not provided, just need to * return count */ rv = CKR_OK; } return (rv); } /* * meta_GetMechanismInfo * * The slotID argument is not used. */ /*ARGSUSED*/ CK_RV meta_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo) { CK_RV rv; mechinfo_t **slots = NULL; unsigned long i, slotCount = 0; mech_support_info_t mech_support_info; if (!metaslot_enabled) { return (CKR_SLOT_ID_INVALID); } if (pInfo == NULL) { return (CKR_ARGUMENTS_BAD); } mech_support_info.supporting_slots = malloc(meta_slotManager_get_slotcount() * sizeof (mechinfo_t *)); if (mech_support_info.supporting_slots == NULL) { return (CKR_HOST_MEMORY); } mech_support_info.mech = type; rv = meta_mechManager_get_slots(&mech_support_info, TRUE, NULL); if (rv != CKR_OK) { free(mech_support_info.supporting_slots); return (rv); } slotCount = mech_support_info.num_supporting_slots; slots = mech_support_info.supporting_slots; /* Merge mechanism info from all slots. */ (void) memcpy(pInfo, &(slots[0]->mechanism_info), sizeof (CK_MECHANISM_INFO)); /* no need to look at index 0, since that's what we started with */ for (i = 1; i < slotCount; i++) { CK_ULONG thisValue; /* MinKeySize should be smallest of all slots. */ thisValue = slots[i]->mechanism_info.ulMinKeySize; if (thisValue < pInfo->ulMinKeySize) { pInfo->ulMinKeySize = thisValue; } /* MaxKeySize should be largest of all slots. */ thisValue = slots[i]->mechanism_info.ulMaxKeySize; if (thisValue > pInfo->ulMaxKeySize) { pInfo->ulMaxKeySize = thisValue; } pInfo->flags |= slots[i]->mechanism_info.flags; } /* Clear the CKF_HW flag. We might select a software provider later. */ pInfo->flags &= ~CKF_HW; /* Clear the extenstion flag. Spec says is should never even be set. */ pInfo->flags &= ~CKF_EXTENSION; free(mech_support_info.supporting_slots); return (CKR_OK); } /* * meta_InitToken * * Not supported. The metaslot "token" is always initialized. The token object * token must already be initialized. Other vendors don't seem to support * this anyway. */ /* ARGSUSED */ CK_RV meta_InitToken(CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, CK_UTF8CHAR_PTR pLabel) { return (CKR_FUNCTION_NOT_SUPPORTED); } /* * meta_InitPIN * * Not supported. Same reason as C_InitToken. */ /* ARGSUSED */ CK_RV meta_InitPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) { return (CKR_FUNCTION_NOT_SUPPORTED); } /* * meta_SetPIN * * This is basically just a pass-thru to the object token. No need to * even check the arguments, since we don't use them. */ CK_RV meta_SetPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldPinLen, CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewPinLen) { CK_RV rv; meta_session_t *session; slot_session_t *slot_session; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); if (IS_READ_ONLY_SESSION(session->session_flags)) { REFRELEASE(session); return (CKR_SESSION_READ_ONLY); } rv = meta_get_slot_session(get_keystore_slotnum(), &slot_session, session->session_flags); if (rv != CKR_OK) { REFRELEASE(session); return (rv); } rv = FUNCLIST(slot_session->fw_st_id)->C_SetPIN(slot_session->hSession, pOldPin, ulOldPinLen, pNewPin, ulNewPinLen); meta_release_slot_session(slot_session); REFRELEASE(session); return (rv); } /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include "metaGlobal.h" extern cipher_mechs_threshold_t meta_mechs_threshold[]; static boolean_t threshold_chk_enabled = B_FALSE; CK_RV meta_operation_init_defer(CK_FLAGS optype, meta_session_t *session, CK_MECHANISM *pMechanism, meta_object_t *key) { if (session->init.pMech == NULL) { session->init.pMech = malloc(sizeof (CK_MECHANISM)); if (session->init.pMech == NULL) return (CKR_HOST_MEMORY); (void) memcpy(session->init.pMech, pMechanism, sizeof (CK_MECHANISM)); if ((pMechanism->ulParameterLen > 0) && (pMechanism->pParameter != NULL)) { session->init.pMech->pParameter = malloc(pMechanism->ulParameterLen); if (session->init.pMech->pParameter == NULL) { free(session->init.pMech); session->init.pMech = NULL; return (CKR_HOST_MEMORY); } (void) memcpy(session->init.pMech->pParameter, pMechanism->pParameter, pMechanism->ulParameterLen); } else { session->init.pMech->pParameter = NULL; } } else { /* reuse it */ if ((pMechanism->ulParameterLen > 0) && (pMechanism->pParameter != NULL)) { if (pMechanism->ulParameterLen != session->init.pMech->ulParameterLen) { if (session->init.pMech->pParameter != NULL) free(session->init.pMech->pParameter); session->init.pMech->pParameter = malloc(pMechanism->ulParameterLen); if (session->init.pMech->pParameter == NULL) { free(session->init.pMech); session->init.pMech = NULL; return (CKR_HOST_MEMORY); } } /* otherwise reuse it */ (void) memcpy(session->init.pMech->pParameter, pMechanism->pParameter, pMechanism->ulParameterLen); } else { /* * free the previous pParameter if not yet freed * because we don't need it now. */ if (session->init.pMech->pParameter != NULL) { free(session->init.pMech->pParameter); session->init.pMech->pParameter = NULL; } } /* copy the rest of data */ session->init.pMech->mechanism = pMechanism->mechanism; session->init.pMech->ulParameterLen = pMechanism->ulParameterLen; } session->init.session = session; session->init.optype = optype; session->init.key = key; session->init.done = B_FALSE; session->init.app = B_TRUE; return (CKR_OK); } /* * meta_operation_init * */ CK_RV meta_operation_init(CK_FLAGS optype, meta_session_t *session, CK_MECHANISM *pMechanism, meta_object_t *key) { CK_RV rv, save_rv; mechinfo_t **supporting_slots; CK_ULONG slotnum; unsigned long i, slotCount = 0; slot_session_t *init_session = NULL; CK_MECHANISM_INFO mech_info; /* * If an operation is already active, cleanup existing operation * and start a new one. */ if (session->op1.type != 0) { CK_MECHANISM mech; if ((optype == CKF_ENCRYPT) || (optype == CKF_DECRYPT) || (optype == CKF_DIGEST)) { mech = *pMechanism; if ((pMechanism->ulParameterLen > 0) && (pMechanism->pParameter != NULL)) { mech.pParameter = malloc(pMechanism->ulParameterLen); if (mech.pParameter == NULL) { return (CKR_HOST_MEMORY); } (void) memcpy(mech.pParameter, pMechanism->pParameter, pMechanism->ulParameterLen); } else { mech.pParameter = NULL; mech.ulParameterLen = 0; } meta_operation_cleanup(session, session->op1.type, B_FALSE); rv = meta_operation_init_defer(optype, session, &mech, key); if (mech.pParameter != NULL) { free(mech.pParameter); } if (rv != CKR_OK) return (rv); } else { meta_operation_cleanup(session, session->op1.type, B_FALSE); } } mech_info.flags = optype; /* * Get a list of capable slots. * * If the specified mechanism is used in this session last time, * the list of capable slots is already retrieved. We can save * some processing, and just use that list of slots. */ if (((session->mech_support_info).mech != pMechanism->mechanism) || ((session->mech_support_info).num_supporting_slots == 0)) { (session->mech_support_info).mech = pMechanism->mechanism; rv = meta_mechManager_get_slots(&(session->mech_support_info), B_FALSE, &mech_info); if (rv != CKR_OK) { goto finish; } } rv = CKR_FUNCTION_FAILED; /* The following 2 assignment is just to make the code more readable */ slotCount = (session->mech_support_info).num_supporting_slots; supporting_slots = (session->mech_support_info).supporting_slots; /* Attempt to initialize operation on slots until one succeeds. */ for (i = 0; i < slotCount; i++) { slot_object_t *init_key; CK_SLOT_ID fw_st_id; init_session = NULL; slotnum = supporting_slots[i]->slotnum; /* * An actual session with the underlying slot is required * for the operation. When the operation is successfully * completed, the underlying session with the slot * is not released back to the list of available sessions * pool. This will help if the next operation can * also be done on the same slot, because it avoids * one extra trip to the session pool to get an idle session. * If the operation can't be done on that slot, * we release the session back to the session pool then. */ if (session->op1.session != NULL) { if ((session->op1.session)->slotnum == slotnum) { init_session = session->op1.session; /* * set it to NULL for now, assign it to * init_session again if it is successful */ session->op1.session = NULL; } else { init_session = NULL; } } if (!init_session) { rv = meta_get_slot_session(slotnum, &init_session, session->session_flags); if (rv != CKR_OK) { goto loop_cleanup; } } /* if necessary, ensure a clone of the obj exists in slot */ if (optype != CKF_DIGEST) { rv = meta_object_get_clone(key, slotnum, init_session, &init_key); if (rv != CKR_OK) { goto loop_cleanup; } } fw_st_id = init_session->fw_st_id; switch (optype) { case CKF_ENCRYPT: rv = FUNCLIST(fw_st_id)->C_EncryptInit( init_session->hSession, pMechanism, init_key->hObject); break; case CKF_DECRYPT: rv = FUNCLIST(fw_st_id)->C_DecryptInit( init_session->hSession, pMechanism, init_key->hObject); break; case CKF_DIGEST: rv = FUNCLIST(fw_st_id)->C_DigestInit( init_session->hSession, pMechanism); break; case CKF_SIGN: rv = FUNCLIST(fw_st_id)->C_SignInit( init_session->hSession, pMechanism, init_key->hObject); break; case CKF_VERIFY: rv = FUNCLIST(fw_st_id)->C_VerifyInit( init_session->hSession, pMechanism, init_key->hObject); break; case CKF_SIGN_RECOVER: rv = FUNCLIST(fw_st_id)->C_SignRecoverInit( init_session->hSession, pMechanism, init_key->hObject); break; case CKF_VERIFY_RECOVER: rv = FUNCLIST(fw_st_id)->C_VerifyRecoverInit( init_session->hSession, pMechanism, init_key->hObject); break; default: /*NOTREACHED*/ rv = CKR_FUNCTION_FAILED; break; } if (rv == CKR_OK) break; loop_cleanup: if (i == 0) { save_rv = rv; } if (init_session) { meta_release_slot_session(init_session); init_session = NULL; } } if (rv == CKR_OK) { /* * If currently stored session is not the one being in use now, * release the previous one and store the current one */ if ((session->op1.session) && (session->op1.session != init_session)) { meta_release_slot_session(session->op1.session); } /* Save the session */ session->op1.session = init_session; session->op1.type = optype; session->init.slotnum = slotnum; session->init.done = B_TRUE; } else { rv = save_rv; } finish: return (rv); } /* * meta_operation_init_softtoken() * It will always do the crypto init operation on softtoken slot. */ CK_RV meta_operation_init_softtoken(CK_FLAGS optype, meta_session_t *session, CK_MECHANISM *pMechanism, meta_object_t *key) { CK_RV rv = CKR_FUNCTION_FAILED; slot_session_t *init_session = NULL; slot_object_t *init_key; CK_SLOT_ID fw_st_id; CK_ULONG softtoken_slot_num; softtoken_slot_num = get_softtoken_slotnum(); /* * If an operation is already active, cleanup existing operation * and start a new one. */ if (session->op1.type != 0) { CK_MECHANISM mech; mech = *pMechanism; if ((pMechanism->ulParameterLen > 0) && (pMechanism->pParameter != NULL)) { mech.pParameter = malloc(pMechanism->ulParameterLen); if (mech.pParameter == NULL) { return (CKR_HOST_MEMORY); } (void) memcpy(mech.pParameter, pMechanism->pParameter, pMechanism->ulParameterLen); } else { mech.pParameter = NULL; mech.ulParameterLen = 0; } meta_operation_cleanup(session, session->op1.type, B_FALSE); rv = meta_operation_init_defer(optype, session, &mech, key); if (mech.pParameter != NULL) { free(mech.pParameter); } if (rv != CKR_OK) return (rv); } /* * An actual session with the underlying slot is required * for the operation. When the operation is successfully * completed, the underlying session with the slot * is not released back to the list of available sessions * pool. This will help if the next operation can * also be done on the same slot, because it avoids * one extra trip to the session pool to get an idle session. * If the operation can't be done on that slot, * we release the session back to the session pool. */ if (session->op1.session != NULL) { if ((session->op1.session)->slotnum == softtoken_slot_num) { init_session = session->op1.session; /* * set it to NULL for now, assign it to * init_session again if it is successful */ session->op1.session = NULL; } else { init_session = NULL; } } if (init_session == NULL) { /* get the active session from softtoken slot */ rv = meta_get_slot_session(softtoken_slot_num, &init_session, session->session_flags); if (rv != CKR_OK) { goto finish; } } /* if necessary, ensure a clone of the obj exists in softtoken slot */ if (optype != CKF_DIGEST) { rv = meta_object_get_clone(key, softtoken_slot_num, init_session, &init_key); if (rv != CKR_OK) { if (init_session != NULL) { meta_release_slot_session(init_session); init_session = NULL; } goto finish; } } fw_st_id = init_session->fw_st_id; /* * Currently, we only support offloading encrypt, decrypt * and digest operations to softtoken based on kernel * threshold for the supported mechanisms. */ switch (optype) { case CKF_ENCRYPT: rv = FUNCLIST(fw_st_id)->C_EncryptInit( init_session->hSession, pMechanism, init_key->hObject); break; case CKF_DECRYPT: rv = FUNCLIST(fw_st_id)->C_DecryptInit( init_session->hSession, pMechanism, init_key->hObject); break; case CKF_DIGEST: rv = FUNCLIST(fw_st_id)->C_DigestInit( init_session->hSession, pMechanism); break; default: /*NOTREACHED*/ rv = CKR_FUNCTION_FAILED; break; } if (rv == CKR_OK) { /* * If currently stored session is not the one being in use now, * release the previous one and store the current one */ if ((session->op1.session) && (session->op1.session != init_session)) { meta_release_slot_session(session->op1.session); } /* Save the session */ session->op1.session = init_session; session->op1.type = optype; /* * The init.done flag will be checked by the meta_do_operation() * to indicate whether the C_xxxInit has been done against * softtoken. */ session->init.done = B_TRUE; session->init.slotnum = softtoken_slot_num; } finish: return (rv); } int meta_GetThreshold(CK_MECHANISM_TYPE mechanism) { int i; for (i = 0; i < MAX_NUM_THRESHOLD; i++) { if (mechanism == meta_mechs_threshold[i].mech_type) return (meta_mechs_threshold[i].mech_threshold); } /* no matching mechanism */ return (0); } /* * meta_do_operation * * NOTES: * * 1) The spec says you cannot do a C_Encrypt after a C_EncUpdate, * but we don't explicitly enforce it here (ie, disallow doing MODE_SINGLE * after a MODE_UPDATE). Instead, we just assume the underlying provider * will catch the problem and return an appropriate error. * * 2) Note that the Verify operations are a little unusual, due to the * PKCS#11 API. For C_Verify, the last two arguments are used as inputs, * unlike the other single pass operations (where they are outputs). For * C_VerifyFinal, in/inLen are passed instead of out/outLen like the other * Final operations. * * 3) C_DigestKey is the only crypto operation that uses an object after * the operation has been initialized. No other callers should provide * this argument (use NULL). */ CK_RV meta_do_operation(CK_FLAGS optype, int mode, meta_session_t *session, meta_object_t *object, CK_BYTE *in, CK_ULONG inLen, CK_BYTE *out, CK_ULONG *outLen) { CK_RV rv; CK_SESSION_HANDLE hSession; CK_SLOT_ID fw_st_id; slot_session_t *slot_session = NULL; slot_object_t *slot_object = NULL; int threshold = 0; boolean_t shutdown, finished_normally; /* * We've deferred the init for encrypt, decrypt and digest * operations. As we know the size of the input data now, we * can decide where to perform the real init operation based * on the kernel cipher-specific thresholds for certain * supported mechanisms. */ if ((optype == CKF_ENCRYPT) || (optype == CKF_DECRYPT) || (optype == CKF_DIGEST)) { if (Tmp_GetThreshold != NULL) { if (!session->init.app) { return (CKR_OPERATION_NOT_INITIALIZED); } threshold = meta_GetThreshold( session->init.pMech->mechanism); } if ((threshold_chk_enabled == B_FALSE) || (inLen > threshold)) { if ((session->init.app) && (!session->init.done)) { /* * Call real init operation only if the * application has called C_xxxInit * but the real init operation has not * been done. */ rv = meta_operation_init(optype, session->init.session, session->init.pMech, session->init.key); if (rv != CKR_OK) goto exit; } else if (!session->init.app) { /* * This checking detects the case that * application calls C_En(De)Crypt/Digest * directly without calling C_xxxInit. */ return (CKR_OPERATION_NOT_INITIALIZED); } } else { /* * The size of the input data is smaller than the * threshold so we'll use softoken to perform the * crypto operation for better performance reason. */ if ((session->init.app) && (!session->init.done)) { /* * Call real init operation only if the * application has called C_xxxInit * but the real init operation has not * been done. */ rv = meta_operation_init_softtoken(optype, session->init.session, session->init.pMech, session->init.key); if (rv != CKR_OK) { /* * In case the operation fails in * softtoken, go back to use the * original slot again. */ rv = meta_operation_init(optype, session->init.session, session->init.pMech, session->init.key); if (rv != CKR_OK) goto exit; } } else if (!session->init.app) { /* * This checking detects the case that * application calls C_En(De)Crypt/Digest * directly without calling C_xxxInit. */ return (CKR_OPERATION_NOT_INITIALIZED); } } } else if (optype != session->op1.type) { return (CKR_OPERATION_NOT_INITIALIZED); } slot_session = session->op1.session; if (slot_session) { hSession = slot_session->hSession; fw_st_id = slot_session->fw_st_id; } else { /* should never be here */ rv = CKR_FUNCTION_FAILED; goto exit; } /* Do the operation... */ if (optype == CKF_ENCRYPT && mode == MODE_SINGLE) { rv = FUNCLIST(fw_st_id)->C_Encrypt(hSession, in, inLen, out, outLen); } else if (optype == CKF_ENCRYPT && mode == MODE_UPDATE) { rv = FUNCLIST(fw_st_id)->C_EncryptUpdate(hSession, in, inLen, out, outLen); } else if (optype == CKF_ENCRYPT && mode == MODE_FINAL) { rv = FUNCLIST(fw_st_id)->C_EncryptFinal(hSession, out, outLen); } else if (optype == CKF_DECRYPT && mode == MODE_SINGLE) { rv = FUNCLIST(fw_st_id)->C_Decrypt(hSession, in, inLen, out, outLen); } else if (optype == CKF_DECRYPT && mode == MODE_UPDATE) { rv = FUNCLIST(fw_st_id)->C_DecryptUpdate(hSession, in, inLen, out, outLen); } else if (optype == CKF_DECRYPT && mode == MODE_FINAL) { rv = FUNCLIST(fw_st_id)->C_DecryptFinal(hSession, out, outLen); } else if (optype == CKF_DIGEST && mode == MODE_SINGLE) { rv = FUNCLIST(fw_st_id)->C_Digest(hSession, in, inLen, out, outLen); } else if (optype == CKF_DIGEST && mode == MODE_UPDATE) { /* noOutputForOp = TRUE; */ rv = FUNCLIST(fw_st_id)->C_DigestUpdate(hSession, in, inLen); } else if (optype == CKF_DIGEST && mode == MODE_UPDATE_WITHKEY) { /* noOutputForOp = TRUE; */ /* * For C_DigestKey, a key is provided and * we need the clone. */ rv = meta_object_get_clone(object, slot_session->slotnum, slot_session, &slot_object); if (rv == CKR_OK) rv = FUNCLIST(fw_st_id)->C_DigestKey(hSession, slot_object->hObject); } else if (optype == CKF_DIGEST && mode == MODE_FINAL) { rv = FUNCLIST(fw_st_id)->C_DigestFinal(hSession, out, outLen); } else if (optype == CKF_SIGN && mode == MODE_SINGLE) { rv = FUNCLIST(fw_st_id)->C_Sign(hSession, in, inLen, out, outLen); } else if (optype == CKF_SIGN && mode == MODE_UPDATE) { /* noOutputForOp = TRUE; */ rv = FUNCLIST(fw_st_id)->C_SignUpdate(hSession, in, inLen); } else if (optype == CKF_SIGN && mode == MODE_FINAL) { rv = FUNCLIST(fw_st_id)->C_SignFinal(hSession, out, outLen); } else if (optype == CKF_VERIFY && mode == MODE_SINGLE) { /* noOutputForOp = TRUE; */ /* Yes, use *outLen not outLen (think in2/in2Len) */ rv = FUNCLIST(fw_st_id)->C_Verify(hSession, in, inLen, out, *outLen); } else if (optype == CKF_VERIFY && mode == MODE_UPDATE) { /* noOutputForOp = TRUE; */ rv = FUNCLIST(fw_st_id)->C_VerifyUpdate(hSession, in, inLen); } else if (optype == CKF_VERIFY && mode == MODE_FINAL) { /* noOutputForOp = TRUE; */ /* Yes, use in/inLen instead of out/outLen */ rv = FUNCLIST(fw_st_id)->C_VerifyFinal(hSession, in, inLen); } else if (optype == CKF_SIGN_RECOVER && mode == MODE_SINGLE) { rv = FUNCLIST(fw_st_id)->C_SignRecover(hSession, in, inLen, out, outLen); } else if (optype == CKF_VERIFY_RECOVER && mode == MODE_SINGLE) { rv = FUNCLIST(fw_st_id)->C_VerifyRecover(hSession, in, inLen, out, outLen); } else { rv = CKR_FUNCTION_FAILED; } /* * Mark the operation type as inactive if an abnormal error * happens, or if the operation normally results in an inactive * operation state. * * NOTE: The spec isn't very explicit about what happens when you * call C_FooFinal (or C_Foo) with a NULL output buffer (to get the * output size), but there is no output. Technically this should be * no different than the normal case (ie, when there is output), and * the operation should remain active until the second call actually * terminates it. However, one could make the case that there is no * need for a second call, since no data is available. This presents * dilemma for metaslot, because we don't know if the operation is * going to remain active or not. We will assume a strict reading of * the spec, the operation will remain active. */ exit: if (rv == CKR_BUFFER_TOO_SMALL || (rv == CKR_OK && out == NULL && optype != CKF_VERIFY)) { /* Leave op active for retry (with larger buffer). */ shutdown = B_FALSE; } else if (rv != CKR_OK) { shutdown = B_TRUE; finished_normally = B_FALSE; } else { /* CKR_OK */ if (mode == MODE_SINGLE || mode == MODE_FINAL) { shutdown = B_TRUE; finished_normally = B_TRUE; } else { /* mode == MODE_UPDATE */ shutdown = B_FALSE; } } if (shutdown) { if (mode == MODE_SINGLE || mode == MODE_FINAL) { session->init.app = B_FALSE; } meta_operation_cleanup(session, optype, finished_normally); } return (rv); } void free_session_mechanism(meta_session_t *session) { if (session->init.pMech != NULL) { if (session->init.pMech->pParameter != NULL) { free(session->init.pMech->pParameter); session->init.pMech->pParameter = NULL; session->init.pMech->ulParameterLen = 0; } free(session->init.pMech); session->init.pMech = NULL; } } /* * meta_operation_cleanup * * Cleans up an operation in the specified session. * If the operation did not finish normally, it will force * the operation to terminate. */ void meta_operation_cleanup(meta_session_t *session, CK_FLAGS optype, boolean_t finished_normally) { operation_info_t *op; CK_SESSION_HANDLE hSession; CK_SLOT_ID fw_st_id; if (!finished_normally) { CK_BYTE dummy_buf[8]; if (session->op1.type == optype) { op = &session->op1; } else { if ((optype == CKF_ENCRYPT) || (optype == CKF_DECRYPT) || (optype == CKF_DIGEST)) { session->op1.type = 0; session->init.app = B_FALSE; session->init.done = B_FALSE; free_session_mechanism(session); } return; } hSession = op->session->hSession; fw_st_id = op->session->fw_st_id; /* * There's no simple, reliable way to abort an * operation. So, we'll force the operation to finish. * * We are here either because we need to abort either after * C_xxxxxInit() or C_xxxxxUpdate(). * * We will call C_xxxxxUpdate() with invalid argument to * force the operation to abort. According to the PKCS#11 * spec, any call to C_xxxxxUpdate() returns in an error * will terminate the current operation. */ switch (optype) { case CKF_ENCRYPT: (void) FUNCLIST(fw_st_id)->C_EncryptUpdate(hSession, NULL, 8, dummy_buf, NULL); break; case CKF_DECRYPT: (void) FUNCLIST(fw_st_id)->C_DecryptUpdate(hSession, NULL, 8, dummy_buf, NULL); break; case CKF_DIGEST: (void) FUNCLIST(fw_st_id)->C_DigestUpdate(hSession, NULL, 8); break; case CKF_SIGN: (void) FUNCLIST(fw_st_id)->C_SignUpdate(hSession, NULL, 8); break; case CKF_SIGN_RECOVER: (void) FUNCLIST(fw_st_id)->C_SignRecover(hSession, NULL, 8, dummy_buf, NULL); break; case CKF_VERIFY: (void) FUNCLIST(fw_st_id)->C_VerifyUpdate(hSession, NULL, 8); break; case CKF_VERIFY_RECOVER: (void) FUNCLIST(fw_st_id)->C_VerifyRecover(hSession, NULL, 8, dummy_buf, NULL); break; default: /*NOTREACHED*/ break; } meta_release_slot_session(session->op1.session); session->op1.session = NULL; } if ((optype == CKF_ENCRYPT) || (optype == CKF_DECRYPT) || (optype == CKF_DIGEST)) { session->init.done = B_FALSE; free_session_mechanism(session); } session->op1.type = 0; } /* * Gets the list of slots that supports the specified mechanism. * * If "token_only", check if the keystore slot supports the specified mech, * if so, return that slot only * * Otherwise, get list of all slots that support the mech. * */ static CK_RV get_slotlist_for_mech(CK_MECHANISM_TYPE mech_type, mech_support_info_t *mech_support_info, mechinfo_t ***slots, unsigned long *slot_count, boolean_t token_only, CK_MECHANISM_INFO *mech_info) { boolean_t mech_supported = B_FALSE; CK_RV rv = CKR_OK; if (token_only) { rv = meta_mechManager_slot_supports_mech(mech_type, get_keystore_slotnum(), &mech_supported, &((mech_support_info->supporting_slots)[0]), B_FALSE, mech_info); if (rv != CKR_OK) { return (rv); } if (mech_supported) { mech_support_info->mech = mech_type; /* * Want to leave this at 0, that way, when * other operation needs to * use this mechanism, but not just for the * keystore slot, we will look at other slots */ mech_support_info->num_supporting_slots = 0; *slots = mech_support_info->supporting_slots; *slot_count = 1; } else { rv = CKR_FUNCTION_FAILED; } } else { /* * Get a list of slots that support this mech . * * If the specified mechanism is used last time, * the list of capable slots is already retrieved. * We can save some processing, and just use that list of slots. */ if ((mech_support_info->mech != mech_type) || (mech_support_info->num_supporting_slots == 0)) { mech_support_info->mech = mech_type; rv = meta_mechManager_get_slots(mech_support_info, B_FALSE, mech_info); if (rv != CKR_OK) { return (CKR_FUNCTION_FAILED); } } *slots = mech_support_info->supporting_slots; *slot_count = mech_support_info->num_supporting_slots; } return (rv); } /* * meta_generate_keys * * Generates symmetric (k1=key, k2=null) or asymmetric (k1=pub, k2=priv) keys. * */ CK_RV meta_generate_keys(meta_session_t *session, CK_MECHANISM *pMechanism, CK_ATTRIBUTE *k1Template, CK_ULONG k1AttrCount, meta_object_t *key1, CK_ATTRIBUTE *k2Template, CK_ULONG k2AttrCount, meta_object_t *key2) { CK_RV rv, save_rv; slot_session_t *gen_session = NULL; slot_object_t *slot_key1 = NULL, *slot_key2 = NULL; mechinfo_t **slots = NULL; unsigned long i, slotCount = 0; boolean_t doKeyPair = B_FALSE, token_only = B_FALSE; CK_ULONG slotnum; CK_MECHANISM_INFO mech_info; /* * Since the keygen call is in a loop, it is performance-wise useful * to keep track of the token value */ CK_BBOOL current_token1_value = FALSE, current_token2_value = FALSE; (void) get_template_boolean(CKA_TOKEN, k1Template, k1AttrCount, &(key1->isToken)); (void) get_template_boolean(CKA_SENSITIVE, k1Template, k1AttrCount, &(key1->isSensitive)); (void) get_template_boolean(CKA_PRIVATE, k1Template, k1AttrCount, &(key1->isPrivate)); if (!get_template_boolean(CKA_EXTRACTABLE, k1Template, k1AttrCount, &(key1->isExtractable))) key1->isExtractable = B_TRUE; if (key1->isToken) current_token1_value = TRUE; mech_info.flags = CKF_GENERATE; if (key2) { (void) get_template_boolean(CKA_TOKEN, k2Template, k2AttrCount, &(key2->isToken)); (void) get_template_boolean(CKA_SENSITIVE, k2Template, k2AttrCount, &(key2->isSensitive)); (void) get_template_boolean(CKA_PRIVATE, k2Template, k2AttrCount, &(key2->isPrivate)); if (!get_template_boolean(CKA_EXTRACTABLE, k2Template, k2AttrCount, &(key2->isExtractable))) key2->isExtractable = B_TRUE; if (key2->isToken) current_token2_value = TRUE; doKeyPair = B_TRUE; mech_info.flags = CKF_GENERATE_KEY_PAIR; } /* Can't create token objects in a read-only session. */ if ((IS_READ_ONLY_SESSION(session->session_flags)) && ((key1->isToken) || ((key2) && (key2->isToken)))) { return (CKR_SESSION_READ_ONLY); } if (meta_freeobject_check(session, key1, pMechanism, k1Template, k1AttrCount, 0)) { if ((key1->isPrivate || (doKeyPair && key2->isPrivate)) && !metaslot_logged_in()) return (CKR_USER_NOT_LOGGED_IN); if (!meta_freeobject_set(key1, k1Template, k1AttrCount, B_FALSE)) return (CKR_FUNCTION_FAILED); if (doKeyPair) { key2->isFreeObject = FREE_ALLOWED_KEY; if (!meta_freeobject_set(key2, k2Template, k2AttrCount, B_FALSE)) return (CKR_FUNCTION_FAILED); } } else if (doKeyPair) { /* * If this is a keypair operation, the second key cannot be * a FreeObject if the first is not. Both keys will have the * same fate when it comes to provider choices */ key2->isFreeObject = FREE_DISABLED; key2->isFreeToken = FREE_DISABLED; } if ((key1->isToken) || ((doKeyPair) && (key2->isToken))) { /* * Token objects can only be generated in the token object * slot. If token object slot doesn't support generating * the key, it will just not be done. */ token_only = B_TRUE; } rv = get_slotlist_for_mech(pMechanism->mechanism, &(session->mech_support_info), &slots, &slotCount, token_only, &mech_info); if (rv != CKR_OK) { goto finish; } rv = meta_slot_object_alloc(&slot_key1); if (doKeyPair && rv == CKR_OK) rv = meta_slot_object_alloc(&slot_key2); if (rv != CKR_OK) goto finish; /* Attempt to generate key on slots until one succeeds. */ for (i = 0; i < slotCount; i++) { CK_SESSION_HANDLE hSession; CK_SLOT_ID fw_st_id; gen_session = NULL; slotnum = slots[i]->slotnum; if (session->op1.session != NULL) { if ((session->op1.session)->slotnum == slotnum) { gen_session = session->op1.session; /* * set it to NULL for now, assign it to * gen_session again if it is successful */ session->op1.session = NULL; } else { gen_session = NULL; } } if (gen_session == NULL) { rv = meta_get_slot_session(slotnum, &gen_session, session->session_flags); if (rv != CKR_OK) { goto loop_cleanup; } } /* * If this is a freetoken, make sure the templates are * approriate for the slot being used. */ if (key1->isFreeToken == FREE_ENABLED) { rv = meta_freetoken_set(slotnum, ¤t_token1_value, k1Template, k1AttrCount); if (rv != CKR_OK) goto loop_cleanup; } if (doKeyPair && key2->isFreeToken == FREE_ENABLED) { rv = meta_freetoken_set(slotnum, ¤t_token2_value, k2Template, k2AttrCount); if (rv != CKR_OK) goto loop_cleanup; } fw_st_id = gen_session->fw_st_id; hSession = gen_session->hSession; if (doKeyPair) { rv = FUNCLIST(fw_st_id)->C_GenerateKeyPair(hSession, pMechanism, k1Template, k1AttrCount, k2Template, k2AttrCount, &slot_key1->hObject, &slot_key2->hObject); } else { rv = FUNCLIST(fw_st_id)->C_GenerateKey(hSession, pMechanism, k1Template, k1AttrCount, &slot_key1->hObject); } if (rv == CKR_OK) break; loop_cleanup: if (i == 0) { save_rv = rv; } if (gen_session) { meta_release_slot_session(gen_session); gen_session = NULL; } } if (rv != CKR_OK) { rv = save_rv; goto finish; } rv = meta_object_get_attr(gen_session, slot_key1->hObject, key1); if (rv != CKR_OK) { goto finish; } if (key2) { rv = meta_object_get_attr(gen_session, slot_key2->hObject, key2); if (rv != CKR_OK) { goto finish; } } /* Allow FreeToken to activate onto token obj list */ if (key1->isFreeToken == FREE_ENABLED) key1->isToken = B_TRUE; meta_slot_object_activate(slot_key1, gen_session, key1->isToken); key1->clones[slotnum] = slot_key1; key1->master_clone_slotnum = slotnum; slot_key1 = NULL; if (key1->isFreeObject == FREE_ENABLED) { rv = meta_freeobject_clone(session, key1); if (rv != CKR_OK) goto finish; } if (doKeyPair) { /* Allow FreeToken to activate onto token obj list */ if (key2->isFreeToken == FREE_ENABLED) key2->isToken = B_TRUE; meta_slot_object_activate(slot_key2, gen_session, key2->isToken); key2->clones[slotnum] = slot_key2; key2->master_clone_slotnum = slotnum; slot_key2 = NULL; if (key2->isFreeObject == FREE_ENABLED) { rv = meta_freeobject_clone(session, key2); if (rv != CKR_OK) goto finish; } } finish: if (slot_key1) { meta_slot_object_dealloc(slot_key1); } if (slot_key2) { meta_slot_object_dealloc(slot_key2); } /* Save the session in case it can be used later */ if (rv == CKR_OK) { /* * If currently stored session is not the one being in use now, * release the previous one and store the current one */ if ((session->op1.session) && (session->op1.session != gen_session)) { meta_release_slot_session(session->op1.session); } /* Save the session */ session->op1.session = gen_session; } return (rv); } /* * meta_wrap_key * */ CK_RV meta_wrap_key(meta_session_t *session, CK_MECHANISM *pMechanism, meta_object_t *wrappingkey, meta_object_t *inputkey, CK_BYTE *wrapped_key, CK_ULONG *wrapped_key_len) { CK_RV rv, save_rv; slot_session_t *wrap_session = NULL; slot_object_t *slot_wrappingkey, *slot_inputkey; mechinfo_t **slots = NULL; unsigned long i, slotCount = 0; CK_ULONG slotnum; CK_MECHANISM_INFO mech_info; /* * If the key to be wrapped is a token object, * the operation can only be done in the token object slot. */ mech_info.flags = CKF_WRAP; rv = get_slotlist_for_mech(pMechanism->mechanism, &(session->mech_support_info), &slots, &slotCount, inputkey->isToken, &mech_info); if (rv != CKR_OK) { return (rv); } /* Attempt to wrap key on slots until one succeeds. */ for (i = 0; i < slotCount; i++) { slotnum = slots[i]->slotnum; wrap_session = NULL; if (session->op1.session != NULL) { if ((session->op1.session)->slotnum == slotnum) { wrap_session = session->op1.session; /* * set it to NULL for now, assign it to * wrap_session again if it is successful */ session->op1.session = NULL; } else { wrap_session = NULL; } } if (wrap_session == NULL) { rv = meta_get_slot_session(slotnum, &wrap_session, session->session_flags); if (rv != CKR_OK) { goto loop_cleanup; } } rv = meta_object_get_clone(wrappingkey, slotnum, wrap_session, &slot_wrappingkey); if (rv != CKR_OK) goto loop_cleanup; rv = meta_object_get_clone(inputkey, slotnum, wrap_session, &slot_inputkey); if (rv != CKR_OK) goto loop_cleanup; rv = FUNCLIST(wrap_session->fw_st_id)->C_WrapKey( wrap_session->hSession, pMechanism, slot_wrappingkey->hObject, slot_inputkey->hObject, wrapped_key, wrapped_key_len); if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) break; loop_cleanup: if (i == 0) { save_rv = rv; } if (wrap_session) { meta_release_slot_session(wrap_session); wrap_session = NULL; } } if (rv != CKR_OK) { if (rv != CKR_BUFFER_TOO_SMALL) { if (i == slotCount) { rv = save_rv; } } } /* Save the session in case it can be used later */ if (rv == CKR_OK) { /* * If currently stored session is not the one being in use now, * release the previous one and store the current one */ if ((session->op1.session) && (session->op1.session != wrap_session)) { meta_release_slot_session(session->op1.session); } /* Save the session */ session->op1.session = wrap_session; } return (rv); } /* * meta_unwrap_key * */ CK_RV meta_unwrap_key(meta_session_t *session, CK_MECHANISM *pMechanism, meta_object_t *unwrapping_key, CK_BYTE *wrapped_key, CK_ULONG wrapped_key_len, CK_ATTRIBUTE *template, CK_ULONG template_size, meta_object_t *unwrapped_key) { CK_RV rv, save_rv; CK_OBJECT_HANDLE hUnwrappedKey; slot_session_t *unwrap_session = NULL; slot_object_t *slot_unwrappingkey, *slot_unwrapped_key; mechinfo_t **slots = NULL; unsigned long i, slotCount = 0; CK_ULONG slotnum; CK_MECHANISM_INFO mech_info; /* Can't create token objects in a read-only session. */ if ((IS_READ_ONLY_SESSION(session->session_flags)) && unwrapped_key->isToken) { return (CKR_SESSION_READ_ONLY); } /* * If the the resulting unwrapped key * needs to be a token object, the operation can only * be performed in the token slot, if it is supported. */ mech_info.flags = CKF_UNWRAP; rv = get_slotlist_for_mech(pMechanism->mechanism, &(session->mech_support_info), &slots, &slotCount, unwrapped_key->isToken, &mech_info); if (rv != CKR_OK) { return (rv); } rv = meta_slot_object_alloc(&slot_unwrapped_key); if (rv != CKR_OK) { goto finish; } /* Attempt to unwrap key on slots until one succeeds. */ for (i = 0; i < slotCount; i++) { slotnum = slots[i]->slotnum; unwrap_session = NULL; if (session->op1.session != NULL) { if ((session->op1.session)->slotnum == slotnum) { unwrap_session = session->op1.session; /* * set it to NULL for now, assign it to * unwrap_session again if it is successful */ session->op1.session = NULL; } else { unwrap_session = NULL; } } if (unwrap_session == NULL) { rv = meta_get_slot_session(slotnum, &unwrap_session, session->session_flags); if (rv != CKR_OK) { goto loop_cleanup; } } rv = meta_object_get_clone(unwrapping_key, slotnum, unwrap_session, &slot_unwrappingkey); if (rv != CKR_OK) goto loop_cleanup; rv = FUNCLIST(unwrap_session->fw_st_id)->C_UnwrapKey( unwrap_session->hSession, pMechanism, slot_unwrappingkey->hObject, wrapped_key, wrapped_key_len, template, template_size, &hUnwrappedKey); if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) break; loop_cleanup: if (i == 0) { save_rv = rv; } if (unwrap_session) { meta_release_slot_session(unwrap_session); unwrap_session = NULL; } } if (rv != CKR_OK) { if (rv != CKR_BUFFER_TOO_SMALL) { rv = save_rv; } goto finish; } slot_unwrapped_key->hObject = hUnwrappedKey; unwrapped_key->clones[slotnum] = slot_unwrapped_key; unwrapped_key->master_clone_slotnum = slotnum; rv = meta_object_get_attr(unwrap_session, slot_unwrapped_key->hObject, unwrapped_key); if (rv != CKR_OK) { goto finish; } meta_slot_object_activate(slot_unwrapped_key, unwrap_session, unwrapped_key->isToken); slot_unwrapped_key = NULL; finish: if (slot_unwrapped_key) { meta_slot_object_dealloc(slot_unwrapped_key); } /* Save the session in case it can be used later */ if (rv == CKR_OK) { /* * If currently stored session is not the one being in use now, * release the previous one and store the current one */ if ((session->op1.session) && (session->op1.session != unwrap_session)) { meta_release_slot_session(session->op1.session); } /* Save the session */ session->op1.session = unwrap_session; } return (rv); } /* * meta_derive_key * * Core implementation for C_DeriveKey. This function is a bit gross because * of PKCS#11 kludges that pass extra object handles in the mechanism * parameters. Normally C_DeriveKey takes a single existing key as input, * and creates a single new key as output. But a few mechanisms take 2 keys * as input, and the two SSL/TLS mechanisms create 4 keys as output. * * When an extra input key (basekey2) is set, we set *phBaseKey2 to the clone's * object handle. phBaseKey2 is provided by the caller so we don't have to * trudge down into different mechanism parameters to set it when issuing the * operation. * * For the SSL/TLS mechanisms, newKey2/newKey3/newKey4 will be set. We pull * the new handles from pMech->pParameter in order to fill in the appropriate * meta_object fields. */ CK_RV meta_derive_key(meta_session_t *session, CK_MECHANISM *pMechanism, meta_object_t *basekey1, meta_object_t *basekey2, CK_OBJECT_HANDLE *phBaseKey2, CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount, meta_object_t *newKey1, meta_object_t *newKey2, meta_object_t *newKey3, meta_object_t *newKey4) { CK_RV rv, save_rv; CK_OBJECT_HANDLE hDerivedKey; CK_ULONG slotnum; boolean_t isSSL = B_FALSE; boolean_t isTLSPRF = B_FALSE; mechinfo_t **slots = NULL; unsigned long i, slot_count = 0; slot_session_t *derive_session = NULL; slot_object_t *slot_basekey1 = NULL, *slot_basekey2 = NULL; slot_object_t *slotkey1 = NULL, *slotkey2 = NULL, *slotkey3 = NULL, *slotkey4 = NULL; CK_MECHANISM_INFO mech_info; CK_BBOOL current_token_value = FALSE; /* * if the derived key needs to be a token object, can only * perform the derive operation in the token slot */ (void) get_template_boolean(CKA_TOKEN, pTemplate, ulAttributeCount, &(newKey1->isToken)); (void) get_template_boolean(CKA_PRIVATE, pTemplate, ulAttributeCount, &(newKey1->isPrivate)); (void) get_template_boolean(CKA_SENSITIVE, pTemplate, ulAttributeCount, &(newKey1->isSensitive)); if (newKey1->isToken) current_token_value = TRUE; /* Can't create token objects in a read-only session. */ if ((IS_READ_ONLY_SESSION(session->session_flags)) && newKey1->isToken) { rv = CKR_SESSION_READ_ONLY; goto finish; } if (meta_freeobject_check(session, newKey1, pMechanism, pTemplate, ulAttributeCount, 0)) { if (newKey1->isPrivate && !metaslot_logged_in()) return (CKR_USER_NOT_LOGGED_IN); if (!meta_freeobject_set(newKey1, pTemplate, ulAttributeCount, B_FALSE)) return (CKR_FUNCTION_FAILED); } mech_info.flags = CKF_DERIVE; rv = get_slotlist_for_mech(pMechanism->mechanism, &(session->mech_support_info), &slots, &slot_count, newKey1->isToken, &mech_info); if (rv != CKR_OK) { return (rv); } if (pMechanism->mechanism == CKM_SSL3_KEY_AND_MAC_DERIVE || pMechanism->mechanism == CKM_TLS_KEY_AND_MAC_DERIVE) isSSL = B_TRUE; else if (pMechanism->mechanism == CKM_TLS_PRF) isTLSPRF = B_TRUE; rv = meta_slot_object_alloc(&slotkey1); if (isSSL) { if (rv == CKR_OK) rv = meta_slot_object_alloc(&slotkey2); if (rv == CKR_OK) rv = meta_slot_object_alloc(&slotkey3); if (rv == CKR_OK) rv = meta_slot_object_alloc(&slotkey4); } if (rv != CKR_OK) { goto finish; } for (i = 0; i < slot_count; i++) { slotnum = slots[i]->slotnum; derive_session = NULL; if (session->op1.session != NULL) { if ((session->op1.session)->slotnum == slotnum) { derive_session = session->op1.session; /* * set it to NULL for now, assign it to * derive_session again if it is successful */ session->op1.session = NULL; } else { derive_session = NULL; } } if (derive_session == NULL) { rv = meta_get_slot_session(slotnum, &derive_session, session->session_flags); if (rv != CKR_OK) { goto loop_cleanup; } } rv = meta_object_get_clone(basekey1, slotnum, derive_session, &slot_basekey1); if (rv != CKR_OK) goto loop_cleanup; if (basekey2) { rv = meta_object_get_clone(basekey2, slotnum, derive_session, &slot_basekey2); if (rv != CKR_OK) goto loop_cleanup; /* Pass the handle somewhere in the mech params. */ *phBaseKey2 = slot_basekey2->hObject; } if (newKey1->isFreeToken == FREE_ENABLED) { rv = meta_freetoken_set(slotnum, ¤t_token_value, pTemplate, ulAttributeCount); if (rv != CKR_OK) goto loop_cleanup; } rv = FUNCLIST(derive_session->fw_st_id)->C_DeriveKey( derive_session->hSession, pMechanism, slot_basekey1->hObject, pTemplate, ulAttributeCount, (isSSL || isTLSPRF) ? NULL : &hDerivedKey); if (rv == CKR_OK) break; loop_cleanup: if (i == 0) { save_rv = rv; } if (derive_session) { meta_release_slot_session(derive_session); derive_session = NULL; } /* No need to cleanup clones, so we can reuse them later. */ } if (rv != CKR_OK) { rv = save_rv; goto finish; } if (isTLSPRF) goto finish; /* * These SSL/TLS are unique in that the parameter in the API for * the new key is unused (NULL). Instead, there are 4 keys which * are derived, and are passed back through the mechanism params. * Both mechs use the same mechanism parameter type. */ if (isSSL) { CK_SSL3_KEY_MAT_PARAMS *keyparams; CK_SSL3_KEY_MAT_OUT *keys; /* NULL checks already done by caller */ keyparams = (CK_SSL3_KEY_MAT_PARAMS*)pMechanism->pParameter; keys = keyparams->pReturnedKeyMaterial; slotkey1->hObject = keys->hClientMacSecret; slotkey2->hObject = keys->hServerMacSecret; slotkey3->hObject = keys->hClientKey; slotkey4->hObject = keys->hServerKey; rv = meta_object_get_attr(derive_session, slotkey1->hObject, newKey1); if (rv != CKR_OK) { goto finish; } rv = meta_object_get_attr(derive_session, slotkey2->hObject, newKey2); if (rv != CKR_OK) { goto finish; } rv = meta_object_get_attr(derive_session, slotkey3->hObject, newKey3); if (rv != CKR_OK) { goto finish; } rv = meta_object_get_attr(derive_session, slotkey4->hObject, newKey4); if (rv != CKR_OK) { goto finish; } newKey1->clones[slotnum] = slotkey1; newKey2->clones[slotnum] = slotkey2; newKey3->clones[slotnum] = slotkey3; newKey4->clones[slotnum] = slotkey4; newKey1->master_clone_slotnum = slotnum; newKey2->master_clone_slotnum = slotnum; newKey3->master_clone_slotnum = slotnum; newKey4->master_clone_slotnum = slotnum; meta_slot_object_activate(slotkey1, derive_session, newKey1->isToken); slotkey1 = NULL; meta_slot_object_activate(slotkey2, derive_session, newKey2->isToken); slotkey2 = NULL; meta_slot_object_activate(slotkey3, derive_session, newKey3->isToken); slotkey3 = NULL; meta_slot_object_activate(slotkey4, derive_session, newKey4->isToken); slotkey4 = NULL; } else { slotkey1->hObject = hDerivedKey; newKey1->clones[slotnum] = slotkey1; newKey1->master_clone_slotnum = slotnum; rv = meta_object_get_attr(derive_session, slotkey1->hObject, newKey1); if (rv != CKR_OK) { goto finish; } /* Allow FreeToken to activate onto token obj list */ if (newKey1->isFreeToken == FREE_ENABLED) newKey1->isToken = B_TRUE; meta_slot_object_activate(slotkey1, derive_session, newKey1->isToken); slotkey1 = NULL; } if (newKey1->isFreeObject == FREE_ENABLED) (void) meta_freeobject_clone(session, newKey1); finish: if (slotkey1) { meta_slot_object_dealloc(slotkey1); } if (slotkey2) { meta_slot_object_dealloc(slotkey2); } if (slotkey3) { meta_slot_object_dealloc(slotkey3); } if (slotkey4) { meta_slot_object_dealloc(slotkey4); } /* Save the session in case it can be used later */ if (rv == CKR_OK) { /* * If currently stored session is not the one being in use now, * release the previous one and store the current one */ if ((session->op1.session) && (session->op1.session != derive_session)) { meta_release_slot_session(session->op1.session); } /* Save the session */ session->op1.session = derive_session; } return (rv); } /* * Check the following 4 environment variables for user/application's * configuration for metaslot. User's configuration takes precedence * over the system wide configuration for metaslot * * ${METASLOT_ENABLED} * ${METASLOT_OBJECTSTORE_SLOT} * ${METASLOT_OBJECTSTORE_TOKEN} * ${METASLOT_AUTO_KEY_MIGRATE} * * ${_METASLOT_ENABLE_THRESHOLD} - private environmental variable to * enable the treshold checking which is disabled by default. * * values defined in these environment variables will be stored in the * global variable "metaslot_config". Variable threshold_chk_disabled is an * exception. */ void get_user_metaslot_config() { char *env_val = NULL; /* * Check to see if any environment variable is defined * by the user for configuring metaslot. */ bzero(&metaslot_config, sizeof (metaslot_config)); /* METASLOT_ENABLED */ env_val = getenv("METASLOT_ENABLED"); if (env_val) { metaslot_config.enabled_specified = B_TRUE; if (strcasecmp(env_val, TRUE_STRING) == 0) { metaslot_config.enabled = B_TRUE; } else if (strcasecmp(env_val, FALSE_STRING) == 0) { metaslot_config.enabled = B_FALSE; } else { /* value is neither 1 or 0, ignore this value */ metaslot_config.enabled_specified = B_FALSE; } } /* METASLOT_AUTO_KEY_MIGRATE */ env_val = getenv("METASLOT_AUTO_KEY_MIGRATE"); if (env_val) { metaslot_config.auto_key_migrate_specified = B_TRUE; if (strcasecmp(env_val, TRUE_STRING) == 0) { metaslot_config.auto_key_migrate = B_TRUE; } else if (strcasecmp(env_val, FALSE_STRING) == 0) { metaslot_config.auto_key_migrate = B_FALSE; } else { /* value is neither 1 or 0, ignore this value */ metaslot_config.auto_key_migrate_specified = B_FALSE; } } /* METASLOT_OBJECTSTORE_SLOT */ env_val = getenv("METASLOT_OBJECTSTORE_SLOT"); if (env_val) { metaslot_config.keystore_slot_specified = B_TRUE; (void) strlcpy((char *)metaslot_config.keystore_slot, env_val, SLOT_DESCRIPTION_SIZE); } /* METASLOT_OBJECTSTORE_TOKEN */ env_val = getenv("METASLOT_OBJECTSTORE_TOKEN"); if (env_val) { metaslot_config.keystore_token_specified = B_TRUE; (void) strlcpy((char *)metaslot_config.keystore_token, env_val, TOKEN_LABEL_SIZE); } /* _METASLOT_ENABLE_THRESHOLD */ env_val = getenv("_METASLOT_ENABLE_THRESHOLD"); if (env_val) { threshold_chk_enabled = B_TRUE; } } /* * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Functions for Verifying Signatures and MACS * (as defined in PKCS#11 spec section 11.13) */ #include "metaGlobal.h" /* * meta_VerifyInit * */ CK_RV meta_VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { CK_RV rv; meta_session_t *session; meta_object_t *key; if (pMechanism == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_handle2object(hKey, &key); if (rv != CKR_OK) { REFRELEASE(session); return (rv); } rv = meta_operation_init(CKF_VERIFY, session, pMechanism, key); OBJRELEASE(key); REFRELEASE(session); return (rv); } /* * meta_Verify * */ CK_RV meta_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { CK_RV rv; meta_session_t *session; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); /* Note: unlike other ops, both buffers are inputs, and required. */ if (pData == NULL || pSignature == NULL) { meta_operation_cleanup(session, CKF_VERIFY, FALSE); REFRELEASE(session); return (CKR_ARGUMENTS_BAD); } rv = meta_do_operation(CKF_VERIFY, MODE_SINGLE, session, NULL, pData, ulDataLen, pSignature, &ulSignatureLen); REFRELEASE(session); return (rv); } /* * meta_VerifyUpdate * */ CK_RV meta_VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { CK_RV rv; meta_session_t *session; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); if (pPart == NULL) { meta_operation_cleanup(session, CKF_VERIFY, FALSE); REFRELEASE(session); return (CKR_ARGUMENTS_BAD); } rv = meta_do_operation(CKF_VERIFY, MODE_UPDATE, session, NULL, pPart, ulPartLen, NULL, NULL); REFRELEASE(session); return (rv); } /* * meta_VerifyFinal * */ CK_RV meta_VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { CK_RV rv; meta_session_t *session; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); /* * Unlike other ops the buffer is an input. Allow NULL if there's * no more input. */ if (pSignature == NULL && ulSignatureLen != 0) { meta_operation_cleanup(session, CKF_VERIFY, FALSE); REFRELEASE(session); return (CKR_ARGUMENTS_BAD); } rv = meta_do_operation(CKF_VERIFY, MODE_FINAL, session, NULL, pSignature, ulSignatureLen, NULL, NULL); REFRELEASE(session); return (rv); } /* * meta_VerifyRecoverInit * */ CK_RV meta_VerifyRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { CK_RV rv; meta_session_t *session; meta_object_t *key; if (pMechanism == NULL) return (CKR_ARGUMENTS_BAD); rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); rv = meta_handle2object(hKey, &key); if (rv != CKR_OK) { REFRELEASE(session); return (rv); } rv = meta_operation_init(CKF_VERIFY_RECOVER, session, pMechanism, key); OBJRELEASE(key); REFRELEASE(session); return (rv); } /* * meta_VerifyRecover * */ CK_RV meta_VerifyRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { CK_RV rv; meta_session_t *session; rv = meta_handle2session(hSession, &session); if (rv != CKR_OK) return (rv); if (pSignature == NULL || pulDataLen == NULL) { meta_operation_cleanup(session, CKF_VERIFY_RECOVER, FALSE); REFRELEASE(session); return (CKR_ARGUMENTS_BAD); } rv = meta_do_operation(CKF_VERIFY_RECOVER, MODE_SINGLE, session, NULL, pSignature, ulSignatureLen, pData, pulDataLen); REFRELEASE(session); return (rv); } /* * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 2010 Nexenta Systems, Inc. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pkcs11Global.h" #include "pkcs11Conf.h" #include "pkcs11Slot.h" #include "metaGlobal.h" /* * Fastpath is used when there is only one slot available from a single provider * plugged into the framework this is the common case. * These globals are used to track the function pointers and policy when * the fast-path is activated. * This will need to be revisted if per-slot policy is ever * implemented. */ boolean_t purefastpath = B_FALSE; boolean_t policyfastpath = B_FALSE; CK_FUNCTION_LIST_PTR fast_funcs = NULL; CK_SLOT_ID fast_slot = 0; boolean_t metaslot_enabled = B_FALSE; boolean_t metaslot_auto_key_migrate = B_FALSE; metaslot_config_t metaslot_config; void (*Tmp_GetThreshold)(void *) = NULL; cipher_mechs_threshold_t meta_mechs_threshold[MAX_NUM_THRESHOLD]; static const char *conf_err = "See cryptoadm(8). Skipping this plug-in."; /* * Set up metaslot for the framework using either user configuration * or system wide configuration options * * Also sets up the global "slottable" to have the first slot be metaslot. */ static CK_RV setup_metaslot(uentry_t *metaslot_entry) { CK_RV rv; CK_MECHANISM_TYPE_PTR prov_pol_mechs = NULL; pkcs11_slot_t *cur_slot; /* process policies for mechanisms */ if ((metaslot_entry) && (metaslot_entry->count > 0)) { rv = pkcs11_mech_parse(metaslot_entry->policylist, &prov_pol_mechs, metaslot_entry->count); if (rv == CKR_HOST_MEMORY) { cryptoerror(LOG_ERR, "libpkcs11: Could not parse configuration," "out of memory. Cannot continue parsing " "%s.\n", _PATH_PKCS11_CONF); return (rv); } else if (rv == CKR_MECHANISM_INVALID) { /* * Configuration file is corrupted for metaslot */ cryptoerror(LOG_ERR, "libpkcs11: Policy invalid or corrupted " "for metaslot. Use cryptoadm(8) to fix " "this. Disabling metaslot functionality.\n"); metaslot_enabled = B_FALSE; return (rv); } } /* * Check for metaslot policy. If all mechanisms are * disabled, disable metaslot since there is nothing * interesting for it to do */ if ((metaslot_entry) && (metaslot_entry->flag_enabledlist) && (prov_pol_mechs == NULL)) { metaslot_enabled = B_FALSE; return (rv); } /* * save system wide value for metaslot's keystore. * If either slot description or token label is specified by * the user, the system wide value for both is ignored. */ if ((metaslot_entry) && (!metaslot_config.keystore_token_specified) && (!metaslot_config.keystore_slot_specified)) { /* * blank_str is used for comparing with token label, * and slot description, make sure it is better than * the larger of both */ char blank_str[TOKEN_LABEL_SIZE + SLOT_DESCRIPTION_SIZE]; bzero(blank_str, sizeof (blank_str)); if (memcmp(metaslot_entry->metaslot_ks_token, blank_str, TOKEN_LABEL_SIZE) != 0) { metaslot_config.keystore_token_specified = B_TRUE; (void) strlcpy( (char *)metaslot_config.keystore_token, (const char *)metaslot_entry->metaslot_ks_token, TOKEN_LABEL_SIZE); } if (memcmp(metaslot_entry->metaslot_ks_slot, blank_str, SLOT_DESCRIPTION_SIZE) != 0) { metaslot_config.keystore_slot_specified = B_TRUE; (void) strlcpy( (char *)metaslot_config.keystore_slot, (const char *)metaslot_entry->metaslot_ks_slot, SLOT_DESCRIPTION_SIZE); } } /* check system-wide value for auto_key_migrate */ if (metaslot_config.auto_key_migrate_specified) { /* take user's specified value */ metaslot_auto_key_migrate = metaslot_config.auto_key_migrate; } else { if (metaslot_entry) { /* use system-wide default */ metaslot_auto_key_migrate = metaslot_entry->flag_metaslot_auto_key_migrate; } else { /* * there's no system wide metaslot entry, * default auto_key_migrate to true */ metaslot_auto_key_migrate = B_TRUE; } } /* Make first slotID be 0, for metaslot. */ slottable->st_first = 0; /* Set up the slottable entry for metaslot */ slottable->st_slots[0] = NULL; cur_slot = calloc(1, sizeof (pkcs11_slot_t)); if (cur_slot == NULL) { rv = CKR_HOST_MEMORY; return (rv); } cur_slot->sl_wfse_state = WFSE_CLEAR; cur_slot->sl_enabledpol = B_FALSE; cur_slot->sl_no_wfse = B_FALSE; (void) pthread_mutex_init(&cur_slot->sl_mutex, NULL); /* * The metaslot entry was prealloc'd by * pkcs11_slottable_increase() */ (void) pthread_mutex_lock(&slottable->st_mutex); slottable->st_slots[0] = cur_slot; (void) pthread_mutex_unlock(&slottable->st_mutex); (void) pthread_mutex_lock(&cur_slot->sl_mutex); cur_slot->sl_id = METASLOT_SLOTID; cur_slot->sl_func_list = &metaslot_functionList; if (metaslot_entry) { cur_slot->sl_enabledpol = metaslot_entry->flag_enabledlist; cur_slot->sl_pol_count = metaslot_entry->count; } else { /* if no metaslot entry, assume all mechs are enabled */ cur_slot->sl_enabledpol = B_FALSE; cur_slot->sl_pol_count = 0; } cur_slot->sl_pol_mechs = prov_pol_mechs; cur_slot->sl_dldesc = NULL; /* not applicable */ cur_slot->sl_prov_id = 0; (void) pthread_mutex_unlock(&cur_slot->sl_mutex); /* Call the meta_Initialize() to initialize metaslot */ rv = meta_Initialize(NULL); if (rv != CKR_OK) { cryptoerror(LOG_ERR, "libpkcs11: Can't initialize metaslot (%s)", pkcs11_strerror(rv)); goto cleanup; } return (CKR_OK); cleanup: metaslot_enabled = B_FALSE; slottable->st_slots[0] = NULL; if (cur_slot) { (void) pthread_mutex_destroy(&cur_slot->sl_mutex); free(cur_slot); } return (rv); } /* * For each provider found in pkcs11.conf: expand $ISA if necessary, * verify the module is signed, load the provider, find all of its * slots, and store the function list and disabled policy. * * This function requires that the uentrylist_t and pkcs11_slottable_t * already have memory allocated, and that the uentrylist_t is already * populated with provider and policy information. * * pInitArgs can be set to NULL, but is normally the same value * the framework's C_Initialize() was called with. * * Unless metaslot is explicitly disabled, it is setup when all other * providers are loaded. */ CK_RV pkcs11_slot_mapping(uentrylist_t *pplist, CK_VOID_PTR pInitArgs) { CK_RV rv = CKR_OK; CK_RV prov_rv; /* Provider's return code */ CK_INFO prov_info; CK_RV (*Tmp_C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR); CK_FUNCTION_LIST_PTR prov_funcs = NULL; /* Provider's function list */ CK_ULONG prov_slot_count; /* Number of slots */ CK_SLOT_ID slot_id; /* slotID assigned for framework */ CK_SLOT_ID_PTR prov_slots = NULL; /* Provider's slot list */ /* Enabled or Disabled policy */ CK_MECHANISM_TYPE_PTR prov_pol_mechs = NULL; void *dldesc = NULL; char *isa, *fullpath = NULL, *dl_error; uentrylist_t *phead; uint_t prov_count = 0; pkcs11_slot_t *cur_slot; CK_ULONG i; size_t len; uentry_t *metaslot_entry = NULL; /* number of slots in the framework, not including metaslot */ uint_t slot_count = 0; phead = pplist; /* Loop through all of the provider listed in pkcs11.conf */ while (phead != NULL) { if (!strcasecmp(phead->puent->name, "metaslot")) { /* * Skip standard processing for metaslot * entry since it is not an actual library * that can be dlopened. * It will be initialized later. */ if (metaslot_entry != NULL) { cryptoerror(LOG_ERR, "libpkcs11: multiple entries for metaslot " "detected. All but the first entry will " "be ignored"); } else { metaslot_entry = phead->puent; } goto contparse; } if (!strcasecmp(phead->puent->name, FIPS_KEYWORD)) { /* * Skip standard processing for fips-140 * entry since it is not an actual library * that can be dlopened. */ goto contparse; } /* Check for Instruction Set Architecture indicator */ if ((isa = strstr(phead->puent->name, PKCS11_ISA)) != NULL) { /* Substitute the architecture dependent path */ len = strlen(phead->puent->name) - strlen(PKCS11_ISA) + strlen(PKCS11_ISA_DIR) + 1; if ((fullpath = (char *)malloc(len)) == NULL) { cryptoerror(LOG_ERR, "libpksc11: parsing %s, out of memory. " "Cannot continue parsing.", _PATH_PKCS11_CONF); rv = CKR_HOST_MEMORY; goto conferror; } *isa = '\000'; isa += strlen(PKCS11_ISA); (void) snprintf(fullpath, len, "%s%s%s", phead->puent->name, PKCS11_ISA_DIR, isa); } else if ((fullpath = strdup(phead->puent->name)) == 0) { cryptoerror(LOG_ERR, "libpkcs11: parsing %s, out of memory. " "Cannot continue parsing.", _PATH_PKCS11_CONF); rv = CKR_HOST_MEMORY; goto conferror; } /* * Open the provider. We assume all of our plugins have * their symbols properly defined, so the use of RTLD_NOW * to flush out errors immediately is not necessary. * * Note that for proper operation, all plugins must be * built with direct bindings enabled. */ dldesc = dlopen(fullpath, RTLD_LAZY); /* * If we failed to load it, we will just skip this * provider and move on to the next one. */ if (dldesc == NULL) { dl_error = dlerror(); cryptoerror(LOG_ERR, "libpkcs11: Cannot load PKCS#11 library %s. " "dlerror: %s. %s", fullpath, dl_error != NULL ? dl_error : "Unknown", conf_err); goto contparse; } /* Get the pointer to provider's C_GetFunctionList() */ Tmp_C_GetFunctionList = (CK_RV(*)())dlsym(dldesc, "C_GetFunctionList"); /* * If we failed to get the pointer to C_GetFunctionList(), * skip this provider and continue to the next one. */ if (Tmp_C_GetFunctionList == NULL) { cryptoerror(LOG_ERR, "libpkcs11: Could not dlsym() C_GetFunctionList() " "for %s. May not be a PKCS#11 library. %s", fullpath, conf_err); (void) dlclose(dldesc); goto contparse; } /* Get the provider's function list */ prov_rv = Tmp_C_GetFunctionList(&prov_funcs); /* * If we failed to get the provider's function list, * skip this provider and continue to the next one. */ if (prov_rv != CKR_OK) { cryptoerror(LOG_ERR, "libpkcs11: Could not get function list for %s. " "%s Error: %s.", fullpath, conf_err, pkcs11_strerror(prov_rv)); (void) dlclose(dldesc); goto contparse; } /* Initialize this provider */ prov_rv = prov_funcs->C_Initialize(pInitArgs); /* * If we failed to initialize this provider, * skip this provider and continue to the next one. */ if ((prov_rv != CKR_OK) && (prov_rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) { cryptoerror(LOG_ERR, "libpkcs11: Could not initialize %s. " "%s Error: %s.", fullpath, conf_err, pkcs11_strerror(prov_rv)); (void) dlclose(dldesc); goto contparse; } /* * Make sure this provider is implementing the same * major version, and at least the same minor version * that we are. */ prov_rv = prov_funcs->C_GetInfo(&prov_info); /* * If we can't verify that we are implementing the * same major version, or if it is definitely not the same * version, we need to skip this provider. */ if ((prov_rv != CKR_OK) || (prov_info.cryptokiVersion.major != CRYPTOKI_VERSION_MAJOR)) { if (prov_rv != CKR_OK) { cryptoerror(LOG_ERR, "libpkcs11: Could not verify version of " "%s. %s Error: %s.", fullpath, conf_err, pkcs11_strerror(prov_rv)); } else { cryptoerror(LOG_ERR, "libpkcs11: Only CRYPTOKI major version " "%d is supported. %s is major " "version %d. %s", CRYPTOKI_VERSION_MAJOR, fullpath, prov_info.cryptokiVersion.major, conf_err); } (void) prov_funcs->C_Finalize(NULL); (void) dlclose(dldesc); goto contparse; } /* * Warn the administrator (at debug) that a provider with * a significantly older or newer version of * CRYPTOKI is being used. It should not cause * problems, but logging a warning makes it easier * to debug later. */ if ((prov_info.cryptokiVersion.minor < CRYPTOKI_VERSION_WARN_MINOR) || (prov_info.cryptokiVersion.minor > CRYPTOKI_VERSION_MINOR)) { cryptoerror(LOG_DEBUG, "libpkcs11: %s CRYPTOKI minor version, %d, may " "not be compatible with minor version %d.", fullpath, prov_info.cryptokiVersion.minor, CRYPTOKI_VERSION_MINOR); } /* * Find out how many slots this provider has, * call with tokenPresent set to FALSE so all * potential slots are returned. */ prov_rv = prov_funcs->C_GetSlotList(FALSE, NULL, &prov_slot_count); /* * If the call failed, or if no slots are returned, * then skip this provider and continue to next one. */ if (prov_rv != CKR_OK) { cryptoerror(LOG_ERR, "libpksc11: Could not get slot list from %s. " "%s Error: %s.", fullpath, conf_err, pkcs11_strerror(prov_rv)); (void) prov_funcs->C_Finalize(NULL); (void) dlclose(dldesc); goto contparse; } if (prov_slot_count == 0) { cryptodebug("libpkcs11: No slots presented from %s. " "Skipping this plug-in at this time.\n", fullpath); (void) prov_funcs->C_Finalize(NULL); (void) dlclose(dldesc); goto contparse; } /* Allocate memory for the slot list */ prov_slots = calloc(prov_slot_count, sizeof (CK_SLOT_ID)); if (prov_slots == NULL) { cryptoerror(LOG_ERR, "libpkcs11: Could not allocate memory for " "plug-in slots. Cannot continue parsing %s\n", _PATH_PKCS11_CONF); rv = CKR_HOST_MEMORY; goto conferror; } /* Get slot list from provider */ prov_rv = prov_funcs->C_GetSlotList(FALSE, prov_slots, &prov_slot_count); /* if second call fails, drop this provider */ if (prov_rv != CKR_OK) { cryptoerror(LOG_ERR, "libpkcs11: Second call to C_GetSlotList() for %s " "failed. %s Error: %s.", fullpath, conf_err, pkcs11_strerror(prov_rv)); (void) prov_funcs->C_Finalize(NULL); (void) dlclose(dldesc); goto contparse; } /* * Parse the list of disabled or enabled mechanisms, will * apply to each of the provider's slots. */ if (phead->puent->count > 0) { rv = pkcs11_mech_parse(phead->puent->policylist, &prov_pol_mechs, phead->puent->count); if (rv == CKR_HOST_MEMORY) { cryptoerror(LOG_ERR, "libpkcs11: Could not parse configuration," "out of memory. Cannot continue parsing " "%s.", _PATH_PKCS11_CONF); goto conferror; } else if (rv == CKR_MECHANISM_INVALID) { /* * Configuration file is corrupted for this * provider. */ cryptoerror(LOG_ERR, "libpkcs11: Policy invalid or corrupted " "for %s. Use cryptoadm(8) to fix " "this. Skipping this plug-in.", fullpath); (void) prov_funcs->C_Finalize(NULL); (void) dlclose(dldesc); goto contparse; } } /* Allocate memory in our slottable for these slots */ rv = pkcs11_slottable_increase(prov_slot_count); /* * If any error is returned, it will be memory related, * so we need to abort the attempt at filling the * slottable. */ if (rv != CKR_OK) { cryptoerror(LOG_ERR, "libpkcs11: slottable could not increase. " "Cannot continue parsing %s.", _PATH_PKCS11_CONF); goto conferror; } /* Configure information for each new slot */ for (i = 0; i < prov_slot_count; i++) { /* allocate slot in framework */ rv = pkcs11_slot_allocate(&slot_id); if (rv != CKR_OK) { cryptoerror(LOG_ERR, "libpkcs11: Could not allocate " "new slot. Cannot continue parsing %s.", _PATH_PKCS11_CONF); goto conferror; } slot_count++; cur_slot = slottable->st_slots[slot_id]; (void) pthread_mutex_lock(&cur_slot->sl_mutex); cur_slot->sl_id = prov_slots[i]; cur_slot->sl_func_list = prov_funcs; cur_slot->sl_enabledpol = phead->puent->flag_enabledlist; cur_slot->sl_pol_mechs = prov_pol_mechs; cur_slot->sl_pol_count = phead->puent->count; cur_slot->sl_norandom = phead->puent->flag_norandom; cur_slot->sl_dldesc = dldesc; cur_slot->sl_prov_id = prov_count + 1; (void) pthread_mutex_unlock(&cur_slot->sl_mutex); } /* * Get the pointer to private interface _SUNW_GetThreshold() * in pkcs11_kernel. */ if (Tmp_GetThreshold == NULL) { Tmp_GetThreshold = (void(*)())dlsym(dldesc, "_SUNW_GetThreshold"); /* Get the threshold values for the supported mechs */ if (Tmp_GetThreshold != NULL) { (void) memset(meta_mechs_threshold, 0, sizeof (meta_mechs_threshold)); Tmp_GetThreshold(meta_mechs_threshold); } } /* Set and reset values to process next provider */ prov_count++; contparse: prov_slot_count = 0; Tmp_C_GetFunctionList = NULL; prov_funcs = NULL; dldesc = NULL; if (fullpath != NULL) { free(fullpath); fullpath = NULL; } if (prov_slots != NULL) { free(prov_slots); prov_slots = NULL; } phead = phead->next; } if (slot_count == 0) { /* * there's no other slot in the framework, * there is nothing to do */ goto config_complete; } /* determine if metaslot should be enabled */ /* * Check to see if any environment variable is defined * by the user for configuring metaslot. Users' * setting always take precedence over the system wide * setting. So, we will first check for any user's * defined env variables before looking at the system-wide * configuration. */ get_user_metaslot_config(); /* no metaslot entry in /etc/crypto/pkcs11.conf */ if (!metaslot_entry) { /* * If user env variable indicates metaslot should be enabled, * but there's no entry in /etc/crypto/pkcs11.conf for * metaslot at all, will respect the user's defined value */ if ((metaslot_config.enabled_specified) && (metaslot_config.enabled)) { metaslot_enabled = B_TRUE; } } else { if (!metaslot_config.enabled_specified) { /* * take system wide value if * it is not specified by user */ metaslot_enabled = metaslot_entry->flag_metaslot_enabled; } else { metaslot_enabled = metaslot_config.enabled; } } /* * * As long as the user or system configuration file does not * disable metaslot, it will be enabled regardless of the * number of slots plugged into the framework. Therefore, * metaslot is enabled even when there's only one slot * plugged into the framework. This is necessary for * presenting a consistent token label view to applications. * * However, for the case where there is only 1 slot plugged into * the framework, we can use "fastpath". * * "fastpath" will pass all of the application's requests * directly to the underlying provider. Only when policy is in * effect will we need to keep slotID around. * * When metaslot is enabled, and fastpath is enabled, * all the metaslot processing will be skipped. * When there is only 1 slot, there's * really not much metaslot can do in terms of combining functionality * of different slots, and object migration. * */ /* check to see if fastpath can be used */ if (slottable->st_last == slottable->st_first) { cur_slot = slottable->st_slots[slottable->st_first]; (void) pthread_mutex_lock(&cur_slot->sl_mutex); if ((cur_slot->sl_pol_count == 0) && (!cur_slot->sl_enabledpol) && (!cur_slot->sl_norandom)) { /* No policy is in effect, don't need slotid */ fast_funcs = cur_slot->sl_func_list; purefastpath = B_TRUE; } else { fast_funcs = cur_slot->sl_func_list; fast_slot = slottable->st_first; policyfastpath = B_TRUE; } (void) pthread_mutex_unlock(&cur_slot->sl_mutex); } if ((purefastpath || policyfastpath) && (!metaslot_enabled)) { goto config_complete; } /* * If we get here, there are more than 2 slots in the framework, * we need to set up metaslot if it is enabled */ if (metaslot_enabled) { rv = setup_metaslot(metaslot_entry); if (rv != CKR_OK) { goto conferror; } } config_complete: return (CKR_OK); conferror: /* * This cleanup code is only exercised when a major, * unrecoverable error like "out of memory". */ if (prov_funcs != NULL) { (void) prov_funcs->C_Finalize(NULL); } if (dldesc != NULL) { (void) dlclose(dldesc); } if (fullpath != NULL) { free(fullpath); fullpath = NULL; } if (prov_slots != NULL) { free(prov_slots); prov_slots = NULL; } return (rv); } /* * pkcs11_mech_parse will take hex mechanism ids, as a list of * strings, and convert them to CK_MECHANISM_TYPE_PTR. */ CK_RV pkcs11_mech_parse(umechlist_t *str_list, CK_MECHANISM_TYPE_PTR *mech_list, int mech_count) { CK_MECHANISM_TYPE_PTR tmp_list; umechlist_t *shead = str_list; tmp_list = malloc(mech_count * sizeof (CK_MECHANISM_TYPE)); if (tmp_list == NULL) { cryptoerror(LOG_ERR, "libpkcs11: parsing %s, out of memory. " "Cannot continue.", _PATH_PKCS11_CONF); return (CKR_HOST_MEMORY); } *mech_list = tmp_list; /* * The following will loop mech_count times, as there are * exactly mech_count items in the str_list. */ while (shead != NULL) { CK_MECHANISM_TYPE cur_mech; errno = 0; /* * "name" is a hexadecimal number, preceded by 0x. */ cur_mech = strtoul(shead->name, NULL, 16); if ((cur_mech == 0) && ((errno == EINVAL) || (errno == ERANGE))) { free(mech_list); return (CKR_MECHANISM_INVALID); } *tmp_list = (CK_MECHANISM_TYPE)cur_mech; tmp_list++; shead = shead->next; } return (CKR_OK); } /* * pkcs11_is_dismech is provided a slotid and a mechanism. * If mech is not disabled, then return B_FALSE. */ boolean_t pkcs11_is_dismech(CK_SLOT_ID slotid, CK_MECHANISM_TYPE mech) { ulong_t i; boolean_t enabled_pol; CK_MECHANISM_TYPE_PTR pol_mechs; ulong_t pol_count; /* Find the associated slot and get the mech policy info */ (void) pthread_mutex_lock(&slottable->st_slots[slotid]->sl_mutex); enabled_pol = slottable->st_slots[slotid]->sl_enabledpol; pol_mechs = slottable->st_slots[slotid]->sl_pol_mechs; pol_count = slottable->st_slots[slotid]->sl_pol_count; (void) pthread_mutex_unlock(&slottable->st_slots[slotid]->sl_mutex); /* Check for policy */ if ((!enabled_pol) && (pol_mechs == NULL)) { /* no policy */ return (B_FALSE); } else if (pol_mechs == NULL) { /* * We have an empty enabled list, which means no * mechanisms are exempted from this policy: all * are disabled. */ return (B_TRUE); } for (i = 0; i < pol_count; i++) { /* * If it matches, return status based on this * being and enabled or a disabled list of mechs. */ if (pol_mechs[i] == mech) { return (enabled_pol ? B_FALSE : B_TRUE); } } /* mech was not found in list */ return (enabled_pol ? B_TRUE : B_FALSE); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _PKCS11_CONF_H #define _PKCS11_CONF_H #ifdef __cplusplus extern "C" { #endif #include #include "pkcs11Slot.h" extern CK_RV pkcs11_slot_mapping(uentrylist_t *pplist, CK_VOID_PTR pInitArgs); extern CK_RV pkcs11_mech_parse(umechlist_t *str_list, CK_MECHANISM_TYPE_PTR *mech_list, int mech_count); extern boolean_t pkcs11_is_dismech(CK_SLOT_ID slotid, CK_MECHANISM_TYPE mech); #ifdef __cplusplus } #endif #endif /* _PKCS11_CONF_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include "pkcs11Global.h" #include "pkcs11Conf.h" #include "pkcs11Session.h" #include "pkcs11Slot.h" /* * C_EncryptInit will verify that the session handle is valid within * the framework, that the mechanism is not disabled for the slot * associated with this session, and then redirect to the underlying * provider. Policy is checked for C_EncryptInit, and not C_Encrypt * or C_EncryptUpdate, since C_EncryptInit is required to be called * before C_Encrypt and C_EncryptUpdate. */ CK_RV C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { CK_RV rv; pkcs11_session_t *sessp; CK_SLOT_ID slotid; /* Check for a fastpath */ if (purefastpath || policyfastpath) { if (policyfastpath && pkcs11_is_dismech(fast_slot, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } return (fast_funcs->C_EncryptInit(hSession, pMechanism, hKey)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } slotid = sessp->se_slotid; /* Make sure this is not a disabled mechanism */ if (pkcs11_is_dismech(slotid, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } /* Initialize the digest with the underlying provider */ rv = FUNCLIST(slotid)->C_EncryptInit(sessp->se_handle, pMechanism, hKey); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_Encrypt is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_Encrypt(hSession, pData, ulDataLen, pEncryptedData, pulEncryptedDataLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Initialize the digest with the underlying provider */ rv = FUNCLIST(sessp->se_slotid)->C_Encrypt(sessp->se_handle, pData, ulDataLen, pEncryptedData, pulEncryptedDataLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_EncryptUpdate is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_EncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_EncryptUpdate(hSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Initialize the digest with the underlying provider */ rv = FUNCLIST(sessp->se_slotid)->C_EncryptUpdate(sessp->se_handle, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_EncryptFinal is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_EncryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pulLastEncryptedPartLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_EncryptFinal(hSession, pLastEncryptedPart, pulLastEncryptedPartLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Initialize the digest with the underlying provider */ rv = FUNCLIST(sessp->se_slotid)->C_EncryptFinal(sessp->se_handle, pLastEncryptedPart, pulLastEncryptedPartLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_DecryptInit will verify that the session handle is valid within * the framework, that the mechanism is not disabled for the slot * associated with this session, and then redirect to the underlying * provider. Policy is checked for C_DecryptInit, and not C_Decrypt * or C_DecryptUpdate, since C_DecryptInit is required to be called * before C_Decrypt and C_DecryptUpdate. */ CK_RV C_DecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { CK_RV rv; pkcs11_session_t *sessp; CK_SLOT_ID slotid; /* Check for a fastpath */ if (purefastpath || policyfastpath) { if (policyfastpath && pkcs11_is_dismech(fast_slot, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } return (fast_funcs->C_DecryptInit(hSession, pMechanism, hKey)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } slotid = sessp->se_slotid; /* Make sure this is not a disabled mechanism */ if (pkcs11_is_dismech(slotid, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } /* Initialize the digest with the underlying provider */ rv = FUNCLIST(slotid)->C_DecryptInit(sessp->se_handle, pMechanism, hKey); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_Decrypt is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_Decrypt(hSession, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Initialize the digest with the underlying provider */ rv = FUNCLIST(sessp->se_slotid)->C_Decrypt(sessp->se_handle, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_DecryptUpdate is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_DecryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_DecryptUpdate(hSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Initialize the digest with the underlying provider */ rv = FUNCLIST(sessp->se_slotid)->C_DecryptUpdate(sessp->se_handle, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_DecryptFinal is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_DecryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_DecryptFinal(hSession, pLastPart, pulLastPartLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Initialize the digest with the underlying provider */ rv = FUNCLIST(sessp->se_slotid)->C_DecryptFinal(sessp->se_handle, pLastPart, pulLastPartLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include "pkcs11Global.h" #include "pkcs11Conf.h" #include "pkcs11Session.h" #include "pkcs11Slot.h" /* * C_DigestInit will verify that the session handle is valid within * the framework, that the mechanism is not disabled for the slot * associated with this session, and then redirect to the underlying * provider. Policy is only checked for C_DigestInit, since it is * required to be called before C_Digest and C_DigestUpdate. */ CK_RV C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) { CK_RV rv; pkcs11_session_t *sessp; CK_SLOT_ID slotid; /* Check for a fastpath */ if (purefastpath || policyfastpath) { if (policyfastpath && pkcs11_is_dismech(fast_slot, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } return (fast_funcs->C_DigestInit(hSession, pMechanism)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } slotid = sessp->se_slotid; /* Make sure this is not a disabled mechanism */ if (pkcs11_is_dismech(slotid, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } /* Initialize the digest with the underlying provider */ rv = FUNCLIST(slotid)->C_DigestInit(sessp->se_handle, pMechanism); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_Digest is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_Digest(hSession, pData, ulDataLen, pDigest, pulDigestLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_Digest(sessp->se_handle, pData, ulDataLen, pDigest, pulDigestLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_DigestUpdate is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_DigestUpdate(hSession, pPart, ulPartLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_DigestUpdate(sessp->se_handle, pPart, ulPartLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_DigestKey is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_DigestKey(hSession, hKey)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_DigestKey(sessp->se_handle, hKey); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_DigestFinal is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_DigestFinal(hSession, pDigest, pulDigestLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_DigestFinal(sessp->se_handle, pDigest, pulDigestLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include "pkcs11Global.h" #include "pkcs11Session.h" #include "pkcs11Slot.h" /* * C_DigestEncryptUpdate is a pure wrapper to the underlying provider. * Policy enforcement was done earlier by the mandatory calls to * C_DigestInit and C_EncryptInit. * * The only argument checked is whether or not hSession is valid. */ CK_RV C_DigestEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_DigestEncryptUpdate(hSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)-> C_DigestEncryptUpdate(sessp->se_handle, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_DecryptDigestUpdate is a pure wrapper to the underlying provider. * Policy enforcement was done earlier by the mandatory calls to * C_DigestInit and C_DecryptInit. * * The only argument checked is whether or not hSession is valid. */ CK_RV C_DecryptDigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_DecryptDigestUpdate(hSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)-> C_DecryptDigestUpdate(sessp->se_handle, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_SignEncryptUpdate is a pure wrapper to the underlying provider. * Policy enforcement was done earlier by the mandatory calls to * C_SignInit and C_EncryptInit. * * The only argument checked is whether or not hSession is valid. */ CK_RV C_SignEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_SignEncryptUpdate(hSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)-> C_SignEncryptUpdate(sessp->se_handle, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_DecryptVerifyUpdate is a pure wrapper to the underlying provider. * Policy enforcement was done earlier by the mandatory calls to * C_SignInit and C_EncryptInit. * * The only argument checked is whether or not hSession is valid. */ CK_RV C_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_DecryptVerifyUpdate(hSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)-> C_DecryptVerifyUpdate(sessp->se_handle, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include "pkcs11Global.h" #include "pkcs11Slot.h" #include "pkcs11Conf.h" #include "pkcs11Session.h" #include "metaGlobal.h" #pragma init(pkcs11_init) #pragma fini(pkcs11_fini) static struct CK_FUNCTION_LIST functionList = { { 2, 20 }, /* version */ C_Initialize, C_Finalize, C_GetInfo, C_GetFunctionList, C_GetSlotList, C_GetSlotInfo, C_GetTokenInfo, C_GetMechanismList, C_GetMechanismInfo, C_InitToken, C_InitPIN, C_SetPIN, C_OpenSession, C_CloseSession, C_CloseAllSessions, C_GetSessionInfo, C_GetOperationState, C_SetOperationState, C_Login, C_Logout, C_CreateObject, C_CopyObject, C_DestroyObject, C_GetObjectSize, C_GetAttributeValue, C_SetAttributeValue, C_FindObjectsInit, C_FindObjects, C_FindObjectsFinal, C_EncryptInit, C_Encrypt, C_EncryptUpdate, C_EncryptFinal, C_DecryptInit, C_Decrypt, C_DecryptUpdate, C_DecryptFinal, C_DigestInit, C_Digest, C_DigestUpdate, C_DigestKey, C_DigestFinal, C_SignInit, C_Sign, C_SignUpdate, C_SignFinal, C_SignRecoverInit, C_SignRecover, C_VerifyInit, C_Verify, C_VerifyUpdate, C_VerifyFinal, C_VerifyRecoverInit, C_VerifyRecover, C_DigestEncryptUpdate, C_DecryptDigestUpdate, C_SignEncryptUpdate, C_DecryptVerifyUpdate, C_GenerateKey, C_GenerateKeyPair, C_WrapKey, C_UnwrapKey, C_DeriveKey, C_SeedRandom, C_GenerateRandom, C_GetFunctionStatus, C_CancelFunction, C_WaitForSlotEvent }; boolean_t pkcs11_initialized = B_FALSE; boolean_t pkcs11_cant_create_threads = B_FALSE; boolean_t fini_called = B_FALSE; static boolean_t pkcs11_atfork_initialized = B_FALSE; static pid_t pkcs11_pid = 0; /* protects pkcs11_[initialized|pid], and fastpath */ static pthread_mutex_t globalmutex = PTHREAD_MUTEX_INITIALIZER; static CK_RV finalize_common(CK_VOID_PTR pReserved); static void pkcs11_init(); static void pkcs11_fini(); /* * Ensure that before a fork, all mutexes are taken. * We cannot acquire globalmutex, because it can cause deadlock when * atfork() and fork() are called in parallel. It can happen when * C_Ininitialize() tries to dlopen() a provider. The dlopen() operation * is protected by globalmutex and when another thread calls fork() * pkcs11_fork_prepare cannot acquire the mutex again and thus it must wait. * When a provider tries to register its atfork handler, atfork() must * wait on fork(). See the comment in fork() libc function for more details. * * Order: * 1. slottable->st_mutex * 2. all slottable->st_slots' mutexes */ static void pkcs11_fork_prepare(void) { int i; if (pkcs11_initialized) { if (slottable != NULL) { (void) pthread_mutex_lock(&slottable->st_mutex); /* Take the sl_mutex of all slots */ for (i = slottable->st_first; i <= slottable->st_last; i++) { if (slottable->st_slots[i] != NULL) { (void) pthread_mutex_lock( &slottable->st_slots[i]->sl_mutex); } } } } } /* * Ensure that after a fork, in the parent, all mutexes are released in opposite * order to pkcs11_fork_prepare(). */ static void pkcs11_fork_parent(void) { int i; if (pkcs11_initialized) { if (slottable != NULL) { /* Release the sl_mutex of all slots */ for (i = slottable->st_first; i <= slottable->st_last; i++) { if (slottable->st_slots[i] != NULL) { (void) pthread_mutex_unlock( &slottable->st_slots[i]->sl_mutex); } } } (void) pthread_mutex_unlock(&slottable->st_mutex); } } /* * Ensure that after a fork, in the child, all mutexes are released in opposite * order to pkcs11_fork_prepare() and cleanup is done. * Because we need to handle fork correctly before library is initialized two * handlers are necessary. * * 1) pkcs11_fork_child() - unlock mutexes * 2) pkcs11_fork_child_fini() - cleanup library after fork, it is registered in * C_Initialize() after providers initialization. */ static void pkcs11_fork_child(void) { int i; if (pkcs11_initialized) { if (slottable != NULL) { /* Release the sl_mutex of all slots */ for (i = slottable->st_first; i <= slottable->st_last; i++) { if (slottable->st_slots[i] != NULL) { (void) pthread_mutex_unlock( &slottable->st_slots[i]->sl_mutex); } } } (void) pthread_mutex_unlock(&slottable->st_mutex); } (void) pthread_mutex_destroy(&globalmutex); (void) pthread_mutex_init(&globalmutex, NULL); } /* Library cleanup have to be last afterfork child handler. */ static void pkcs11_fork_child_fini(void) { pkcs11_fini(); } CK_RV C_Initialize(CK_VOID_PTR pInitArgs) { CK_RV rv; uentrylist_t *pliblist = NULL; int initialize_pid; /* * Grab lock to insure only one thread enters * this function at a time. */ (void) pthread_mutex_lock(&globalmutex); initialize_pid = getpid(); /* Make sure function hasn't been called twice */ if (pkcs11_initialized) { if (initialize_pid == pkcs11_pid) { (void) pthread_mutex_unlock(&globalmutex); return (CKR_CRYPTOKI_ALREADY_INITIALIZED); } else { /* * A fork has happened and the child is * reinitializing. Do a finalize_common() to close * out any state from the parent, and then * continue on. */ (void) finalize_common(NULL); } } /* Check if application has provided mutex-handling functions */ if (pInitArgs != NULL) { CK_C_INITIALIZE_ARGS_PTR initargs = (CK_C_INITIALIZE_ARGS_PTR) pInitArgs; /* pReserved should not be set */ if (initargs->pReserved != NULL) { rv = CKR_ARGUMENTS_BAD; goto errorexit; } /* * Make sure function pointers are either all NULL or * all set. */ if (!(((initargs->CreateMutex != NULL) && (initargs->LockMutex != NULL) && (initargs->UnlockMutex != NULL) && (initargs->DestroyMutex != NULL)) || ((initargs->CreateMutex == NULL) && (initargs->LockMutex == NULL) && (initargs->UnlockMutex == NULL) && (initargs->DestroyMutex == NULL)))) { rv = CKR_ARGUMENTS_BAD; goto errorexit; } if (!(initargs->flags & CKF_OS_LOCKING_OK)) { if (initargs->CreateMutex != NULL) { /* * Do not accept application supplied * locking primitives. */ rv = CKR_CANT_LOCK; goto errorexit; } } if (initargs->flags & CKF_LIBRARY_CANT_CREATE_OS_THREADS) { /* * Calling application does not want the library * to create threads. This will effect * C_WaitForSlotEvent(). */ pkcs11_cant_create_threads = B_TRUE; } } /* Initialize slot table */ rv = pkcs11_slottable_initialize(); if (rv != CKR_OK) goto errorexit; /* Get the list of providers */ if (get_pkcs11conf_info(&pliblist) != SUCCESS) { rv = CKR_FUNCTION_FAILED; goto errorexit; } /* * Load each provider, check for accessible slots, * and populate slottable. If metaslot is enabled, * it will be initialized as well. */ rv = pkcs11_slot_mapping(pliblist, pInitArgs); if (rv != CKR_OK) goto errorexit; pkcs11_initialized = B_TRUE; pkcs11_pid = initialize_pid; /* Children inherit parent's atfork handlers */ if (!pkcs11_atfork_initialized) { (void) pthread_atfork(NULL, NULL, pkcs11_fork_child_fini); pkcs11_atfork_initialized = B_TRUE; } (void) pthread_mutex_unlock(&globalmutex); /* Cleanup data structures no longer needed */ free_uentrylist(pliblist); return (CKR_OK); errorexit: /* Cleanup any data structures that have already been allocated */ if (slottable) (void) pkcs11_slottable_delete(); if (pliblist) (void) free_uentrylist(pliblist); (void) pthread_mutex_unlock(&globalmutex); return (rv); } /* * C_Finalize is a wrapper around finalize_common. The * globalmutex should be locked by C_Finalize(). * * When an explicit C_Finalize() call is received, all * plugins currently in the slottable will also be * finalized. This must occur, even if libpkcs11(3lib) * was not the first one to initialize the plugins, since it * is the only way in PKCS#11 to force a refresh of the * slot listings (ie to get new hardware devices). */ CK_RV C_Finalize(CK_VOID_PTR pReserved) { CK_RV rv; (void) pthread_mutex_lock(&globalmutex); rv = finalize_common(pReserved); (void) pthread_mutex_unlock(&globalmutex); return (rv); } /* * finalize_common() does the work for C_Finalize. globalmutex * must be held before calling this function. */ static CK_RV finalize_common(CK_VOID_PTR pReserved) { CK_RV rv; if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } if (pReserved != NULL) { return (CKR_ARGUMENTS_BAD); } purefastpath = B_FALSE; policyfastpath = B_FALSE; fast_funcs = NULL; fast_slot = 0; pkcs11_initialized = B_FALSE; pkcs11_cant_create_threads = B_FALSE; pkcs11_pid = 0; /* Check if C_WaitForSlotEvent() is currently active */ (void) pthread_mutex_lock(&slottable->st_mutex); if (slottable->st_wfse_active) { /* * Wait for this thread to proceed far enough to block or * end on its own. Otherwise, teardown of slottable may * occurr before this active function completes. */ while (slottable->st_wfse_active) { /* * If C_WaitForSlotEvent is blocking, wake it up and * return error to calling application. */ if (slottable->st_blocking) { slottable->st_list_signaled = B_TRUE; (void) pthread_cond_signal( &slottable->st_wait_cond); (void) pthread_mutex_unlock( &slottable->st_mutex); (void) pthread_join(slottable->st_tid, NULL); } } } else { (void) pthread_mutex_unlock(&slottable->st_mutex); } rv = pkcs11_slottable_delete(); return (rv); } static void pkcs11_init() { (void) pthread_atfork(pkcs11_fork_prepare, pkcs11_fork_parent, pkcs11_fork_child); } /* * pkcs11_fini() function required to make sure complete cleanup * is done of plugins if the framework is ever unloaded without * a C_Finalize() call. This would be common when applications * load and unload other libraries that use libpkcs11(3lib), since * shared libraries should not call C_Finalize(). * * If pkcs11_fini() is used, we set fini_called to B_TRUE so that * pkcs11_slottable_delete() will not call C_Finalize() on the plugins. * * This is to protect in cases where the application has dlopened * an object (for example, dlobj) that links to libpkcs11(3lib), but * the application is unaware that the object is doing PKCS#11 calls * underneath. This application may later directly dlopen one of the * plugins (like pkcs11_softtoken.so, or any other 3rd party provided * plugin) in order to directly perform PKCS#11 operations. * * While it is still actively using the PKCS#11 plugin directly, * the application may finish with dlobj and dlclose it. As the * reference count for libpkcs11(3lib) has become 0, pkcs11_fini() * will be run by the linker. Even though libpkcs11(3lib) was the * first to initialize the plugin in this case, it is not safe for * libpkcs11(3lib) to finalize the plugin, as the application would * lose state. */ static void pkcs11_fini() { (void) pthread_mutex_lock(&globalmutex); /* if we're not initilized, do not attempt to finalize */ if (!pkcs11_initialized) { (void) pthread_mutex_unlock(&globalmutex); return; } fini_called = B_TRUE; (void) finalize_common(NULL_PTR); (void) pthread_mutex_unlock(&globalmutex); } CK_RV C_GetInfo(CK_INFO_PTR pInfo) { /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_GetInfo(pInfo)); } if (!pkcs11_initialized) return (CKR_CRYPTOKI_NOT_INITIALIZED); if (pInfo == NULL) { return (CKR_ARGUMENTS_BAD); } /* * Copy data into the provided buffer, use strncpy() instead * of strlcpy() so that the strings are NOT NULL terminated, * as required by the PKCS#11 standard */ (void) strncpy((char *)pInfo->manufacturerID, MANUFACTURER_ID, PKCS11_STRING_LENGTH); (void) strncpy((char *)pInfo->libraryDescription, LIBRARY_DESCRIPTION, PKCS11_STRING_LENGTH); pInfo->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR; pInfo->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR; pInfo->flags = 0; pInfo->libraryVersion.major = LIBRARY_VERSION_MAJOR; pInfo->libraryVersion.minor = LIBRARY_VERSION_MINOR; return (CKR_OK); } /* * This function is unaffected by the fast-path, since it is likely * called before C_Initialize is, so we will not yet know the status * of the fast-path. Additionally, policy will still need to be * enforced if applicable. */ CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) { if (ppFunctionList == NULL) { return (CKR_ARGUMENTS_BAD); } *ppFunctionList = &functionList; return (CKR_OK); } /* * This function is no longer supported in this revision of the PKCS#11 * standard. It is maintained for backwards compatibility only. */ /*ARGSUSED*/ CK_RV C_GetFunctionStatus(CK_SESSION_HANDLE hSession) { return (CKR_FUNCTION_NOT_PARALLEL); } /* * This function is no longer supported in this revision of the PKCS#11 * standard. It is maintained for backwards compatibility only. */ /*ARGSUSED*/ CK_RV C_CancelFunction(CK_SESSION_HANDLE hSession) { return (CKR_FUNCTION_NOT_PARALLEL); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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. */ #ifndef _PKCS11_GLOBAL_H #define _PKCS11_GLOBAL_H #ifdef __cplusplus extern "C" { #endif #include #include #include "pkcs11t.h" extern boolean_t pkcs11_initialized; extern boolean_t pkcs11_cant_create_threads; extern boolean_t purefastpath; extern boolean_t policyfastpath; extern boolean_t fini_called; extern CK_FUNCTION_LIST_PTR fast_funcs; extern CK_SLOT_ID fast_slot; #define PKCS11_STRING_LENGTH 32 /* CK_INFO: Information about cryptoki */ #define CRYPTOKI_VERSION_WARN_MINOR 10 #define MANUFACTURER_ID "Sun Microsystems, Inc. " #define LIBRARY_DESCRIPTION "Sun Crypto PKCS#11 Library " #define LIBRARY_VERSION_MAJOR 1 #define LIBRARY_VERSION_MINOR 1 /* CK_SLOT_INFO */ #define HARDWARE_VERSION_MAJOR 0 #define HARDWARE_VERSION_MINOR 0 #define FIRMWARE_VERSION_MAJOR 0 #define FIRMWARE_VERSION_MINOR 0 #ifdef __cplusplus } #endif #endif /* _PKCS11_GLOBAL_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include "pkcs11Global.h" #include "pkcs11Conf.h" #include "pkcs11Session.h" #include "pkcs11Slot.h" /* * C_GenerateKey will verify that the session handle is valid within * the framework, that the mechanism is not disabled for the slot * associated with this session, and then redirect to the underlying * provider. */ CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey) { CK_RV rv; pkcs11_session_t *sessp; CK_SLOT_ID slotid; /* Check for a fastpath */ if (purefastpath || policyfastpath) { if (policyfastpath && pkcs11_is_dismech(fast_slot, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } return (fast_funcs->C_GenerateKey(hSession, pMechanism, pTemplate, ulCount, phKey)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } slotid = sessp->se_slotid; /* Make sure this is not a disabled mechanism */ if (pkcs11_is_dismech(slotid, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } /* Initialize the digest with the underlying provider */ rv = FUNCLIST(slotid)->C_GenerateKey(sessp->se_handle, pMechanism, pTemplate, ulCount, phKey); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_GenerateKeyPair will verify that the session handle is valid within * the framework, that the mechanism is not disabled for the slot * associated with this session, and then redirect to the underlying * provider. */ CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey) { CK_RV rv; pkcs11_session_t *sessp; CK_SLOT_ID slotid; /* Check for a fastpath */ if (purefastpath || policyfastpath) { if (policyfastpath && pkcs11_is_dismech(fast_slot, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } return (fast_funcs->C_GenerateKeyPair(hSession, pMechanism, pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, phPublicKey, phPrivateKey)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } slotid = sessp->se_slotid; /* Make sure this is not a disabled mechanism */ if (pkcs11_is_dismech(slotid, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } /* Initialize the digest with the underlying provider */ rv = FUNCLIST(slotid)->C_GenerateKeyPair(sessp->se_handle, pMechanism, pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, phPublicKey, phPrivateKey); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_WrapKey will verify that the session handle is valid within * the framework, that the mechanism is not disabled for the slot * associated with this session, and then redirect to the underlying * provider. */ CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen) { CK_RV rv; pkcs11_session_t *sessp; CK_SLOT_ID slotid; /* Check for a fastpath */ if (purefastpath || policyfastpath) { if (policyfastpath && pkcs11_is_dismech(fast_slot, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } return (fast_funcs->C_WrapKey(hSession, pMechanism, hWrappingKey, hKey, pWrappedKey, pulWrappedKeyLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } slotid = sessp->se_slotid; /* Make sure this is not a disabled mechanism */ if (pkcs11_is_dismech(slotid, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } /* Initialize the digest with the underlying provider */ rv = FUNCLIST(slotid)->C_WrapKey(sessp->se_handle, pMechanism, hWrappingKey, hKey, pWrappedKey, pulWrappedKeyLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_UnwrapKey will verify that the session handle is valid within * the framework, that the mechanism is not disabled for the slot * associated with this session, and then redirect to the underlying * provider. */ CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) { CK_RV rv; pkcs11_session_t *sessp; CK_SLOT_ID slotid; /* Check for a fastpath */ if (purefastpath || policyfastpath) { if (policyfastpath && pkcs11_is_dismech(fast_slot, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } return (fast_funcs->C_UnwrapKey(hSession, pMechanism, hUnwrappingKey, pWrappedKey, ulWrappedKeyLen, pTemplate, ulAttributeCount, phKey)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } slotid = sessp->se_slotid; /* Make sure this is not a disabled mechanism */ if (pkcs11_is_dismech(slotid, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } /* Initialize the digest with the underlying provider */ rv = FUNCLIST(slotid)->C_UnwrapKey(sessp->se_handle, pMechanism, hUnwrappingKey, pWrappedKey, ulWrappedKeyLen, pTemplate, ulAttributeCount, phKey); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_DeriveKey will verify that the session handle is valid within * the framework, that the mechanism is not disabled for the slot * associated with this session, and then redirect to the underlying * provider. */ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) { CK_RV rv; pkcs11_session_t *sessp; CK_SLOT_ID slotid; /* Check for a fastpath */ if (purefastpath || policyfastpath) { if (policyfastpath && pkcs11_is_dismech(fast_slot, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } return (fast_funcs->C_DeriveKey(hSession, pMechanism, hBaseKey, pTemplate, ulAttributeCount, phKey)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } slotid = sessp->se_slotid; /* Make sure this is not a disabled mechanism */ if (pkcs11_is_dismech(slotid, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } /* Initialize the digest with the underlying provider */ rv = FUNCLIST(slotid)->C_DeriveKey(sessp->se_handle, pMechanism, hBaseKey, pTemplate, ulAttributeCount, phKey); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include "pkcs11Global.h" #include "pkcs11Session.h" #include "pkcs11Slot.h" /* * C_CreateObject is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_CreateObject(hSession, pTemplate, ulCount, phObject)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_CreateObject(sessp->se_handle, pTemplate, ulCount, phObject); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_CopyObject is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_CopyObject(hSession, hObject, pTemplate, ulCount, phNewObject)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_CopyObject(sessp->se_handle, hObject, pTemplate, ulCount, phNewObject); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_DestroyObject is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_DestroyObject(hSession, hObject)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_DestroyObject(sessp->se_handle, hObject); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_GetAttributeValue is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_GetAttributeValue(hSession, hObject, pTemplate, ulCount)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_GetAttributeValue(sessp->se_handle, hObject, pTemplate, ulCount); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_SetAttributeValue is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_SetAttributeValue(hSession, hObject, pTemplate, ulCount)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_SetAttributeValue(sessp->se_handle, hObject, pTemplate, ulCount); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_GetObjectSize is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_GetObjectSize(hSession, hObject, pulSize)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_GetObjectSize(sessp->se_handle, hObject, pulSize); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_FindObjectsInit is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_FindObjectsInit(hSession, pTemplate, ulCount)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_FindObjectsInit(sessp->se_handle, pTemplate, ulCount); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_FindObjects is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_FindObjects(hSession, phObject, ulMaxObjectCount, pulObjectCount)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_FindObjects(sessp->se_handle, phObject, ulMaxObjectCount, pulObjectCount); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_FindObjectsFinal is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_FindObjectsFinal(hSession)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_FindObjectsFinal(sessp->se_handle); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include "pkcs11Global.h" #include "pkcs11Session.h" #include "pkcs11Slot.h" /* * C_SeedRandom will verify that the session handle is valid within * the framework, that random numbers are not disabled for the slot * associated with this session, and then redirect to the underlying * provider. */ CK_RV C_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen) { CK_RV rv; pkcs11_session_t *sessp; CK_SLOT_ID slotid; /* Check for a fastpath */ if (purefastpath || policyfastpath) { /* Check if random number functions are allowed */ if (policyfastpath && slottable->st_slots[fast_slot]->sl_norandom) { return (CKR_FUNCTION_FAILED); } return (fast_funcs->C_SeedRandom(hSession, pSeed, ulSeedLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } slotid = sessp->se_slotid; /* Check if random number functions are allowed */ if (slottable->st_slots[slotid]->sl_norandom) return (CKR_FUNCTION_FAILED); /* Pass data to the provider */ rv = FUNCLIST(slotid)->C_SeedRandom(sessp->se_handle, pSeed, ulSeedLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_GenerateRandom will verify that the session handle is valid within * the framework, that random numbers are not disabled for the slot * associated with this session, and then redirect to the underlying * provider. */ CK_RV C_GenerateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen) { CK_RV rv; pkcs11_session_t *sessp; CK_SLOT_ID slotid; /* Check for a fastpath */ if (purefastpath || policyfastpath) { /* Check if random number functions are allowed */ if (policyfastpath && slottable->st_slots[fast_slot]->sl_norandom) { return (CKR_FUNCTION_FAILED); } return (fast_funcs->C_GenerateRandom(hSession, pRandomData, ulRandomLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } slotid = sessp->se_slotid; /* Check if random number functions are allowed */ if (slottable->st_slots[slotid]->sl_norandom) return (CKR_FUNCTION_FAILED); /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_GenerateRandom(sessp->se_handle, pRandomData, ulRandomLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Solaris specific functions to reduce the initialization * overhead of using PKCS #11 */ #include #include #include #include #include #include static CK_OBJECT_CLASS objclass = CKO_SECRET_KEY; static CK_BBOOL falsevalue = FALSE; static CK_BBOOL truevalue = TRUE; #define NUM_SECRETKEY_ATTRS 12 typedef struct _ATTRTYPE_MECHINFO_MAPPING { CK_ATTRIBUTE_TYPE attr; CK_FLAGS flag; } ATTRTYPE_MECHINFO_MAPPING; /* possible attribute types for creating key */ ATTRTYPE_MECHINFO_MAPPING mapping[] = { {CKA_ENCRYPT, CKF_ENCRYPT}, {CKA_DECRYPT, CKF_DECRYPT}, {CKA_SIGN, CKF_SIGN}, {CKA_VERIFY, CKF_VERIFY}, {CKA_WRAP, CKF_WRAP}, {CKA_UNWRAP, CKF_UNWRAP} }; /* * List of mechanisms that only supports asymmetric key operations * in PKCS #11 V2.11 */ CK_MECHANISM_TYPE asymmetric_mechs[] = { CKM_RSA_PKCS_KEY_PAIR_GEN, CKM_RSA_PKCS, CKM_RSA_9796, CKM_RSA_X_509, CKM_RSA_PKCS_OAEP, CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31, CKM_RSA_PKCS_PSS, CKM_DSA_KEY_PAIR_GEN, CKM_DSA, CKM_DSA_SHA1, CKM_DSA_PARAMETER_GEN, CKM_ECDSA_KEY_PAIR_GEN, CKM_EC_KEY_PAIR_GEN, CKM_ECDSA, CKM_ECDSA_SHA1, CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE, CKM_ECMQV_DERIVE }; typedef struct _KEY_TYPE_SIZE_MAPPING { CK_KEY_TYPE type; CK_ULONG len; } KEY_TYPE_SIZE_MAPPING; /* * List of secret key types that have fixed sizes and their sizes. * These key types do not allow CKA_VALUE_LEN for key generation. * The sizes are in bytes. * * Discrete-sized keys, such as AES and Twofish, and variable sized * keys, such as Blowfish, are not in this list. */ KEY_TYPE_SIZE_MAPPING fixed_size_secrets[] = { {CKK_DES, 8}, {CKK_DES2, 16}, {CKK_DES3, 24}, {CKK_IDEA, 16}, {CKK_CDMF, 8}, {CKK_SKIPJACK, 12}, {CKK_BATON, 40}, {CKK_JUNIPER, 40} }; /* * match_mech is an example of many possible criteria functions. * It matches the given mech type (in args) with the slot's mech info. * If no match is found, pkcs11_GetCriteriaSession is asked to return * CKR_MECHANISM_INVALID. */ boolean_t match_mech(CK_SLOT_ID slot_id, void *args, CK_RV *rv) { CK_MECHANISM_INFO mech_info; CK_MECHANISM_TYPE mech = (CK_MECHANISM_TYPE)args; *rv = CKR_MECHANISM_INVALID; return (C_GetMechanismInfo(slot_id, mech, &mech_info) == CKR_OK); } /* * pkcs11_GetCriteriaSession will initialize the framework and do all * the necessary work of calling C_GetSlotList(), C_GetMechanismInfo() * C_OpenSession() to create a session that meets all the criteria in * the given function pointer. * * The criteria function must return a boolean value of true or false. * The arguments to the function are the current slot id, an opaque * args value that is passed through to the function, and the error * value pkcs11_GetCriteriaSession should return if no slot id meets the * criteria. * * If the function is called multiple times, it will return a new session * without reinitializing the framework. */ CK_RV pkcs11_GetCriteriaSession( boolean_t (*criteria)(CK_SLOT_ID slot_id, void *args, CK_RV *rv), void *args, CK_SESSION_HANDLE_PTR hSession) { CK_RV rv; CK_ULONG slotcount; CK_SLOT_ID_PTR slot_list; CK_SLOT_ID slot_id; CK_ULONG i; if (hSession == NULL || criteria == NULL) { return (CKR_ARGUMENTS_BAD); } /* initialize PKCS #11 */ if (!pkcs11_initialized) { rv = C_Initialize(NULL); if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) { return (rv); } } /* get slot count */ rv = C_GetSlotList(0, NULL, &slotcount); if (rv != CKR_OK) { return (rv); } if (slotcount == 0) { return (CKR_FUNCTION_FAILED); } /* allocate memory for slot list */ slot_list = malloc(slotcount * sizeof (CK_SLOT_ID)); if (slot_list == NULL) { return (CKR_HOST_MEMORY); } if ((rv = C_GetSlotList(0, slot_list, &slotcount)) != CKR_OK) { free(slot_list); return (rv); } /* find slot with matching criteria */ for (i = 0; i < slotcount; i++) { slot_id = slot_list[i]; if ((*criteria)(slot_id, args, &rv)) { break; } } if (i == slotcount) { /* no matching slot found */ free(slot_list); return (rv); /* this rv is from the criteria function */ } rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL, NULL, hSession); free(slot_list); return (rv); } /* * SUNW_C_GetMechSession will initialize the framework and do all * of the neccessary work of calling C_GetSlotList(), C_GetMechanismInfo() * C_OpenSession() to create a session capable of providing the requested * mechanism. * * If the function is called multiple times, it will return a new session * without reinitializing the framework. */ CK_RV SUNW_C_GetMechSession(CK_MECHANISM_TYPE mech, CK_SESSION_HANDLE_PTR hSession) { /* * All the code in this function can be replaced with one line: * * return (pkcs11_GetCriteriaSession(match_mech, (void *)mech, * hSession)); * */ CK_RV rv; CK_ULONG slotcount; CK_SLOT_ID_PTR slot_list; CK_SLOT_ID slot_id; CK_MECHANISM_INFO mech_info; CK_ULONG i; if (hSession == NULL) { return (CKR_ARGUMENTS_BAD); } /* initialize PKCS #11 */ if (!pkcs11_initialized) { rv = C_Initialize(NULL); if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) { return (rv); } } /* get slot count */ rv = C_GetSlotList(0, NULL, &slotcount); if (rv != CKR_OK) { return (rv); } if (slotcount == 0) { return (CKR_FUNCTION_FAILED); } /* allocate memory for slot list */ slot_list = malloc(slotcount * sizeof (CK_SLOT_ID)); if (slot_list == NULL) { return (CKR_HOST_MEMORY); } if ((rv = C_GetSlotList(0, slot_list, &slotcount)) != CKR_OK) { free(slot_list); return (rv); } /* find slot with matching mechanism */ for (i = 0; i < slotcount; i++) { slot_id = slot_list[i]; if (C_GetMechanismInfo(slot_id, mech, &mech_info) == CKR_OK) { /* found mechanism */ break; } } if (i == slotcount) { /* no matching mechanism found */ free(slot_list); return (CKR_MECHANISM_INVALID); } rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL, NULL, hSession); free(slot_list); return (rv); } /* * SUNW_C_KeyToObject creates a secret key object for the given * mechanism from the rawkey data. */ CK_RV SUNW_C_KeyToObject(CK_SESSION_HANDLE hSession, CK_MECHANISM_TYPE mech, const void *rawkey, size_t rawkey_len, CK_OBJECT_HANDLE_PTR obj) { CK_RV rv; CK_SESSION_INFO session_info; CK_SLOT_ID slot_id; CK_MECHANISM_INFO mech_info; CK_ULONG i, j; CK_KEY_TYPE keytype; CK_ULONG num_asym_mechs, num_mapping; /* template for creating generic secret key object */ CK_ATTRIBUTE template[NUM_SECRETKEY_ATTRS]; if ((hSession == CK_INVALID_HANDLE) || (obj == NULL) || (rawkey == NULL) || (rawkey_len == 0)) { return (CKR_ARGUMENTS_BAD); } /* * Check to make sure mechanism type is not for asymmetric key * only operations. This function is only applicable to * generating secret key. */ num_asym_mechs = sizeof (asymmetric_mechs) / sizeof (CK_MECHANISM_TYPE); for (i = 0; i < num_asym_mechs; i++) { if (mech == asymmetric_mechs[i]) { return (CKR_MECHANISM_INVALID); } } rv = C_GetSessionInfo(hSession, &session_info); if (rv != CKR_OK) { return (rv); } slot_id = session_info.slotID; i = 0; template[i].type = CKA_CLASS; template[i].pValue = &objclass; template[i].ulValueLen = sizeof (objclass); i++; /* get the key type for this mechanism */ if ((rv = pkcs11_mech2keytype(mech, &keytype)) != CKR_OK) { return (rv); } assert(i < NUM_SECRETKEY_ATTRS); template[i].type = CKA_KEY_TYPE; template[i].pValue = &keytype; template[i].ulValueLen = sizeof (keytype); i++; rv = C_GetMechanismInfo(slot_id, mech, &mech_info); if (rv != CKR_OK) { return (rv); } /* set the attribute type flag on object based on mechanism */ num_mapping = sizeof (mapping) / sizeof (ATTRTYPE_MECHINFO_MAPPING); for (j = 0; j < num_mapping; j++) { assert(i < NUM_SECRETKEY_ATTRS); template[i].type = mapping[j].attr; template[i].ulValueLen = sizeof (falsevalue); if (mech_info.flags & ((mapping[j]).flag)) { template[i].pValue = &truevalue; } else { template[i].pValue = &falsevalue; } i++; } assert(i < NUM_SECRETKEY_ATTRS); template[i].type = CKA_TOKEN; template[i].pValue = &falsevalue; template[i].ulValueLen = sizeof (falsevalue); i++; assert(i < NUM_SECRETKEY_ATTRS); template[i].type = CKA_VALUE; template[i].pValue = (CK_VOID_PTR)rawkey; template[i].ulValueLen = (CK_ULONG)rawkey_len; i++; rv = C_CreateObject(hSession, template, i, obj); return (rv); } /* * pkcs11_PasswdToPBKD2Object will create a secret key from the given string * (e.g. passphrase) using PKCS#5 Password-Based Key Derivation Function 2 * (PBKD2). * * Session must be open. Salt and iterations use defaults. */ CK_RV pkcs11_PasswdToPBKD2Object(CK_SESSION_HANDLE hSession, char *passphrase, size_t passphrase_len, void *salt, size_t salt_len, CK_ULONG iterations, CK_KEY_TYPE key_type, CK_ULONG key_len, CK_FLAGS key_flags, CK_OBJECT_HANDLE_PTR obj) { CK_RV rv; CK_PKCS5_PBKD2_PARAMS params; CK_MECHANISM mechanism; CK_KEY_TYPE asym_key_type; CK_ULONG i, j, num_asym_mechs, num_fixed_secs, num_mapping; CK_ATTRIBUTE template[NUM_SECRETKEY_ATTRS]; if (hSession == CK_INVALID_HANDLE || obj == NULL || passphrase == NULL || passphrase_len == 0 || iterations == 0UL) { return (CKR_ARGUMENTS_BAD); } /* * Check to make sure key type is not asymmetric. This function * is only applicable to generating secret key. */ num_asym_mechs = sizeof (asymmetric_mechs) / sizeof (CK_MECHANISM_TYPE); for (i = 0; i < num_asym_mechs; i++) { rv = pkcs11_mech2keytype(asymmetric_mechs[i], &asym_key_type); assert(rv == CKR_OK); if (key_type == asym_key_type) { return (CKR_KEY_TYPE_INCONSISTENT); } } /* * Key length must either be 0 or the correct size for PBKD of * fixed-size secret keys. However, underlying key generation * cannot have CKA_VALUE_LEN set for the key length attribute. */ num_fixed_secs = sizeof (fixed_size_secrets) / sizeof (KEY_TYPE_SIZE_MAPPING); for (i = 0; i < num_fixed_secs; i++) { if (key_type == fixed_size_secrets[i].type) { if (key_len == fixed_size_secrets[i].len) { key_len = 0; } if (key_len == 0) { break; } return (CKR_KEY_SIZE_RANGE); } } if (salt == NULL || salt_len == 0) { params.saltSource = 0; params.pSaltSourceData = NULL; params.ulSaltSourceDataLen = 0; } else { params.saltSource = CKZ_SALT_SPECIFIED; params.pSaltSourceData = salt; params.ulSaltSourceDataLen = salt_len; } params.iterations = iterations; params.prf = CKP_PKCS5_PBKD2_HMAC_SHA1; params.pPrfData = NULL; params.ulPrfDataLen = 0; params.pPassword = (CK_UTF8CHAR_PTR)passphrase; params.ulPasswordLen = (CK_ULONG_PTR)&passphrase_len; /* * PKCS#11 spec error, ulPasswordLen should have been pulPasswordLen, * or its type should have been CK_ULONG instead of CK_ULONG_PTR, * but it's legacy now */ mechanism.mechanism = CKM_PKCS5_PBKD2; mechanism.pParameter = ¶ms; mechanism.ulParameterLen = sizeof (params); i = 0; template[i].type = CKA_CLASS; template[i].pValue = &objclass; template[i].ulValueLen = sizeof (objclass); i++; assert(i < NUM_SECRETKEY_ATTRS); template[i].type = CKA_KEY_TYPE; template[i].pValue = &key_type; template[i].ulValueLen = sizeof (key_type); i++; assert(i < NUM_SECRETKEY_ATTRS); template[i].type = CKA_TOKEN; template[i].pValue = &falsevalue; template[i].ulValueLen = sizeof (falsevalue); i++; if (key_len != 0) { assert(i < NUM_SECRETKEY_ATTRS); template[i].type = CKA_VALUE_LEN; template[i].pValue = &key_len; template[i].ulValueLen = sizeof (key_len); i++; } /* * C_GenerateKey may not implicitly set capability attributes, * e.g. CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, ... */ num_mapping = sizeof (mapping) / sizeof (ATTRTYPE_MECHINFO_MAPPING); for (j = 0; j < num_mapping; j++) { assert(i < NUM_SECRETKEY_ATTRS); template[i].type = mapping[j].attr; template[i].pValue = (key_flags & ((mapping[j]).flag)) ? &truevalue : &falsevalue; template[i].ulValueLen = sizeof (falsevalue); i++; } rv = C_GenerateKey(hSession, &mechanism, template, i, obj); return (rv); } /* * pkcs11_ObjectToKey gets the rawkey data from a secret key object. * The caller is responsible to free the allocated rawkey data. * * Optionally the object can be destroyed after the value is retrieved. * As an example, after using pkcs11_PasswdToPBKD2Object() to create a * secret key object from a passphrase, an app may call pkcs11_ObjectToKey * to get the rawkey data. The intermediate object may no longer be needed * and should be destroyed. */ CK_RV pkcs11_ObjectToKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE obj, void **rawkey, size_t *rawkey_len, boolean_t destroy_obj) { CK_RV rv; CK_ATTRIBUTE template; if (hSession == CK_INVALID_HANDLE) return (CKR_SESSION_HANDLE_INVALID); if (obj == 0) return (CKR_OBJECT_HANDLE_INVALID); if (rawkey == NULL || rawkey_len == NULL) return (CKR_ARGUMENTS_BAD); template.type = CKA_VALUE; template.pValue = NULL; template.ulValueLen = 0; /* First get the size of the rawkey */ rv = C_GetAttributeValue(hSession, obj, &template, 1); if (rv != CKR_OK) { return (rv); } template.pValue = malloc(template.ulValueLen); if (template.pValue == NULL) { return (CKR_HOST_MEMORY); } /* Then get the rawkey data */ rv = C_GetAttributeValue(hSession, obj, &template, 1); if (rv != CKR_OK) { free(template.pValue); return (rv); } if (destroy_obj) { /* * Could have asserted rv == CKR_OK, making threaded * apps that share objects see stars. Here mercy is ok. */ (void) C_DestroyObject(hSession, obj); } *rawkey = template.pValue; *rawkey_len = template.ulValueLen; return (CKR_OK); } /* * pkcs11_PasswdToKey will create PKCS#5 PBKD2 rawkey data from the * given passphrase. The caller is responsible to free the allocated * rawkey data. */ CK_RV pkcs11_PasswdToKey(CK_SESSION_HANDLE hSession, char *passphrase, size_t passphrase_len, void *salt, size_t salt_len, CK_KEY_TYPE key_type, CK_ULONG key_len, void **rawkey, size_t *rawkey_len) { CK_RV rv; CK_OBJECT_HANDLE obj; rv = pkcs11_PasswdToPBKD2Object(hSession, passphrase, passphrase_len, salt, salt_len, CK_PKCS5_PBKD2_ITERATIONS, key_type, key_len, 0, &obj); if (rv != CKR_OK) return (rv); rv = pkcs11_ObjectToKey(hSession, obj, rawkey, rawkey_len, B_TRUE); return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include "pkcs11Global.h" #include "pkcs11Session.h" #include "pkcs11Slot.h" #include "metaGlobal.h" /* * C_OpenSession will need to create a pseudo session associated * with the session created by the plugged in provider. Only * minimal argument checking is done here, as we rely on the * underlying provider to catch most errors. */ CK_RV C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession) { CK_RV rv; CK_SLOT_ID true_id; CK_SLOT_ID fw_st_id; /* id for accessing framework's slottable */ CK_SESSION_HANDLE prov_sess; if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Check for a fastpath */ if (purefastpath || policyfastpath) { if (metaslot_enabled) { /* * if metaslot is enabled and we are in fastpath * mode, only one other slot is in the framework * so, need to go to that slot's entry * to look up the true slot ID for the slot */ return (fast_funcs->C_OpenSession(TRUEID(slotID+1), flags, pApplication, Notify, phSession)); } else { return (fast_funcs->C_OpenSession(slotID, flags, pApplication, Notify, phSession)); } } if (slotID == METASLOT_FRAMEWORK_ID) { rv = meta_OpenSession(METASLOT_SLOTID, flags, pApplication, Notify, &prov_sess); } else { /* Check that slotID is valid */ if (pkcs11_validate_and_convert_slotid(slotID, &fw_st_id) != CKR_OK) { return (CKR_SLOT_ID_INVALID); } true_id = TRUEID(fw_st_id); rv = FUNCLIST(fw_st_id)->C_OpenSession(true_id, flags, pApplication, Notify, &prov_sess); } /* Present consistent interface for framework */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } else if (rv != CKR_OK) { /* could not create session with provider, return now */ return (rv); } /* Provider was successful, now create session in framework */ if (slotID == METASLOT_FRAMEWORK_ID) { rv = pkcs11_session_add( slottable->st_slots[METASLOT_FRAMEWORK_ID], METASLOT_FRAMEWORK_ID, phSession, prov_sess); } else { rv = pkcs11_session_add(slottable->st_slots[fw_st_id], fw_st_id, phSession, prov_sess); } if (rv != CKR_OK) { /* Trouble in the framework, clean up provider session */ FUNCLIST(slotID)->C_CloseSession(prov_sess); } return (rv); } /* * C_CloseSession will close a session with the underlying provider, * and if that's successful will close it in the framework. */ CK_RV C_CloseSession(CK_SESSION_HANDLE hSession) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_CloseSession(hSession)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Delete the session with the provider */ rv = FUNCLIST(sessp->se_slotid)->C_CloseSession(sessp->se_handle); /* Present consistent interface for framework */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } else if (rv != CKR_OK) { /* could not delete session with provider, return now */ return (rv); } /* Delete session from the framework */ pkcs11_session_delete(slottable->st_slots[sessp->se_slotid], sessp); return (rv); } /* * C_CloseAllSessions will close all sessions associated with this * slot with the underlying provider. If that is successful, will * close the associated sessions in the framework. If the provider * has not implemented C_CloseAllSessions, then we will loop through * the list of sessions and individually call C_CloseSession. */ CK_RV C_CloseAllSessions(CK_SLOT_ID slotID) { CK_RV rv, rv1; CK_SLOT_ID true_id; CK_SLOT_ID fw_st_id; /* id for accessing framework's slottable */ pkcs11_session_t *sessp, *sess_nextp; pkcs11_slot_t *slotp; if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Check for a fastpath */ if (purefastpath || policyfastpath) { if (metaslot_enabled) { /* * if metaslot is enabled and we are in fastpath * mode, only one other slot is in the framework * so, need to go to that slot's entry * to look up the true slot ID for the slot */ return (fast_funcs->C_CloseAllSessions( TRUEID(slotID+1))); } else { return (fast_funcs->C_CloseAllSessions(slotID)); } } /* Check that slotID is valid */ if (pkcs11_validate_and_convert_slotid(slotID, &fw_st_id) != CKR_OK) { return (CKR_SLOT_ID_INVALID); } slotp = slottable->st_slots[fw_st_id]; true_id = TRUEID(fw_st_id); rv = FUNCLIST(fw_st_id)->C_CloseAllSessions(true_id); /* Present consistent interface for framework */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { /* Need to attempt to individually delete sessions */ /* reset rv */ rv = CKR_OK; (void) pthread_mutex_lock(&slotp->sl_mutex); sessp = slotp->sl_sess_list; while (sessp) { sess_nextp = sessp->se_next; rv1 = FUNCLIST(fw_st_id)-> C_CloseSession(sessp->se_handle); /* Record the first error encountered */ if ((rv == CKR_OK) && (rv1 != CKR_OK)) { rv = rv1; } sessp = sess_nextp; } (void) pthread_mutex_unlock(&slotp->sl_mutex); } if (rv != CKR_OK) { /* could not delete sessionlist with provider, return now */ return (rv); } /* Delete sessions from the framework */ pkcs11_sessionlist_delete(slotp); return (rv); } /* * C_GetSessionInfo is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) { CK_RV rv; CK_SLOT_ID slot_id; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { rv = fast_funcs->C_GetSessionInfo(hSession, pInfo); /* * If metaslot is enabled, and we are here, that * that means there's only 1 other slot in the * framework, and that slot should be hidden. * so, override value of slot id to be metaslot's * slot id. */ if (metaslot_enabled) { pInfo->slotID = METASLOT_FRAMEWORK_ID; } return (rv); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Find the slot id for the framework */ slot_id = sessp->se_slotid; /* Get session info from the provider */ rv = FUNCLIST(slot_id)-> C_GetSessionInfo(sessp->se_handle, pInfo); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } /* Override value of slot id to framework's */ pInfo->slotID = slot_id; return (rv); } /* * C_GetOperationState is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG_PTR pulOperationStateLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_GetOperationState(hSession, pOperationState, pulOperationStateLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Get the operation state with the provider */ rv = FUNCLIST(sessp->se_slotid)->C_GetOperationState(sessp->se_handle, pOperationState, pulOperationStateLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_SetOperationState is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_SetOperationState(hSession, pOperationState, ulOperationStateLen, hEncryptionKey, hAuthenticationKey)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Set the operation state with the provider */ rv = FUNCLIST(sessp->se_slotid)->C_SetOperationState(sessp->se_handle, pOperationState, ulOperationStateLen, hEncryptionKey, hAuthenticationKey); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_Login is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_Login(hSession, userType, pPin, ulPinLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Login with the provider */ rv = FUNCLIST(sessp->se_slotid)->C_Login(sessp->se_handle, userType, pPin, ulPinLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_Logout is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_Logout(CK_SESSION_HANDLE hSession) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_Logout(hSession)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } rv = FUNCLIST(sessp->se_slotid)->C_Logout(sessp->se_handle); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * 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. */ #ifndef _PKCS11_SESSION_H #define _PKCS11_SESSION_H #ifdef __cplusplus extern "C" { #endif #define PKCS11_SESSION_MAGIC 0xECF00001 typedef struct pkcs11_session { ulong_t se_magic; /* ensure this is a valid session */ CK_SESSION_HANDLE se_handle; /* from slot's C_OpenSession() */ CK_SLOT_ID se_slotid; /* slotID in framework */ struct pkcs11_session *se_prev; /* Chain of sessions */ struct pkcs11_session *se_next; /* in this slot */ } pkcs11_session_t; /* * This macro is used to typecast a session handle to a pointer * to a session structure. It also checks to see if the session * is tagged with a session magic number. This is to detect when an * application passes a bogus session pointer. */ #define HANDLE2SESSION(hSession, sessionp, rv)\ sessionp = (pkcs11_session_t *)(hSession); \ rv = CKR_OK; \ if ((sessionp == NULL) || \ (sessionp->se_magic != PKCS11_SESSION_MAGIC)) \ rv = CKR_SESSION_HANDLE_INVALID; struct pkcs11_slot; extern CK_RV pkcs11_session_add(struct pkcs11_slot *pslot, CK_SLOT_ID slot_id, CK_SESSION_HANDLE_PTR pfwhandle, CK_SESSION_HANDLE prov_sess); extern void pkcs11_session_delete(struct pkcs11_slot *pslot, pkcs11_session_t *psess); extern void pkcs11_sessionlist_delete(struct pkcs11_slot *pslot); #ifdef __cplusplus } #endif #endif /* _PKCS11_SESSION_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include "pkcs11Global.h" #include "pkcs11Slot.h" #include "pkcs11Session.h" /* * pkcs11_session_add: * Create a session and add it to the list of sessions associated * with the slot it is being opened on. The session handle, fwsessionp, * will be the memory address of the session, typecast to a CK_SESSION_HANDLE. * * Assumptions: slotp is a valid slot, mutexes are not held, and * the provider already successfully opened related session. */ CK_RV pkcs11_session_add(pkcs11_slot_t *slotp, CK_SLOT_ID slot_id, CK_SESSION_HANDLE_PTR fwsessionp, CK_SESSION_HANDLE prov_sess) { pkcs11_session_t *newhandle = malloc(sizeof (pkcs11_session_t)); if (newhandle == NULL) { return (CKR_HOST_MEMORY); } newhandle->se_magic = PKCS11_SESSION_MAGIC; newhandle->se_handle = prov_sess; newhandle->se_slotid = slot_id; (void) pthread_mutex_lock(&slotp->sl_mutex); /* Insert the new session in the front of the slot's session list */ if (slotp->sl_sess_list == NULL) { slotp->sl_sess_list = newhandle; newhandle->se_prev = NULL; newhandle->se_next = NULL; } else { slotp->sl_sess_list->se_prev = newhandle; newhandle->se_next = slotp->sl_sess_list; newhandle->se_prev = NULL; slotp->sl_sess_list = newhandle; } /* Typecast the address of session structure to a session handle */ *fwsessionp = (CK_SESSION_HANDLE)newhandle; (void) pthread_mutex_unlock(&slotp->sl_mutex); return (CKR_OK); } /* * pkcs11_session_delete: * Delete a session from a particular slot's session list. * * Assumptions: slotp is a valid slot, sessp is a valid session, * provider has already successfully closed this session, and * mutexes are not held. */ void pkcs11_session_delete(pkcs11_slot_t *slotp, pkcs11_session_t *sessp) { /* Acquire the slot's lock */ (void) pthread_mutex_lock(&slotp->sl_mutex); if (slotp->sl_sess_list == sessp) { /* This is the first session in the list */ if (sessp->se_next != NULL) { slotp->sl_sess_list = sessp->se_next; sessp->se_next->se_prev = NULL; } else { /* Session is the only one in the list */ slotp->sl_sess_list = NULL; } } else { /* Session is not the first one in the list */ if (sessp->se_next != NULL) { /* Session is in the middle of the list */ sessp->se_prev->se_next = sessp->se_next; sessp->se_next->se_prev = sessp->se_prev; } else { /* Session is the last one in the list */ sessp->se_prev->se_next = NULL; } } /* Mark session as no longer valid */ sessp->se_magic = 0; free(sessp); (void) pthread_mutex_unlock(&slotp->sl_mutex); } /* * pkcs11_sessionlist_delete: * Delete all sessions associated with a particular slot's session list. * * Assumptions: slotp is a valid slot, no mutexes are held, and the * sessions were successfully closed with the provider already. */ void pkcs11_sessionlist_delete(pkcs11_slot_t *slotp) { pkcs11_session_t *sessp, *sess_nextp; sessp = slotp->sl_sess_list; /* Delete all the sessions in this slot's session list */ while (sessp) { sess_nextp = sessp->se_next; pkcs11_session_delete(slotp, sessp); sessp = sess_nextp; } slotp->sl_sess_list = NULL; } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include "pkcs11Global.h" #include "pkcs11Conf.h" #include "pkcs11Session.h" #include "pkcs11Slot.h" /* * C_SignInit will verify that the session handle is valid within the * framework, that the mechanism is not disabled for the slot * associated with this session, and then redirect to the underlying * provider. Policy is only checked for C_SignInit, since it is * required to be called before C_Sign and C_SignUpdate. */ CK_RV C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { CK_RV rv; pkcs11_session_t *sessp; CK_SLOT_ID slotid; /* Check for a fastpath */ if (purefastpath || policyfastpath) { if (policyfastpath && pkcs11_is_dismech(fast_slot, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } return (fast_funcs->C_SignInit(hSession, pMechanism, hKey)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } slotid = sessp->se_slotid; /* Make sure this is not a disabled mechanism */ if (pkcs11_is_dismech(slotid, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } /* Initialize the digest with the underlying provider */ rv = FUNCLIST(slotid)->C_SignInit(sessp->se_handle, pMechanism, hKey); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_Sign is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_Sign(hSession, pData, ulDataLen, pSignature, pulSignatureLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_Sign(sessp->se_handle, pData, ulDataLen, pSignature, pulSignatureLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_SignUpdate is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_SignUpdate(hSession, pPart, ulPartLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_SignUpdate(sessp->se_handle, pPart, ulPartLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_SignFinal is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_SignFinal(hSession, pSignature, pulSignatureLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_SignFinal(sessp->se_handle, pSignature, pulSignatureLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_SignRecoverInit will verify that the session handle is valid within * the framework, that the mechanism is not disabled for the slot * associated with this session, and then redirect to the underlying * provider. Policy is only checked for C_SignRecoverInit, since it is * required to be called before C_SignRecover. */ CK_RV C_SignRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { CK_RV rv; pkcs11_session_t *sessp; CK_SLOT_ID slotid; /* Check for a fastpath */ if (purefastpath || policyfastpath) { if (policyfastpath && pkcs11_is_dismech(fast_slot, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } return (fast_funcs->C_SignRecoverInit(hSession, pMechanism, hKey)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } slotid = sessp->se_slotid; /* Make sure this is not a disabled mechanism */ if (pkcs11_is_dismech(slotid, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } /* Initialize the digest with the underlying provider */ rv = FUNCLIST(slotid)->C_SignRecoverInit(sessp->se_handle, pMechanism, hKey); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_SignRecover is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_SignRecover(hSession, pData, ulDataLen, pSignature, pulSignatureLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_SignRecover(sessp->se_handle, pData, ulDataLen, pSignature, pulSignatureLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _PKCS11_SLOT_H #define _PKCS11_SLOT_H #ifdef __cplusplus extern "C" { #endif #include "pkcs11Session.h" #define MECHLIST_SIZE 32 /* * Used to pass arguments to child threads for C_WaitForSlotEvent. */ typedef struct wfse_args { CK_FLAGS flags; CK_VOID_PTR pReserved; CK_SLOT_ID slotid; } wfse_args_t; typedef struct pkcs11_slot { CK_SLOT_ID sl_id; /* real slotID from provider */ struct pkcs11_session *sl_sess_list; /* all open sessions */ pthread_mutex_t sl_mutex; /* protects: sl_sess_list, */ /* sl_tid, sl_wfse_state, */ /* and sl_wfse_args */ CK_FUNCTION_LIST_PTR sl_func_list; /* function entry points */ boolean_t sl_enabledpol; /* TRUE if policy for enabled */ CK_MECHANISM_TYPE_PTR sl_pol_mechs; /* policy restricted */ uint_t sl_pol_count; /* policy restricted */ boolean_t sl_norandom; /* TRUE if random is disabled */ void *sl_dldesc; /* from dlopen */ uint_t sl_prov_id; /* set by order read in */ uchar_t sl_wfse_state; /* Used by C_WaitForSlotEvent */ boolean_t sl_no_wfse; /* WaitForSlotEvent not impl */ pthread_t sl_tid; /* Used to track child thread */ wfse_args_t *sl_wfse_args; /* Used for WaitForSlotEvent */ } pkcs11_slot_t; /* * State definitions used for C_WaitForSlotEvent, stored in sl_wfse_state * for each slot. These states are mutually exclusive, ie only one should * be set at a time. */ #define WFSE_CLEAR 0x0 #define WFSE_EVENT 0x1 #define WFSE_ACTIVE 0x2 /* * Dynamically allocated array of slots, indexed by the slotID assigned * by the framework. st_first will be initialized to 1. Only if there * is more than one other slot present, triggering the existence of the * metaslot, with st_first be set to 0. st_last will be set to the * last slotID assigned, also used for looping through the slottable. */ typedef struct pkcs11_slottable { pkcs11_slot_t **st_slots; pthread_mutex_t st_mutex; /* Protects all data in the slottable */ /* except for st_start_cond. */ CK_SLOT_ID st_first; /* First used slot ID, used for loops */ CK_SLOT_ID st_last; /* Last slot ID allocated */ ulong_t st_cur_size; /* current memory allocated */ pthread_cond_t st_wait_cond; /* Used for C_WaitForSlotEvent */ CK_SLOT_ID st_event_slot; /* Slot with event */ boolean_t st_wfse_active; /* A thread is actively running WFSE */ boolean_t st_blocking; /* Blocking for C_WaitForSlotEvent */ boolean_t st_list_signaled; /* Listener has been signaled */ uint_t st_thr_count; /* Used for C_WaitForSlotEvent */ pthread_t st_tid; pthread_mutex_t st_start_mutex; /* wait for listener to start */ pthread_cond_t st_start_cond; /* signal when listener has started */ } pkcs11_slottable_t; /* * This macro is used to quickly derefence from a framework slot ID, * provided by an application, to the function pointers for the correct * underlying provider. */ #define FUNCLIST(slotID) (slottable->st_slots[(slotID)]->sl_func_list) /* * This macro is used to quickly get the slot ID associated with this * slot ID, that is used by the underlying provider. */ #define TRUEID(slotID) (slottable->st_slots[(slotID)]->sl_id) extern pkcs11_slottable_t *slottable; extern CK_RV pkcs11_slottable_initialize(); extern CK_RV pkcs11_slottable_increase(ulong_t increase); extern CK_RV pkcs11_slot_allocate(CK_SLOT_ID *slot); extern CK_RV pkcs11_slottable_delete(); extern CK_RV pkcs11_is_valid_slot(CK_SLOT_ID slot_id); extern CK_RV pkcs11_validate_and_convert_slotid(CK_SLOT_ID slot_id, CK_SLOT_ID *real_slot_id); #ifdef __cplusplus } #endif #endif /* _PKCS11_SLOT_H */ /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include "pkcs11Global.h" #include "pkcs11Conf.h" #include "pkcs11Slot.h" #include "metaGlobal.h" static void *listener_waitforslotevent(void *arg); static void *child_waitforslotevent(void *arg); /* * C_GetSlotList is implemented entirely within this framework, * using the slottable that was created during the call to * C_Initialize in pkcs11_slot_mapping(). The plugged in providers * are only queried when tokenPresent is set. * * If metaslot is enabled, the slot that provides keystore support * needs to be hidden. Therefore, even when fastpath is enabled, * we can't go through fastpath because the slot needs to be * hidden. */ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount) { CK_RV rv; CK_RV prov_rv; CK_SLOT_ID true_id; CK_SLOT_INFO_PTR pinfo; CK_SLOT_ID count = 0, i; CK_SLOT_ID slot_id; /* slot ID for returning to the application */ /* Check for a fastpath */ if ((purefastpath || policyfastpath) && (!metaslot_enabled)) { return (fast_funcs->C_GetSlotList(tokenPresent, pSlotList, pulCount)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } if (pulCount == NULL) { return (CKR_ARGUMENTS_BAD); } if (tokenPresent) { /* Need to allocate memory for pinfo */ pinfo = malloc(sizeof (CK_SLOT_INFO)); if (pinfo == NULL) { return (CKR_HOST_MEMORY); } } /* * Count the number of valid slots for returning to the application. * If metaslot is enabled, the slot providing keystore support for * metaslot is skipped. Therefore, we can't simply sequentially * assign "i" as the slot id to be returned to the application. * The variable "slot_id" is used for keeping track of the * next slot id to be assigned. */ slot_id = slottable->st_first; for (i = slottable->st_first; i <= slottable->st_last; i++) { if ((pkcs11_is_valid_slot(i) == CKR_OK) && ((!metaslot_enabled) || (i != metaslot_keystore_slotid))) { /* Check if token present is required */ if (tokenPresent) { /* Check with provider */ true_id = TRUEID(i); prov_rv = FUNCLIST(i)-> C_GetSlotInfo(true_id, pinfo); if ((prov_rv != CKR_OK) || !(pinfo->flags & CKF_TOKEN_PRESENT)) { continue; } } /* Fill in the given buffer if it is sufficient */ if (pSlotList && (*pulCount > count)) { pSlotList[count] = slot_id; slot_id++; } count++; } } /* pSlotList set to NULL means caller only wants count */ if ((*pulCount < count) && (pSlotList != NULL)) { rv = CKR_BUFFER_TOO_SMALL; } else { rv = CKR_OK; } *pulCount = count; if (tokenPresent) { free(pinfo); } return (rv); } CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { CK_RV rv; CK_SLOT_ID fw_st_id; /* id for accessing framework's slottable */ if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Check for a fastpath */ if ((purefastpath || policyfastpath) && !metaslot_enabled) return (fast_funcs->C_GetSlotInfo(slotID, pInfo)); if (slotID == METASLOT_FRAMEWORK_ID) { /* just need to get metaslot information */ return (meta_GetSlotInfo(METASLOT_SLOTID, pInfo)); } /* Check that slotID is valid */ if (pkcs11_validate_and_convert_slotid(slotID, &fw_st_id) != CKR_OK) { return (CKR_SLOT_ID_INVALID); } rv = FUNCLIST(fw_st_id)->C_GetSlotInfo(TRUEID(fw_st_id), pInfo); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } CK_RV C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) { CK_RV rv; CK_SLOT_ID fw_st_id; /* id for accessing framework's slottable */ if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Check for a fastpath */ if ((purefastpath || policyfastpath) && !metaslot_enabled) return (fast_funcs->C_GetTokenInfo(slotID, pInfo)); if (slotID == METASLOT_FRAMEWORK_ID) { /* just need to get metaslot information */ return (meta_GetTokenInfo(METASLOT_SLOTID, pInfo)); } /* Check that slotID is valid */ if (pkcs11_validate_and_convert_slotid(slotID, &fw_st_id) != CKR_OK) { return (CKR_SLOT_ID_INVALID); } rv = FUNCLIST(fw_st_id)->C_GetTokenInfo(TRUEID(fw_st_id), pInfo); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_WaitForSlotEvent cannot be a direct pass through to the underlying * provider (except in the case of fastpath), due to the complex nature * of this function. The calling application is asking to be alerted * when an event has occurred on any of the slots in the framework, so * we need to check with all underlying providers and ask for events * on any of their slots. If this is called in blocking mode, we will * need to start threads to wait for slot events for each provider * plugged into the framework. */ CK_RV C_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved) { CK_SLOT_ID i, j; uint32_t prov_id; int32_t last_prov_id = -1; CK_RV rv = CKR_OK; CK_SLOT_ID event_slot; pkcs11_slot_t *cur_slot; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_WaitForSlotEvent(flags, pSlot, pReserved)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } if (pReserved != NULL) { return (CKR_ARGUMENTS_BAD); } /* * Check to see if we're already blocking on another threads * call to this function. If so, behaviour is undefined so * we should return to application. */ (void) pthread_mutex_lock(&slottable->st_mutex); if ((slottable->st_blocking) || (slottable->st_wfse_active)) { (void) pthread_mutex_unlock(&slottable->st_mutex); return (CKR_FUNCTION_FAILED); } else { slottable->st_wfse_active = B_TRUE; (void) pthread_mutex_unlock(&slottable->st_mutex); } /* * Check first to see if any events have been recorded * already on any of the slots, regardless of blocking or * thread status. */ for (i = slottable->st_first; i <= slottable->st_last; i++) { cur_slot = slottable->st_slots[i]; if (cur_slot->sl_wfse_state == WFSE_EVENT) { /* found one, clear event and notify application */ (void) pthread_mutex_lock(&cur_slot->sl_mutex); cur_slot->sl_wfse_state = WFSE_CLEAR; (void) pthread_mutex_unlock(&cur_slot->sl_mutex); *pSlot = i; /* * This event has been captured, clear the function's * active status. Other threads may now enter this * function. */ (void) pthread_mutex_lock(&slottable->st_mutex); slottable->st_wfse_active = B_FALSE; (void) pthread_mutex_unlock(&slottable->st_mutex); return (CKR_OK); } } /* * We could not find any existing event, so let's see * if we can block and start threads to watch for events. */ if (flags & CKF_DONT_BLOCK) { /* * Application does not want us to block so check with * underlying providers to see if any events have occurred. * Not every provider will have implemented this function, * so error codes or CKR_NO_EVENT can be ignored. */ for (i = slottable->st_first; i <= slottable->st_last; i++) { prov_id = slottable->st_slots[i]->sl_prov_id; cur_slot = slottable->st_slots[i]; /* * Only do process once per provider. */ if (prov_id == last_prov_id) { continue; } /* * Check to make sure a child thread is not already * running, due to another of the application's * thread calling this function. */ (void) pthread_mutex_lock(&cur_slot->sl_mutex); if (cur_slot->sl_wfse_state == WFSE_ACTIVE) { (void) pthread_mutex_unlock( &cur_slot->sl_mutex); continue; } cur_slot->sl_wfse_state = WFSE_ACTIVE; /* * Release the hold on the slot's mutex while we * are waiting for this function to complete. */ (void) pthread_mutex_unlock(&cur_slot->sl_mutex); rv = FUNCLIST(i)->C_WaitForSlotEvent(flags, pSlot, pReserved); (void) pthread_mutex_lock(&cur_slot->sl_mutex); cur_slot->sl_wfse_state = WFSE_CLEAR; (void) pthread_mutex_unlock(&cur_slot->sl_mutex); /* See if we've found a slot with an event */ if ((rv == CKR_OK) && (pSlot != NULL)) { /* * Try to map the returned slotid to a slot * allocated by the framework. All slots from * one provider are adjacent in the framework's * slottable, so search for a mapping while * the prov_id field is the same. */ j = i; while (prov_id == slottable->st_slots[j]->sl_prov_id) { /* Find the slot, remap pSlot */ if (*pSlot == TRUEID(j)) { *pSlot = j; (void) pthread_mutex_lock( &slottable->st_mutex); slottable->st_wfse_active = B_FALSE; (void) pthread_mutex_unlock( &slottable->st_mutex); return (CKR_OK); } j++; } } /* * If we reach this part of the loop, this * provider either had no events, did not support * this function, or set pSlot to a value we * could not find in the slots associated with * this provider. Continue checking with remaining * providers. */ last_prov_id = prov_id; } /* No provider had any events */ (void) pthread_mutex_lock(&slottable->st_mutex); slottable->st_wfse_active = B_FALSE; (void) pthread_mutex_unlock(&slottable->st_mutex); return (CKR_NO_EVENT); } else if (!(flags & CKF_DONT_BLOCK) && (pkcs11_cant_create_threads)) { /* * Application has asked us to block, but forbidden * us from creating threads. This is too risky to perform * with underlying providers (we may block indefinitely), * so will return an error in this case. */ (void) pthread_mutex_lock(&slottable->st_mutex); slottable->st_wfse_active = B_FALSE; (void) pthread_mutex_unlock(&slottable->st_mutex); return (CKR_FUNCTION_FAILED); } /* * Grab the st_start_mutex now, which will prevent the listener * thread from signaling on st_start_cond before we're ready to * wait for it. */ (void) pthread_mutex_lock(&slottable->st_start_mutex); /* * Application allows us to create threads and has * asked us to block. Create listener thread to wait for * child threads to return. */ (void) pthread_mutex_lock(&slottable->st_mutex); if (pthread_create(&slottable->st_tid, NULL, listener_waitforslotevent, NULL) != 0) { slottable->st_wfse_active = B_FALSE; (void) pthread_mutex_unlock(&slottable->st_mutex); (void) pthread_mutex_unlock(&slottable->st_start_mutex); return (CKR_FUNCTION_FAILED); } (void) pthread_mutex_unlock(&slottable->st_mutex); /* * Wait for the listening thread to get started before * we spawn child threads. */ (void) pthread_cond_wait(&slottable->st_start_cond, &slottable->st_start_mutex); (void) pthread_mutex_unlock(&slottable->st_start_mutex); /* * Need to hold the mutex on the entire slottable for the * entire setup of the child threads. Otherwise, the first * child thread may complete before a later child thread is * fully started, resulting in an inaccurate value of * st_thr_count and a potential race condition. */ (void) pthread_mutex_lock(&slottable->st_mutex); /* * Create child threads to check with the plugged in providers * to check for events. Keep a count of the current open threads, * so the listener thread knows when there are no more children * to listen for. Also, make sure a thread is not already active * for that provider. */ for (i = slottable->st_first; i <= slottable->st_last; i++) { prov_id = slottable->st_slots[i]->sl_prov_id; cur_slot = slottable->st_slots[i]; /* * Only do process once per provider. */ if (prov_id == last_prov_id) { continue; } /* * Check to make sure a child thread is not already running, * due to another of the application's threads calling * this function. Also, check that the provider has actually * implemented this function. */ (void) pthread_mutex_lock(&cur_slot->sl_mutex); if ((cur_slot->sl_wfse_state == WFSE_ACTIVE) || (cur_slot->sl_no_wfse)) { (void) pthread_mutex_unlock(&cur_slot->sl_mutex); last_prov_id = prov_id; continue; } /* Set slot to active */ cur_slot->sl_wfse_state = WFSE_ACTIVE; /* * set up variable to pass arguments to child threads. * Only need to set up once, as values will remain the * same for each successive call. */ if (cur_slot->sl_wfse_args == NULL) { cur_slot->sl_wfse_args = malloc(sizeof (wfse_args_t)); if (cur_slot->sl_wfse_args == NULL) { (void) pthread_mutex_unlock( &cur_slot->sl_mutex); slottable->st_wfse_active = B_FALSE; (void) pthread_mutex_unlock( &slottable->st_mutex); return (CKR_HOST_MEMORY); } cur_slot->sl_wfse_args->flags = flags; cur_slot->sl_wfse_args->pReserved = pReserved; cur_slot->sl_wfse_args->slotid = i; } /* Create child thread */ if (pthread_create(&cur_slot->sl_tid, NULL, child_waitforslotevent, (void *)cur_slot->sl_wfse_args) != 0) { (void) pthread_mutex_unlock(&cur_slot->sl_mutex); continue; } (void) pthread_mutex_unlock(&cur_slot->sl_mutex); /* * This counter is decremented every time a * child_waitforslotevent() wakes up the listener. */ slottable->st_thr_count++; last_prov_id = prov_id; } /* If no children are listening, kill the listener */ if (slottable->st_thr_count == 0) { (void) pthread_cancel(slottable->st_tid); /* If there are no child threads, no event will occur */ slottable->st_wfse_active = B_FALSE; (void) pthread_mutex_unlock(&slottable->st_mutex); return (CKR_NO_EVENT); } (void) pthread_mutex_unlock(&slottable->st_mutex); /* Wait for listener thread to terminate */ (void) pthread_join(slottable->st_tid, NULL); /* Make sure C_Finalize has not been called */ if (!pkcs11_initialized) { (void) pthread_mutex_lock(&slottable->st_mutex); slottable->st_wfse_active = B_FALSE; (void) pthread_mutex_unlock(&slottable->st_mutex); return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* See if any events actually occurred */ (void) pthread_mutex_lock(&slottable->st_mutex); event_slot = slottable->st_event_slot; (void) pthread_mutex_unlock(&slottable->st_mutex); if (pkcs11_is_valid_slot(event_slot) == CKR_OK) { (void) pthread_mutex_lock(&slottable-> st_slots[event_slot]->sl_mutex); if (slottable->st_slots[event_slot]-> sl_wfse_state == WFSE_EVENT) { /* An event has occurred on this slot */ slottable->st_slots[event_slot]->sl_wfse_state = WFSE_CLEAR; (void) pthread_mutex_unlock(&slottable-> st_slots[event_slot]->sl_mutex); *pSlot = event_slot; (void) pthread_mutex_lock(&slottable->st_mutex); slottable->st_blocking = B_FALSE; slottable->st_wfse_active = B_FALSE; (void) pthread_mutex_unlock(&slottable->st_mutex); return (CKR_OK); } else { (void) pthread_mutex_unlock(&slottable-> st_slots[event_slot]->sl_mutex); } } (void) pthread_mutex_lock(&slottable->st_mutex); slottable->st_blocking = B_FALSE; slottable->st_wfse_active = B_FALSE; (void) pthread_mutex_unlock(&slottable->st_mutex); /* No provider reported any events, or no provider implemented this */ return (CKR_NO_EVENT); } /* * C_GetMechanismList cannot just be a direct pass through to the * underlying provider, because we allow the administrator to * disable certain mechanisms from specific providers. This affects * both pulCount and pMechanismList. Only when the fastpath with * no policy is in effect can we pass through directly to the * underlying provider. * * It is necessary, for policy filtering, to get the actual list * of mechanisms from the underlying provider, even if the calling * application is just requesting a count. It is the only way to * get an accurate count of the number of mechanisms actually available. */ CK_RV C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount) { CK_RV rv = CKR_OK; CK_ULONG mech_count; CK_ULONG tmpmech_count; CK_MECHANISM_TYPE_PTR pmech_list, tmpmech_list; CK_SLOT_ID true_id; CK_SLOT_ID fw_st_id; /* id for accessing framework's slottable */ CK_FUNCTION_LIST_PTR prov_funcs; CK_ULONG i; if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Check for a fastpath */ if ((purefastpath || policyfastpath) && !metaslot_enabled) return (fast_funcs->C_GetMechanismList(slotID, pMechanismList, pulCount)); if (slotID == METASLOT_FRAMEWORK_ID) { return (meta_GetMechanismList(METASLOT_SLOTID, pMechanismList, pulCount)); } /* Check that slotID is valid */ if (pkcs11_validate_and_convert_slotid(slotID, &fw_st_id) != CKR_OK) { return (CKR_SLOT_ID_INVALID); } if (policyfastpath) { true_id = fw_st_id; slotID = fast_slot; prov_funcs = fast_funcs; } else { true_id = TRUEID(fw_st_id); prov_funcs = FUNCLIST(fw_st_id); } mech_count = 0; tmpmech_count = MECHLIST_SIZE; /* * Allocate memory for a mechanism list. We are assuming * that most mechanism lists will be less than MECHLIST_SIZE. * If that is not enough memory, we will try a second time * with more memory allocated. */ pmech_list = malloc(tmpmech_count * sizeof (CK_MECHANISM_TYPE)); if (pmech_list == NULL) { return (CKR_HOST_MEMORY); } /* * Attempt to get the mechanism list. PKCS11 supports * removable media, so the mechanism list of a slot can vary * over the life of the application. */ rv = prov_funcs->C_GetMechanismList(true_id, pmech_list, &tmpmech_count); if (rv == CKR_BUFFER_TOO_SMALL) { /* Need to use more space */ tmpmech_list = pmech_list; pmech_list = realloc (tmpmech_list, tmpmech_count * sizeof (CK_MECHANISM_TYPE)); if (pmech_list == NULL) { free(tmpmech_list); return (CKR_HOST_MEMORY); } /* Try again to get mechanism list. */ rv = prov_funcs->C_GetMechanismList(true_id, pmech_list, &tmpmech_count); } /* * Present consistent face to calling application. * If something strange has happened, or this function * is not supported by this provider, return a count * of zero mechanisms. */ if (rv != CKR_OK) { *pulCount = 0; free(pmech_list); return (CKR_OK); } /* * Process the mechanism list, removing any mechanisms * that are disabled via the framework. Even if the * application is only asking for a count, we must * process the actual mechanisms being offered by this slot. * We could not just subtract our stored count of disabled * mechanisms, since it is not guaranteed that those * mechanisms are actually supported by the slot. */ for (i = 0; i < tmpmech_count; i++) { /* Filter out the disabled mechanisms */ if (pkcs11_is_dismech(fw_st_id, pmech_list[i])) { continue; } /* * Only set pMechanismList if enough memory * is available. If it was set to NULL * originally, this loop will just be counting * mechanims. */ if (pMechanismList && (*pulCount > mech_count)) { pMechanismList[mech_count] = pmech_list[i]; } mech_count++; } /* * Catch the case where pMechanismList was not set to NULL, * yet the buffer was not large enough. If pMechanismList is * set to NULL, this function will simply set pulCount and * return CKR_OK. */ if ((*pulCount < mech_count) && (pMechanismList != NULL)) { *pulCount = mech_count; free(pmech_list); return (CKR_BUFFER_TOO_SMALL); } *pulCount = mech_count; free(pmech_list); return (CKR_OK); } CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo) { CK_RV rv; CK_SLOT_ID true_id; CK_SLOT_ID fw_st_id; /* id for accessing framework's slottable */ CK_FUNCTION_LIST_PTR prov_funcs; if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Check for a fastpath */ if ((purefastpath || policyfastpath) && !metaslot_enabled) return (fast_funcs->C_GetMechanismInfo(slotID, type, pInfo)); if (slotID == METASLOT_FRAMEWORK_ID) { /* just need to get metaslot information */ return (meta_GetMechanismInfo(METASLOT_SLOTID, type, pInfo)); } /* Check that slotID is valid */ if (pkcs11_validate_and_convert_slotid(slotID, &fw_st_id) != CKR_OK) { return (CKR_SLOT_ID_INVALID); } if (policyfastpath) { true_id = fw_st_id; slotID = fast_slot; prov_funcs = fast_funcs; } else { true_id = TRUEID(fw_st_id); prov_funcs = FUNCLIST(fw_st_id); } /* Make sure this is not a disabled mechanism */ if (pkcs11_is_dismech(fw_st_id, type)) { return (CKR_MECHANISM_INVALID); } rv = prov_funcs->C_GetMechanismInfo(true_id, type, pInfo); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } CK_RV C_InitToken(CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, CK_UTF8CHAR_PTR pLabel) { CK_RV rv; CK_SLOT_ID fw_st_id; /* id for accessing framework's slottable */ if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Check for a fastpath */ if ((purefastpath || policyfastpath) && !metaslot_enabled) return (fast_funcs->C_InitToken(slotID, pPin, ulPinLen, pLabel)); if (slotID == METASLOT_FRAMEWORK_ID) { /* just need to get metaslot information */ return (meta_InitToken(METASLOT_SLOTID, pPin, ulPinLen, pLabel)); } /* Check that slotID is valid */ if (pkcs11_validate_and_convert_slotid(slotID, &fw_st_id) != CKR_OK) { return (CKR_SLOT_ID_INVALID); } rv = FUNCLIST(fw_st_id)->C_InitToken(TRUEID(fw_st_id), pPin, ulPinLen, pLabel); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } CK_RV C_InitPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_InitPIN(hSession, pPin, ulPinLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Initialize the PIN with the provider */ rv = FUNCLIST(sessp->se_slotid)->C_InitPIN(sessp->se_handle, pPin, ulPinLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } CK_RV C_SetPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldPinLen, CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewPinLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_SetPIN(hSession, pOldPin, ulOldPinLen, pNewPin, ulNewPinLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Set the PIN with the provider */ rv = FUNCLIST(sessp->se_slotid)->C_SetPIN(sessp->se_handle, pOldPin, ulOldPinLen, pNewPin, ulNewPinLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * listener_waitforslotevent is spawned by the main C_WaitForSlotEvent() * to listen for events from any of the providers. It also watches the * count of threads, which may go to zero with no recorded events, if * none of the underlying providers have actually implemented this * function. */ /*ARGSUSED*/ static void * listener_waitforslotevent(void *arg) { CK_SLOT_ID eventID; /* Mark slottable in state blocking */ (void) pthread_mutex_lock(&slottable->st_mutex); slottable->st_blocking = B_TRUE; /* alert calling thread that this thread has started */ (void) pthread_mutex_lock(&slottable->st_start_mutex); (void) pthread_cond_signal(&slottable->st_start_cond); (void) pthread_mutex_unlock(&slottable->st_start_mutex); /* wait for an event, or number of threads to reach zero */ for (;;) { /* * Make sure we've really been signaled, and not waking * for another reason. */ while (slottable->st_list_signaled != B_TRUE) { (void) pthread_cond_wait(&slottable->st_wait_cond, &slottable->st_mutex); } slottable->st_list_signaled = B_FALSE; /* See why we were woken up */ if (!pkcs11_initialized) { /* Another thread has called C_Finalize() */ (void) pthread_mutex_unlock(&slottable->st_mutex); return (NULL); } /* A thread has finished, decrement counter */ slottable->st_thr_count--; eventID = slottable->st_event_slot; if (pkcs11_is_valid_slot(eventID) == CKR_OK) { (void) pthread_mutex_lock(&slottable-> st_slots[eventID]->sl_mutex); if (slottable->st_slots[eventID]-> sl_wfse_state == WFSE_EVENT) { (void) pthread_mutex_unlock(&slottable-> st_slots[eventID]->sl_mutex); /* * st_event_slot is set to a valid value, event * flag is set for that slot. The flag will * be cleared by main C_WaitForSlotEvent(). */ (void) pthread_mutex_unlock( &slottable->st_mutex); pthread_exit(0); } else { (void) pthread_mutex_unlock(&slottable-> st_slots[eventID]->sl_mutex); } } if (slottable->st_thr_count == 0) { (void) pthread_mutex_unlock(&slottable->st_mutex); /* No more threads, no events found */ pthread_exit(0); } } /*NOTREACHED*/ return (NULL); } /* * child_waitforslotevent is used as a child thread to contact * underlying provider's C_WaitForSlotEvent(). */ static void * child_waitforslotevent(void *arg) { wfse_args_t *wfse = (wfse_args_t *)arg; CK_SLOT_ID slot; CK_RV rv; uint32_t cur_prov; CK_SLOT_ID i; rv = FUNCLIST(wfse->slotid)->C_WaitForSlotEvent(wfse->flags, &slot, wfse->pReserved); /* * Need to hold the mutex while processing the results, to * keep things synchronized with the listener thread and * the slottable. Otherwise, due to the timing * at which some underlying providers complete, the listener * thread may not actually be blocking on st_wait_cond when * this child signals. Holding the lock a bit longer prevents * this from happening. */ (void) pthread_mutex_lock(&slottable->st_mutex); while (slottable->st_list_signaled == B_TRUE) { /* * We've taken the mutex when the listener should have * control. Release the mutex, thread scheduler should * give control back to the listener. */ (void) pthread_mutex_unlock(&slottable->st_mutex); (void) sleep(1); (void) pthread_mutex_lock(&slottable->st_mutex); } if (rv == CKR_OK) { /* we've had an event, find slot and store it */ cur_prov = slottable->st_slots[wfse->slotid]->sl_prov_id; /* * It is safe to unset active status now, since call to * underlying provider has already terminated, and we * hold the slottable wide mutex (st_mutex). */ (void) pthread_mutex_lock(&slottable-> st_slots[wfse->slotid]->sl_mutex); slottable->st_slots[wfse->slotid]->sl_wfse_state = WFSE_CLEAR; (void) pthread_mutex_unlock(&slottable-> st_slots[wfse->slotid]->sl_mutex); for (i = wfse->slotid; i <= slottable->st_last; i++) { if (cur_prov != slottable->st_slots[i]->sl_prov_id) { break; } if (slot == slottable->st_slots[i]->sl_id) { (void) pthread_mutex_lock(&slottable-> st_slots[i]->sl_mutex); slottable->st_slots[i]-> sl_wfse_state = WFSE_EVENT; (void) pthread_mutex_unlock(&slottable-> st_slots[i]->sl_mutex); slottable->st_event_slot = i; if (slottable->st_blocking) { slottable->st_list_signaled = B_TRUE; (void) pthread_cond_signal(&slottable-> st_wait_cond); } (void) pthread_mutex_unlock( &slottable->st_mutex); pthread_exit(0); } } } (void) pthread_mutex_lock(&slottable-> st_slots[wfse->slotid]->sl_mutex); /* * If the provider told us that it does not support * this function, we should mark it so we do not waste * time later with it. If an error returned, we'll clean * up this thread now and possibly try it again later. */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { slottable->st_slots[wfse->slotid]->sl_no_wfse = B_TRUE; } /* * It is safe to unset active status now, since call to * underlying provider has already terminated, and we * hold the slottable wide mutex (st_mutex). */ slottable->st_slots[wfse->slotid]->sl_wfse_state = WFSE_CLEAR; (void) pthread_mutex_unlock(&slottable-> st_slots[wfse->slotid]->sl_mutex); if (slottable->st_blocking) { slottable->st_list_signaled = B_TRUE; (void) pthread_cond_signal(&slottable->st_wait_cond); } (void) pthread_mutex_unlock(&slottable->st_mutex); /* Manually exit the thread, since nobody will join to it */ pthread_exit(0); /*NOTREACHED*/ return (NULL); } /* * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include "pkcs11Global.h" #include "pkcs11Slot.h" #include "metaGlobal.h" pkcs11_slottable_t *slottable = NULL; /* * pkcs11_slottable_initialize initizializes the global slottable. * This slottable will contain information about the plugged in * slots, including their mapped slotID. This function should only * be called by C_Intialize. */ CK_RV pkcs11_slottable_initialize() { pkcs11_slottable_t *stmp = malloc(sizeof (pkcs11_slottable_t)); if (stmp == NULL) return (CKR_HOST_MEMORY); stmp->st_first = 1; stmp->st_cur_size = 0; stmp->st_last = 0; stmp->st_slots = NULL; if (pthread_mutex_init(&stmp->st_mutex, NULL) != 0) { free(stmp); return (CKR_FUNCTION_FAILED); } /* Set up for possible threads later */ stmp->st_event_slot = 0; stmp->st_thr_count = 0; stmp->st_wfse_active = B_FALSE; stmp->st_blocking = B_FALSE; stmp->st_list_signaled = B_FALSE; (void) pthread_cond_init(&stmp->st_wait_cond, NULL); (void) pthread_mutex_init(&stmp->st_start_mutex, NULL); (void) pthread_cond_init(&stmp->st_start_cond, NULL); slottable = stmp; return (CKR_OK); } /* * pkcs11_slottable_increase should only be called from C_Initialize(). * It is called after the first call to C_GetSlotList() and is used to * increase the size of the slottable, as needed, to contain the next * set of slots that C_Initialize() is currently mapping into the framework. */ CK_RV pkcs11_slottable_increase(ulong_t increment) { pkcs11_slot_t **tmpslots; ulong_t newsize; (void) pthread_mutex_lock(&slottable->st_mutex); /* Add 1 to cover space for the metaslot */ newsize = slottable->st_last + increment + 1; /* Check to see if we already have enough space */ if (slottable->st_cur_size >= newsize) { (void) pthread_mutex_unlock(&slottable->st_mutex); return (CKR_OK); } tmpslots = realloc (slottable->st_slots, newsize * sizeof (pkcs11_slot_t *)); if (tmpslots == NULL) { (void) pthread_mutex_unlock(&slottable->st_mutex); return (CKR_HOST_MEMORY); } slottable->st_slots = tmpslots; slottable->st_cur_size = newsize; (void) pthread_mutex_unlock(&slottable->st_mutex); return (CKR_OK); } /* * pkcs11_slot_allocate should only be called from C_Initialize(). * We won't know if the metaslot will be used until after all of * the other slots have been allocated. */ CK_RV pkcs11_slot_allocate(CK_SLOT_ID *pslot_id) { pkcs11_slot_t *tmpslot; tmpslot = malloc(sizeof (pkcs11_slot_t)); if (tmpslot == NULL) return (CKR_HOST_MEMORY); bzero(tmpslot, sizeof (pkcs11_slot_t)); tmpslot->sl_wfse_state = WFSE_CLEAR; tmpslot->sl_enabledpol = B_FALSE; tmpslot->sl_no_wfse = B_FALSE; /* Initialize this slot's mutex */ if (pthread_mutex_init(&tmpslot->sl_mutex, NULL) != 0) { free(tmpslot); return (CKR_FUNCTION_FAILED); } (void) pthread_mutex_lock(&slottable->st_mutex); slottable->st_last++; *pslot_id = slottable->st_last; slottable->st_slots[*pslot_id] = tmpslot; (void) pthread_mutex_unlock(&slottable->st_mutex); return (CKR_OK); } /* * pkcs11_slottable_delete should only be called by C_Finalize(), * or by C_Initialize() in error conditions. */ CK_RV pkcs11_slottable_delete() { ulong_t i; uint32_t prov_id; int32_t last_prov_id = -1; pkcs11_slot_t *cur_slot; (void) pthread_mutex_lock(&slottable->st_mutex); for (i = slottable->st_first; i <= slottable->st_last; i++) { if (slottable->st_slots[i] != NULL) { cur_slot = slottable->st_slots[i]; prov_id = cur_slot->sl_prov_id; (void) pthread_mutex_lock(&cur_slot->sl_mutex); /* * For the first slot from this provider, do * extra cleanup. */ if (prov_id != last_prov_id) { if (cur_slot->sl_wfse_state == WFSE_ACTIVE) { (void) pthread_cancel (cur_slot->sl_tid); } /* * Only call C_Finalize of plug-in if we * get here from an explicit C_Finalize * call from an application. Otherwise, * there is a risk that the application may * have directly dlopened this provider and * we could interrupt their work. Plug-ins * should have their own _fini function to * clean up when they are no longer referenced. */ if ((cur_slot->sl_func_list != NULL) && (!fini_called)) { (void) cur_slot-> sl_func_list->C_Finalize(NULL); } /* metaslot won't have a sl_dldesc! */ if (cur_slot->sl_dldesc != NULL) { (void) dlclose(cur_slot->sl_dldesc); } /* * Each provider maintains one disabled * mechanism list for each of its slots to use. */ if (cur_slot->sl_pol_mechs != NULL) free(cur_slot->sl_pol_mechs); } if (cur_slot->sl_wfse_args != NULL) { free(cur_slot->sl_wfse_args); } (void) pthread_mutex_unlock(&cur_slot->sl_mutex); /* * Cleanup the session list. This must * happen after the mutext is unlocked * because session_delete tries to lock it * again. */ pkcs11_sessionlist_delete(cur_slot); (void) pthread_mutex_destroy(&cur_slot->sl_mutex); free(cur_slot); cur_slot = NULL; last_prov_id = prov_id; } } (void) pthread_cond_destroy(&slottable->st_wait_cond); (void) pthread_mutex_destroy(&slottable->st_start_mutex); (void) pthread_cond_destroy(&slottable->st_start_cond); free(slottable->st_slots); (void) pthread_mutex_unlock(&slottable->st_mutex); (void) pthread_mutex_destroy(&slottable->st_mutex); free(slottable); slottable = NULL; return (CKR_OK); } /* * pkcs11_is_valid_slot verifies that the slot ID passed to the * framework is valid. */ CK_RV pkcs11_is_valid_slot(CK_SLOT_ID slot_id) { if ((slot_id < slottable->st_first) || (slot_id > slottable->st_last)) { return (CKR_SLOT_ID_INVALID); } else if (slottable->st_slots[slot_id] != NULL) { return (CKR_OK); } else { return (CKR_SLOT_ID_INVALID); } } /* * pkcs11_validate_and_convert_slotid verifies whether the slot ID * passed to the framework is valid, and convert it to the * true slot ID maintained in the framework data structures * accordingly. * * This is necessary because when metaslot is enabled, the slot * providing persistent object storage is "hidden". * * The real ID is returned in the "real_slot_id" argument regardless conversion * is done or not. */ CK_RV pkcs11_validate_and_convert_slotid(CK_SLOT_ID slot_id, CK_SLOT_ID *real_slot_id) { if (!metaslot_enabled) { *real_slot_id = slot_id; } else { /* need to do conversion */ if (slot_id >= metaslot_keystore_slotid) { *real_slot_id = slot_id + 1; } else { *real_slot_id = slot_id; } } return (pkcs11_is_valid_slot(*real_slot_id)); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include "pkcs11Global.h" #include "pkcs11Conf.h" #include "pkcs11Session.h" #include "pkcs11Slot.h" /* * C_VerifyInit will verify that the session handle is valid within the * framework, that the mechanism is not disabled for the slot * associated with this session, and then redirect to the underlying * provider. Policy is only checked for C_VerifyInit, since it is * required to be called before C_Verify and C_VerifyUpdate. */ CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { CK_RV rv; pkcs11_session_t *sessp; CK_SLOT_ID slotid; /* Check for a fastpath */ if (purefastpath || policyfastpath) { if (policyfastpath && pkcs11_is_dismech(fast_slot, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } return (fast_funcs->C_VerifyInit(hSession, pMechanism, hKey)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } slotid = sessp->se_slotid; /* Make sure this is not a disabled mechanism */ if (pkcs11_is_dismech(slotid, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } /* Initialize the digest with the underlying provider */ rv = FUNCLIST(slotid)->C_VerifyInit(sessp->se_handle, pMechanism, hKey); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_Verify is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_Verify(hSession, pData, ulDataLen, pSignature, ulSignatureLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_Verify(sessp->se_handle, pData, ulDataLen, pSignature, ulSignatureLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_VerifyUpdate is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_VerifyUpdate(hSession, pPart, ulPartLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_VerifyUpdate(sessp->se_handle, pPart, ulPartLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_VerifyFinal is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_VerifyFinal(hSession, pSignature, ulSignatureLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_VerifyFinal(sessp->se_handle, pSignature, ulSignatureLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_VerifyRecoverInit will verify that the session handle is valid within * the framework, that the mechanism is not disabled for the slot * associated with this session, and then redirect to the underlying * provider. Policy is only checked for C_VerifyRecoverInit, since it is * required to be called before C_VerifyRecover. */ CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { CK_RV rv; pkcs11_session_t *sessp; CK_SLOT_ID slotid; /* Check for a fastpath */ if (purefastpath || policyfastpath) { if (policyfastpath && pkcs11_is_dismech(fast_slot, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } return (fast_funcs->C_VerifyRecoverInit(hSession, pMechanism, hKey)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } slotid = sessp->se_slotid; /* Make sure this is not a disabled mechanism */ if (pkcs11_is_dismech(slotid, pMechanism->mechanism)) { return (CKR_MECHANISM_INVALID); } /* Initialize the digest with the underlying provider */ rv = FUNCLIST(slotid)->C_VerifyRecoverInit(sessp->se_handle, pMechanism, hKey); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); } /* * C_VerifyRecover is a pure wrapper to the underlying provider. * The only argument checked is whether or not hSession is valid. */ CK_RV C_VerifyRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { CK_RV rv; pkcs11_session_t *sessp; /* Check for a fastpath */ if (purefastpath || policyfastpath) { return (fast_funcs->C_VerifyRecover(hSession, pSignature, ulSignatureLen, pData, pulDataLen)); } if (!pkcs11_initialized) { return (CKR_CRYPTOKI_NOT_INITIALIZED); } /* Obtain the session pointer */ HANDLE2SESSION(hSession, sessp, rv); if (rv != CKR_OK) { return (rv); } /* Pass data to the provider */ rv = FUNCLIST(sessp->se_slotid)->C_VerifyRecover(sessp->se_handle, pSignature, ulSignatureLen, pData, pulDataLen); /* Present consistent interface to the application */ if (rv == CKR_FUNCTION_NOT_SUPPORTED) { return (CKR_FUNCTION_FAILED); } return (rv); }