diff options
Diffstat (limited to 'security/nss/lib/ckfw/nssmkey')
-rw-r--r-- | security/nss/lib/ckfw/nssmkey/Makefile | 72 | ||||
-rw-r--r-- | security/nss/lib/ckfw/nssmkey/README | 21 | ||||
-rw-r--r-- | security/nss/lib/ckfw/nssmkey/ckmk.h | 182 | ||||
-rw-r--r-- | security/nss/lib/ckfw/nssmkey/ckmkver.c | 17 | ||||
-rw-r--r-- | security/nss/lib/ckfw/nssmkey/config.mk | 24 | ||||
-rw-r--r-- | security/nss/lib/ckfw/nssmkey/manchor.c | 17 | ||||
-rw-r--r-- | security/nss/lib/ckfw/nssmkey/manifest.mn | 33 | ||||
-rw-r--r-- | security/nss/lib/ckfw/nssmkey/mconstants.c | 61 | ||||
-rw-r--r-- | security/nss/lib/ckfw/nssmkey/mfind.c | 352 | ||||
-rw-r--r-- | security/nss/lib/ckfw/nssmkey/minst.c | 97 | ||||
-rw-r--r-- | security/nss/lib/ckfw/nssmkey/mobject.c | 1861 | ||||
-rw-r--r-- | security/nss/lib/ckfw/nssmkey/mrsa.c | 479 | ||||
-rw-r--r-- | security/nss/lib/ckfw/nssmkey/msession.c | 87 | ||||
-rw-r--r-- | security/nss/lib/ckfw/nssmkey/mslot.c | 81 | ||||
-rw-r--r-- | security/nss/lib/ckfw/nssmkey/mtoken.c | 184 | ||||
-rw-r--r-- | security/nss/lib/ckfw/nssmkey/nssmkey.def | 26 | ||||
-rw-r--r-- | security/nss/lib/ckfw/nssmkey/nssmkey.h | 41 | ||||
-rw-r--r-- | security/nss/lib/ckfw/nssmkey/staticobj.c | 36 |
18 files changed, 3671 insertions, 0 deletions
diff --git a/security/nss/lib/ckfw/nssmkey/Makefile b/security/nss/lib/ckfw/nssmkey/Makefile new file mode 100644 index 000000000..e630e84b0 --- /dev/null +++ b/security/nss/lib/ckfw/nssmkey/Makefile @@ -0,0 +1,72 @@ +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +include manifest.mn +include $(CORE_DEPTH)/coreconf/config.mk +include config.mk + +EXTRA_LIBS = \ + $(DIST)/lib/$(LIB_PREFIX)nssckfw.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)secutil.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)nssb.$(LIB_SUFFIX) \ + $(NULL) + +# can't do this in manifest.mn because OS_TARGET isn't defined there. +ifeq (,$(filter-out WIN%,$(OS_TARGET))) + +ifdef NS_USE_GCC +EXTRA_LIBS += \ + -L$(NSPR_LIB_DIR) \ + -lplc4 \ + -lplds4 \ + -lnspr4 \ + $(NULL) +else +EXTRA_SHARED_LIBS += \ + $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plc4.lib \ + $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plds4.lib \ + $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)nspr4.lib \ + $(NULL) +endif # NS_USE_GCC +else + +EXTRA_LIBS += \ + -L$(NSPR_LIB_DIR) \ + -lplc4 \ + -lplds4 \ + -lnspr4 \ + -framework Security \ + -framework CoreServices \ + $(NULL) +endif + + +include $(CORE_DEPTH)/coreconf/rules.mk + +# Generate certdata.c. +generate: + perl certdata.perl < certdata.txt + +# This'll need some help from a build person. + + +ifeq ($(OS_TARGET)$(OS_RELEASE), AIX4.1) +DSO_LDOPTS = -bM:SRE -bh:4 -bnoentry +EXTRA_DSO_LDOPTS = -lc +MKSHLIB = xlC $(DSO_LDOPTS) + +$(SHARED_LIBRARY): $(OBJS) + @$(MAKE_OBJDIR) + rm -f $@ + $(MKSHLIB) -o $@ $(OBJS) $(EXTRA_LIBS) $(EXTRA_DSO_LDOPTS) + chmod +x $@ + +endif + +ifeq ($(OS_TARGET)$(OS_RELEASE), AIX4.2) +LD += -G +endif + + diff --git a/security/nss/lib/ckfw/nssmkey/README b/security/nss/lib/ckfw/nssmkey/README new file mode 100644 index 000000000..c060d9c3c --- /dev/null +++ b/security/nss/lib/ckfw/nssmkey/README @@ -0,0 +1,21 @@ +This Cryptoki module provides acces to certs and keys stored in +Macintosh key Ring. + +- It does not yet export PKCS #12 keys. To get this to work should be + implemented using exporting the key object in PKCS #8 wrapped format. + PSM work needs to happen before this can be completed. +- It does not import or export CA Root trust from the mac keychain. +- It does not handle S/MIME objects (pkcs #7 in mac keychain terms?). +- The AuthRoots don't show up on the default list. +- Only RSA keys are supported currently. + +There are a number of things that have not been tested that other PKCS #11 +apps may need: +- reading Modulus and Public Exponents from private keys and public keys. +- storing public keys. +- setting attributes other than CKA_ID and CKA_LABEL. + +Other TODOs: +- Check for and plug memory leaks. +- Need to map mac errors into something more intellegible than + CKR_GENERAL_ERROR. diff --git a/security/nss/lib/ckfw/nssmkey/ckmk.h b/security/nss/lib/ckfw/nssmkey/ckmk.h new file mode 100644 index 000000000..4f3ab82d7 --- /dev/null +++ b/security/nss/lib/ckfw/nssmkey/ckmk.h @@ -0,0 +1,182 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef CKMK_H +#define CKMK_H 1 + +#include <Security/SecKeychainSearch.h> +#include <Security/SecKeychainItem.h> +#include <Security/SecKeychain.h> +#include <Security/cssmtype.h> +#include <Security/cssmapi.h> +#include <Security/SecKey.h> +#include <Security/SecCertificate.h> + +#define NTO + +#include "nssckmdt.h" +#include "nssckfw.h" +/* + * I'm including this for access to the arena functions. + * Looks like we should publish that API. + */ +#ifndef BASE_H +#include "base.h" +#endif /* BASE_H */ +/* + * This is where the Netscape extensions live, at least for now. + */ +#ifndef CKT_H +#include "ckt.h" +#endif /* CKT_H */ + +/* + * statically defined raw objects. Allows us to data description objects + * to this PKCS #11 module. + */ +struct ckmkRawObjectStr { + CK_ULONG n; + const CK_ATTRIBUTE_TYPE *types; + const NSSItem *items; +}; +typedef struct ckmkRawObjectStr ckmkRawObject; + +/* + * Key/Cert Items + */ +struct ckmkItemObjectStr { + SecKeychainItemRef itemRef; + SecItemClass itemClass; + PRBool hasID; + NSSItem modify; + NSSItem private; + NSSItem encrypt; + NSSItem decrypt; + NSSItem derive; + NSSItem sign; + NSSItem signRecover; + NSSItem verify; + NSSItem verifyRecover; + NSSItem wrap; + NSSItem unwrap; + NSSItem label; + NSSItem subject; + NSSItem issuer; + NSSItem serial; + NSSItem derCert; + NSSItem id; + NSSItem modulus; + NSSItem exponent; + NSSItem privateExponent; + NSSItem prime1; + NSSItem prime2; + NSSItem exponent1; + NSSItem exponent2; + NSSItem coefficient; +}; +typedef struct ckmkItemObjectStr ckmkItemObject; + +typedef enum { + ckmkRaw, + ckmkItem, +} ckmkObjectType; + +/* + * all the various types of objects are abstracted away in cobject and + * cfind as ckmkInternalObjects. + */ +struct ckmkInternalObjectStr { + ckmkObjectType type; + union { + ckmkRawObject raw; + ckmkItemObject item; + } u; + CK_OBJECT_CLASS objClass; + NSSItem hashKey; + unsigned char hashKeyData[128]; + NSSCKMDObject mdObject; +}; +typedef struct ckmkInternalObjectStr ckmkInternalObject; + +/* our raw object data array */ +NSS_EXTERN_DATA ckmkInternalObject nss_ckmk_data[]; +NSS_EXTERN_DATA const PRUint32 nss_ckmk_nObjects; + +NSS_EXTERN_DATA const CK_VERSION nss_ckmk_CryptokiVersion; +NSS_EXTERN_DATA const NSSUTF8 *nss_ckmk_ManufacturerID; +NSS_EXTERN_DATA const NSSUTF8 *nss_ckmk_LibraryDescription; +NSS_EXTERN_DATA const CK_VERSION nss_ckmk_LibraryVersion; +NSS_EXTERN_DATA const NSSUTF8 *nss_ckmk_SlotDescription; +NSS_EXTERN_DATA const CK_VERSION nss_ckmk_HardwareVersion; +NSS_EXTERN_DATA const CK_VERSION nss_ckmk_FirmwareVersion; +NSS_EXTERN_DATA const NSSUTF8 *nss_ckmk_TokenLabel; +NSS_EXTERN_DATA const NSSUTF8 *nss_ckmk_TokenModel; +NSS_EXTERN_DATA const NSSUTF8 *nss_ckmk_TokenSerialNumber; + +NSS_EXTERN_DATA const NSSCKMDInstance nss_ckmk_mdInstance; +NSS_EXTERN_DATA const NSSCKMDSlot nss_ckmk_mdSlot; +NSS_EXTERN_DATA const NSSCKMDToken nss_ckmk_mdToken; +NSS_EXTERN_DATA const NSSCKMDMechanism nss_ckmk_mdMechanismRSA; + +NSS_EXTERN NSSCKMDSession * +nss_ckmk_CreateSession( + NSSCKFWSession *fwSession, + CK_RV *pError); + +NSS_EXTERN NSSCKMDFindObjects * +nss_ckmk_FindObjectsInit( + NSSCKFWSession *fwSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + CK_RV *pError); + +/* + * Object Utilities + */ +NSS_EXTERN NSSCKMDObject * +nss_ckmk_CreateMDObject( + NSSArena *arena, + ckmkInternalObject *io, + CK_RV *pError); + +NSS_EXTERN NSSCKMDObject * +nss_ckmk_CreateObject( + NSSCKFWSession *fwSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + CK_RV *pError); + +NSS_EXTERN const NSSItem * +nss_ckmk_FetchAttribute( + ckmkInternalObject *io, + CK_ATTRIBUTE_TYPE type, + CK_RV *pError); + +NSS_EXTERN void +nss_ckmk_DestroyInternalObject( + ckmkInternalObject *io); + +unsigned char * +nss_ckmk_DERUnwrap( + unsigned char *src, + int size, + int *outSize, + unsigned char **next); + +CK_ULONG +nss_ckmk_GetULongAttribute( + CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *template, + CK_ULONG templateSize, + CK_RV *pError); + +#define NSS_CKMK_ARRAY_SIZE(x) ((sizeof(x)) / (sizeof((x)[0]))) + +#ifdef DEBUG +#define CKMK_MACERR(str, err) cssmPerror(str, err) +#else +#define CKMK_MACERR(str, err) +#endif + +#endif diff --git a/security/nss/lib/ckfw/nssmkey/ckmkver.c b/security/nss/lib/ckfw/nssmkey/ckmkver.c new file mode 100644 index 000000000..2b99f1e22 --- /dev/null +++ b/security/nss/lib/ckfw/nssmkey/ckmkver.c @@ -0,0 +1,17 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* Library identity and versioning */ + +#include "nssmkey.h" + +#if defined(DEBUG) +#define _DEBUG_STRING " (debug)" +#else +#define _DEBUG_STRING "" +#endif + +/* + * Version information + */ +const char __nss_ckmk_version[] = "Version: NSS Access to the MAC OS X Key Ring " NSS_CKMK_LIBRARY_VERSION _DEBUG_STRING; diff --git a/security/nss/lib/ckfw/nssmkey/config.mk b/security/nss/lib/ckfw/nssmkey/config.mk new file mode 100644 index 000000000..709691067 --- /dev/null +++ b/security/nss/lib/ckfw/nssmkey/config.mk @@ -0,0 +1,24 @@ +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +ifdef BUILD_IDG +DEFINES += -DNSSDEBUG +endif + +ifdef NS_USE_CKFW_TRACE +DEFINES += -DTRACE +endif + +# +# Override TARGETS variable so that only static libraries +# are specifed as dependencies within rules.mk. +# + +TARGETS = $(LIBRARY) +SHARED_LIBRARY = +IMPORT_LIBRARY = +PROGRAM = + + diff --git a/security/nss/lib/ckfw/nssmkey/manchor.c b/security/nss/lib/ckfw/nssmkey/manchor.c new file mode 100644 index 000000000..3b8bc2dbb --- /dev/null +++ b/security/nss/lib/ckfw/nssmkey/manchor.c @@ -0,0 +1,17 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * nssmkey/manchor.c + * + * This file "anchors" the actual cryptoki entry points in this module's + * shared library, which is required for dynamic loading. See the + * comments in nssck.api for more information. + */ + +#include "ckmk.h" + +#define MODULE_NAME ckmk +#define INSTANCE_NAME (NSSCKMDInstance *)&nss_ckmk_mdInstance +#include "nssck.api" diff --git a/security/nss/lib/ckfw/nssmkey/manifest.mn b/security/nss/lib/ckfw/nssmkey/manifest.mn new file mode 100644 index 000000000..036d9bc3f --- /dev/null +++ b/security/nss/lib/ckfw/nssmkey/manifest.mn @@ -0,0 +1,33 @@ +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +CORE_DEPTH = ../../../.. + +MODULE = nss +MAPFILE = $(OBJDIR)/nssmkey.def + +EXPORTS = \ + nssmkey.h \ + $(NULL) + +CSRCS = \ + manchor.c \ + mconstants.c \ + mfind.c \ + minst.c \ + mobject.c \ + mrsa.c \ + msession.c \ + mslot.c \ + mtoken.c \ + ckmkver.c \ + staticobj.c \ + $(NULL) + +REQUIRES = nspr + +LIBRARY_NAME = nssmkey + +#EXTRA_SHARED_LIBS = -L$(DIST)/lib -lnssckfw -lnssb -lplc4 -lplds4 diff --git a/security/nss/lib/ckfw/nssmkey/mconstants.c b/security/nss/lib/ckfw/nssmkey/mconstants.c new file mode 100644 index 000000000..c26298ada --- /dev/null +++ b/security/nss/lib/ckfw/nssmkey/mconstants.c @@ -0,0 +1,61 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * nssmkey/constants.c + * + * Identification and other constants, all collected here in one place. + */ + +#ifndef NSSBASET_H +#include "nssbaset.h" +#endif /* NSSBASET_H */ + +#ifndef NSSCKT_H +#include "nssckt.h" +#endif /* NSSCKT_H */ + +#include "nssmkey.h" + +NSS_IMPLEMENT_DATA const CK_VERSION + nss_ckmk_CryptokiVersion = { + NSS_CKMK_CRYPTOKI_VERSION_MAJOR, + NSS_CKMK_CRYPTOKI_VERSION_MINOR + }; + +NSS_IMPLEMENT_DATA const NSSUTF8 * + nss_ckmk_ManufacturerID = (NSSUTF8 *)"Mozilla Foundation"; + +NSS_IMPLEMENT_DATA const NSSUTF8 * + nss_ckmk_LibraryDescription = (NSSUTF8 *)"NSS Access to Mac OS X Key Ring"; + +NSS_IMPLEMENT_DATA const CK_VERSION + nss_ckmk_LibraryVersion = { + NSS_CKMK_LIBRARY_VERSION_MAJOR, + NSS_CKMK_LIBRARY_VERSION_MINOR + }; + +NSS_IMPLEMENT_DATA const NSSUTF8 * + nss_ckmk_SlotDescription = (NSSUTF8 *)"Mac OS X Key Ring"; + +NSS_IMPLEMENT_DATA const CK_VERSION + nss_ckmk_HardwareVersion = { + NSS_CKMK_HARDWARE_VERSION_MAJOR, + NSS_CKMK_HARDWARE_VERSION_MINOR + }; + +NSS_IMPLEMENT_DATA const CK_VERSION + nss_ckmk_FirmwareVersion = { + NSS_CKMK_FIRMWARE_VERSION_MAJOR, + NSS_CKMK_FIRMWARE_VERSION_MINOR + }; + +NSS_IMPLEMENT_DATA const NSSUTF8 * + nss_ckmk_TokenLabel = (NSSUTF8 *)"Mac OS X Key Ring"; + +NSS_IMPLEMENT_DATA const NSSUTF8 * + nss_ckmk_TokenModel = (NSSUTF8 *)"1"; + +NSS_IMPLEMENT_DATA const NSSUTF8 * + nss_ckmk_TokenSerialNumber = (NSSUTF8 *)"1"; diff --git a/security/nss/lib/ckfw/nssmkey/mfind.c b/security/nss/lib/ckfw/nssmkey/mfind.c new file mode 100644 index 000000000..d193a8de7 --- /dev/null +++ b/security/nss/lib/ckfw/nssmkey/mfind.c @@ -0,0 +1,352 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef CKMK_H +#include "ckmk.h" +#endif /* CKMK_H */ + +/* + * nssmkey/mfind.c + * + * This file implements the NSSCKMDFindObjects object for the + * "nssmkey" cryptoki module. + */ + +struct ckmkFOStr { + NSSArena *arena; + CK_ULONG n; + CK_ULONG i; + ckmkInternalObject **objs; +}; + +static void +ckmk_mdFindObjects_Final( + NSSCKMDFindObjects *mdFindObjects, + NSSCKFWFindObjects *fwFindObjects, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + struct ckmkFOStr *fo = (struct ckmkFOStr *)mdFindObjects->etc; + NSSArena *arena = fo->arena; + PRUint32 i; + + /* walk down an free the unused 'objs' */ + for (i = fo->i; i < fo->n; i++) { + nss_ckmk_DestroyInternalObject(fo->objs[i]); + } + + nss_ZFreeIf(fo->objs); + nss_ZFreeIf(fo); + nss_ZFreeIf(mdFindObjects); + if ((NSSArena *)NULL != arena) { + NSSArena_Destroy(arena); + } + + return; +} + +static NSSCKMDObject * +ckmk_mdFindObjects_Next( + NSSCKMDFindObjects *mdFindObjects, + NSSCKFWFindObjects *fwFindObjects, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + NSSArena *arena, + CK_RV *pError) +{ + struct ckmkFOStr *fo = (struct ckmkFOStr *)mdFindObjects->etc; + ckmkInternalObject *io; + + if (fo->i == fo->n) { + *pError = CKR_OK; + return (NSSCKMDObject *)NULL; + } + + io = fo->objs[fo->i]; + fo->i++; + + return nss_ckmk_CreateMDObject(arena, io, pError); +} + +static CK_BBOOL +ckmk_attrmatch( + CK_ATTRIBUTE_PTR a, + ckmkInternalObject *o) +{ + PRBool prb; + const NSSItem *b; + CK_RV error; + + b = nss_ckmk_FetchAttribute(o, a->type, &error); + if (b == NULL) { + return CK_FALSE; + } + + if (a->ulValueLen != b->size) { + /* match a decoded serial number */ + if ((a->type == CKA_SERIAL_NUMBER) && (a->ulValueLen < b->size)) { + int len; + unsigned char *data; + + data = nss_ckmk_DERUnwrap(b->data, b->size, &len, NULL); + if ((len == a->ulValueLen) && + nsslibc_memequal(a->pValue, data, len, (PRStatus *)NULL)) { + return CK_TRUE; + } + } + return CK_FALSE; + } + + prb = nsslibc_memequal(a->pValue, b->data, b->size, (PRStatus *)NULL); + + if (PR_TRUE == prb) { + return CK_TRUE; + } else { + return CK_FALSE; + } +} + +static CK_BBOOL +ckmk_match( + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + ckmkInternalObject *o) +{ + CK_ULONG i; + + for (i = 0; i < ulAttributeCount; i++) { + if (CK_FALSE == ckmk_attrmatch(&pTemplate[i], o)) { + return CK_FALSE; + } + } + + /* Every attribute passed */ + return CK_TRUE; +} + +#define CKMK_ITEM_CHUNK 20 + +#define PUT_OBJECT(obj, err, size, count, list) \ + { \ + if (count >= size) { \ + (list) = (list) ? nss_ZREALLOCARRAY(list, ckmkInternalObject *, \ + ((size) + \ + CKMK_ITEM_CHUNK)) \ + : nss_ZNEWARRAY(NULL, ckmkInternalObject *, \ + ((size) + \ + CKMK_ITEM_CHUNK)); \ + if ((ckmkInternalObject **)NULL == list) { \ + err = CKR_HOST_MEMORY; \ + goto loser; \ + } \ + (size) += CKMK_ITEM_CHUNK; \ + } \ + (list)[count] = (obj); \ + count++; \ + } + +/* find all the certs that represent the appropriate object (cert, priv key, or + * pub key) in the cert store. + */ +static PRUint32 +collect_class( + CK_OBJECT_CLASS objClass, + SecItemClass itemClass, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + ckmkInternalObject ***listp, + PRUint32 *sizep, + PRUint32 count, + CK_RV *pError) +{ + ckmkInternalObject *next = NULL; + SecKeychainSearchRef searchRef = 0; + SecKeychainItemRef itemRef = 0; + OSStatus error; + + /* future, build the attribute list based on the template + * so we can refine the search */ + error = SecKeychainSearchCreateFromAttributes( + NULL, itemClass, NULL, &searchRef); + + while (noErr == SecKeychainSearchCopyNext(searchRef, &itemRef)) { + /* if we don't have an internal object structure, get one */ + if ((ckmkInternalObject *)NULL == next) { + next = nss_ZNEW(NULL, ckmkInternalObject); + if ((ckmkInternalObject *)NULL == next) { + *pError = CKR_HOST_MEMORY; + goto loser; + } + } + /* fill in the relevant object data */ + next->type = ckmkItem; + next->objClass = objClass; + next->u.item.itemRef = itemRef; + next->u.item.itemClass = itemClass; + + /* see if this is one of the objects we are looking for */ + if (CK_TRUE == ckmk_match(pTemplate, ulAttributeCount, next)) { + /* yes, put it on the list */ + PUT_OBJECT(next, *pError, *sizep, count, *listp); + next = NULL; /* this one is on the list, need to allocate a new one now */ + } else { + /* no , release the current item and clear out the structure for reuse */ + CFRelease(itemRef); + /* don't cache the values we just loaded */ + nsslibc_memset(next, 0, sizeof(*next)); + } + } +loser: + if (searchRef) { + CFRelease(searchRef); + } + nss_ZFreeIf(next); + return count; +} + +static PRUint32 +collect_objects( + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + ckmkInternalObject ***listp, + CK_RV *pError) +{ + PRUint32 i; + PRUint32 count = 0; + PRUint32 size = 0; + CK_OBJECT_CLASS objClass; + + /* + * first handle the static build in objects (if any) + */ + for (i = 0; i < nss_ckmk_nObjects; i++) { + ckmkInternalObject *o = (ckmkInternalObject *)&nss_ckmk_data[i]; + + if (CK_TRUE == ckmk_match(pTemplate, ulAttributeCount, o)) { + PUT_OBJECT(o, *pError, size, count, *listp); + } + } + + /* + * now handle the various object types + */ + objClass = nss_ckmk_GetULongAttribute(CKA_CLASS, + pTemplate, ulAttributeCount, pError); + if (CKR_OK != *pError) { + objClass = CK_INVALID_HANDLE; + } + *pError = CKR_OK; + switch (objClass) { + case CKO_CERTIFICATE: + count = collect_class(objClass, kSecCertificateItemClass, + pTemplate, ulAttributeCount, listp, + &size, count, pError); + break; + case CKO_PUBLIC_KEY: + count = collect_class(objClass, CSSM_DL_DB_RECORD_PUBLIC_KEY, + pTemplate, ulAttributeCount, listp, + &size, count, pError); + break; + case CKO_PRIVATE_KEY: + count = collect_class(objClass, CSSM_DL_DB_RECORD_PRIVATE_KEY, + pTemplate, ulAttributeCount, listp, + &size, count, pError); + break; + /* all of them */ + case CK_INVALID_HANDLE: + count = collect_class(CKO_CERTIFICATE, kSecCertificateItemClass, + pTemplate, ulAttributeCount, listp, + &size, count, pError); + count = collect_class(CKO_PUBLIC_KEY, CSSM_DL_DB_RECORD_PUBLIC_KEY, + pTemplate, ulAttributeCount, listp, + &size, count, pError); + count = collect_class(CKO_PUBLIC_KEY, CSSM_DL_DB_RECORD_PRIVATE_KEY, + pTemplate, ulAttributeCount, listp, + &size, count, pError); + break; + default: + break; + } + if (CKR_OK != *pError) { + goto loser; + } + + return count; +loser: + nss_ZFreeIf(*listp); + return 0; +} + +NSS_IMPLEMENT NSSCKMDFindObjects * +nss_ckmk_FindObjectsInit( + NSSCKFWSession *fwSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + CK_RV *pError) +{ + /* This could be made more efficient. I'm rather rushed. */ + NSSArena *arena; + NSSCKMDFindObjects *rv = (NSSCKMDFindObjects *)NULL; + struct ckmkFOStr *fo = (struct ckmkFOStr *)NULL; + ckmkInternalObject **temp = (ckmkInternalObject **)NULL; + + arena = NSSArena_Create(); + if ((NSSArena *)NULL == arena) { + goto loser; + } + + rv = nss_ZNEW(arena, NSSCKMDFindObjects); + if ((NSSCKMDFindObjects *)NULL == rv) { + *pError = CKR_HOST_MEMORY; + goto loser; + } + + fo = nss_ZNEW(arena, struct ckmkFOStr); + if ((struct ckmkFOStr *)NULL == fo) { + *pError = CKR_HOST_MEMORY; + goto loser; + } + + fo->arena = arena; + /* fo->n and fo->i are already zero */ + + rv->etc = (void *)fo; + rv->Final = ckmk_mdFindObjects_Final; + rv->Next = ckmk_mdFindObjects_Next; + rv->null = (void *)NULL; + + fo->n = collect_objects(pTemplate, ulAttributeCount, &temp, pError); + if (*pError != CKR_OK) { + goto loser; + } + + fo->objs = nss_ZNEWARRAY(arena, ckmkInternalObject *, fo->n); + if ((ckmkInternalObject **)NULL == fo->objs) { + *pError = CKR_HOST_MEMORY; + goto loser; + } + + (void)nsslibc_memcpy(fo->objs, temp, sizeof(ckmkInternalObject *) * fo->n); + nss_ZFreeIf(temp); + temp = (ckmkInternalObject **)NULL; + + return rv; + +loser: + nss_ZFreeIf(temp); + nss_ZFreeIf(fo); + nss_ZFreeIf(rv); + if ((NSSArena *)NULL != arena) { + NSSArena_Destroy(arena); + } + return (NSSCKMDFindObjects *)NULL; +} diff --git a/security/nss/lib/ckfw/nssmkey/minst.c b/security/nss/lib/ckfw/nssmkey/minst.c new file mode 100644 index 000000000..fcb96c652 --- /dev/null +++ b/security/nss/lib/ckfw/nssmkey/minst.c @@ -0,0 +1,97 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ckmk.h" + +/* + * nssmkey/minstance.c + * + * This file implements the NSSCKMDInstance object for the + * "nssmkey" cryptoki module. + */ + +/* + * NSSCKMDInstance methods + */ + +static CK_ULONG +ckmk_mdInstance_GetNSlots( + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (CK_ULONG)1; +} + +static CK_VERSION +ckmk_mdInstance_GetCryptokiVersion( + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return nss_ckmk_CryptokiVersion; +} + +static NSSUTF8 * +ckmk_mdInstance_GetManufacturerID( + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (NSSUTF8 *)nss_ckmk_ManufacturerID; +} + +static NSSUTF8 * +ckmk_mdInstance_GetLibraryDescription( + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (NSSUTF8 *)nss_ckmk_LibraryDescription; +} + +static CK_VERSION +ckmk_mdInstance_GetLibraryVersion( + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return nss_ckmk_LibraryVersion; +} + +static CK_RV +ckmk_mdInstance_GetSlots( + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + NSSCKMDSlot *slots[]) +{ + slots[0] = (NSSCKMDSlot *)&nss_ckmk_mdSlot; + return CKR_OK; +} + +static CK_BBOOL +ckmk_mdInstance_ModuleHandlesSessionObjects( + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + /* we don't want to allow any session object creation, at least + * until we can investigate whether or not we can use those objects + */ + return CK_TRUE; +} + +NSS_IMPLEMENT_DATA const NSSCKMDInstance + nss_ckmk_mdInstance = { + (void *)NULL, /* etc */ + NULL, /* Initialize */ + NULL, /* Finalize */ + ckmk_mdInstance_GetNSlots, + ckmk_mdInstance_GetCryptokiVersion, + ckmk_mdInstance_GetManufacturerID, + ckmk_mdInstance_GetLibraryDescription, + ckmk_mdInstance_GetLibraryVersion, + ckmk_mdInstance_ModuleHandlesSessionObjects, + /*NULL, /* HandleSessionObjects */ + ckmk_mdInstance_GetSlots, + NULL, /* WaitForSlotEvent */ + (void *)NULL /* null terminator */ + }; diff --git a/security/nss/lib/ckfw/nssmkey/mobject.c b/security/nss/lib/ckfw/nssmkey/mobject.c new file mode 100644 index 000000000..b19a8fdbd --- /dev/null +++ b/security/nss/lib/ckfw/nssmkey/mobject.c @@ -0,0 +1,1861 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ckmk.h" +#include "nssbase.h" + +#include "secdert.h" /* for DER_INTEGER */ +#include "string.h" + +/* asn1 encoder (to build pkcs#8 blobs) */ +#include <seccomon.h> +#include <secitem.h> +#include <blapit.h> +#include <secoid.h> +#include <secasn1.h> + +/* for importing the keys */ +#include <CoreFoundation/CoreFoundation.h> +#include <security/SecImportExport.h> + +/* + * nssmkey/mobject.c + * + * This file implements the NSSCKMDObject object for the + * "nssmkey" cryptoki module. + */ + +const CK_ATTRIBUTE_TYPE certAttrs[] = { + CKA_CLASS, + CKA_TOKEN, + CKA_PRIVATE, + CKA_MODIFIABLE, + CKA_LABEL, + CKA_CERTIFICATE_TYPE, + CKA_SUBJECT, + CKA_ISSUER, + CKA_SERIAL_NUMBER, + CKA_VALUE +}; +const PRUint32 certAttrsCount = NSS_CKMK_ARRAY_SIZE(certAttrs); + +/* private keys, for now only support RSA */ +const CK_ATTRIBUTE_TYPE privKeyAttrs[] = { + CKA_CLASS, + CKA_TOKEN, + CKA_PRIVATE, + CKA_MODIFIABLE, + CKA_LABEL, + CKA_KEY_TYPE, + CKA_DERIVE, + CKA_LOCAL, + CKA_SUBJECT, + CKA_SENSITIVE, + CKA_DECRYPT, + CKA_SIGN, + CKA_SIGN_RECOVER, + CKA_UNWRAP, + CKA_EXTRACTABLE, + CKA_ALWAYS_SENSITIVE, + CKA_NEVER_EXTRACTABLE, + CKA_MODULUS, + CKA_PUBLIC_EXPONENT, +}; +const PRUint32 privKeyAttrsCount = NSS_CKMK_ARRAY_SIZE(privKeyAttrs); + +/* public keys, for now only support RSA */ +const CK_ATTRIBUTE_TYPE pubKeyAttrs[] = { + CKA_CLASS, + CKA_TOKEN, + CKA_PRIVATE, + CKA_MODIFIABLE, + CKA_LABEL, + CKA_KEY_TYPE, + CKA_DERIVE, + CKA_LOCAL, + CKA_SUBJECT, + CKA_ENCRYPT, + CKA_VERIFY, + CKA_VERIFY_RECOVER, + CKA_WRAP, + CKA_MODULUS, + CKA_PUBLIC_EXPONENT, +}; +const PRUint32 pubKeyAttrsCount = NSS_CKMK_ARRAY_SIZE(pubKeyAttrs); +static const CK_BBOOL ck_true = CK_TRUE; +static const CK_BBOOL ck_false = CK_FALSE; +static const CK_CERTIFICATE_TYPE ckc_x509 = CKC_X_509; +static const CK_KEY_TYPE ckk_rsa = CKK_RSA; +static const CK_OBJECT_CLASS cko_certificate = CKO_CERTIFICATE; +static const CK_OBJECT_CLASS cko_private_key = CKO_PRIVATE_KEY; +static const CK_OBJECT_CLASS cko_public_key = CKO_PUBLIC_KEY; +static const NSSItem ckmk_trueItem = { + (void *)&ck_true, (PRUint32)sizeof(CK_BBOOL) +}; +static const NSSItem ckmk_falseItem = { + (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL) +}; +static const NSSItem ckmk_x509Item = { + (void *)&ckc_x509, (PRUint32)sizeof(CK_CERTIFICATE_TYPE) +}; +static const NSSItem ckmk_rsaItem = { + (void *)&ckk_rsa, (PRUint32)sizeof(CK_KEY_TYPE) +}; +static const NSSItem ckmk_certClassItem = { + (void *)&cko_certificate, (PRUint32)sizeof(CK_OBJECT_CLASS) +}; +static const NSSItem ckmk_privKeyClassItem = { + (void *)&cko_private_key, (PRUint32)sizeof(CK_OBJECT_CLASS) +}; +static const NSSItem ckmk_pubKeyClassItem = { + (void *)&cko_public_key, (PRUint32)sizeof(CK_OBJECT_CLASS) +}; +static const NSSItem ckmk_emptyItem = { + (void *)&ck_true, 0 +}; + +/* + * these are utilities. The chould be moved to a new utilities file. + */ +#ifdef DEBUG +static void +itemdump(char *str, void *data, int size, CK_RV error) +{ + unsigned char *ptr = (unsigned char *)data; + int i; + fprintf(stderr, str); + for (i = 0; i < size; i++) { + fprintf(stderr, "%02x ", (unsigned int)ptr[i]); + } + fprintf(stderr, " (error = %d)\n", (int)error); +} +#endif + +/* + * unwrap a single DER value + * now that we have util linked in, we should probably use + * the ANS1_Decoder for this work... + */ +unsigned char * +nss_ckmk_DERUnwrap( + unsigned char *src, + int size, + int *outSize, + unsigned char **next) +{ + unsigned char *start = src; + unsigned int len = 0; + + /* initialize error condition return values */ + *outSize = 0; + if (next) { + *next = src; + } + + if (size < 2) { + return start; + } + src++; /* skip the tag -- should check it against an expected value! */ + len = (unsigned)*src++; + if (len & 0x80) { + int count = len & 0x7f; + len = 0; + + if (count + 2 > size) { + return start; + } + while (count-- > 0) { + len = (len << 8) | (unsigned)*src++; + } + } + if (len + (src - start) > (unsigned int)size) { + return start; + } + if (next) { + *next = src + len; + } + *outSize = len; + + return src; +} + +/* + * get an attribute from a template. Value is returned in NSS item. + * data for the item is owned by the template. + */ +CK_RV +nss_ckmk_GetAttribute( + CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *template, + CK_ULONG templateSize, + NSSItem *item) +{ + CK_ULONG i; + + for (i = 0; i < templateSize; i++) { + if (template[i].type == type) { + item->data = template[i].pValue; + item->size = template[i].ulValueLen; + return CKR_OK; + } + } + return CKR_TEMPLATE_INCOMPLETE; +} + +/* + * get an attribute which is type CK_ULONG. + */ +CK_ULONG +nss_ckmk_GetULongAttribute( + CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *template, + CK_ULONG templateSize, + CK_RV *pError) +{ + NSSItem item; + + *pError = nss_ckmk_GetAttribute(type, template, templateSize, &item); + if (CKR_OK != *pError) { + return (CK_ULONG)0; + } + if (item.size != sizeof(CK_ULONG)) { + *pError = CKR_ATTRIBUTE_VALUE_INVALID; + return (CK_ULONG)0; + } + return *(CK_ULONG *)item.data; +} + +/* + * get an attribute which is type CK_BBOOL. + */ +CK_BBOOL +nss_ckmk_GetBoolAttribute( + CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *template, + CK_ULONG templateSize, + CK_BBOOL defaultBool) +{ + NSSItem item; + CK_RV error; + + error = nss_ckmk_GetAttribute(type, template, templateSize, &item); + if (CKR_OK != error) { + return defaultBool; + } + if (item.size != sizeof(CK_BBOOL)) { + return defaultBool; + } + return *(CK_BBOOL *)item.data; +} + +/* + * get an attribute as a NULL terminated string. Caller is responsible to + * free the string. + */ +char * +nss_ckmk_GetStringAttribute( + CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *template, + CK_ULONG templateSize, + CK_RV *pError) +{ + NSSItem item; + char *str; + + /* get the attribute */ + *pError = nss_ckmk_GetAttribute(type, template, templateSize, &item); + if (CKR_OK != *pError) { + return (char *)NULL; + } + /* make sure it is null terminated */ + str = nss_ZNEWARRAY(NULL, char, item.size + 1); + if ((char *)NULL == str) { + *pError = CKR_HOST_MEMORY; + return (char *)NULL; + } + + nsslibc_memcpy(str, item.data, item.size); + str[item.size] = 0; + + return str; +} + +/* + * Apple doesn't seem to have a public interface to the DER encoder, + * wip out a quick one for integers only (anything more complicated, + * we should use one of the 3 in lib/util). -- especially since we + * now link with it. + */ +static CK_RV +ckmk_encodeInt(NSSItem *dest, void *src, int srcLen) +{ + int dataLen = srcLen; + int lenLen = 1; + int encLen; + int isSigned = 0; + int offset = 0; + unsigned char *data = NULL; + int i; + + if (*(unsigned char *)src & 0x80) { + dataLen++; + isSigned = 1; + } + + /* calculate the length of the length specifier */ + /* (NOTE: destroys dataLen value) */ + if (dataLen > 0x7f) { + do { + lenLen++; + dataLen >>= 8; + } while (dataLen); + } + + /* calculate our total length */ + dataLen = isSigned + srcLen; + encLen = 1 + lenLen + dataLen; + data = nss_ZNEWARRAY(NULL, unsigned char, encLen); + if ((unsigned char *)NULL == data) { + return CKR_HOST_MEMORY; + } + data[0] = DER_INTEGER; + if (1 == lenLen) { + data[1] = dataLen; + } else { + data[1] = 0x80 + lenLen; + for (i = 0; i < lenLen; i++) { + data[i + 1] = ((dataLen >> ((lenLen - + i - 1) * + 8)) & + 0xff); + } + } + offset = lenLen + 1; + + if (isSigned) { + data[offset++] = 0; + } + nsslibc_memcpy(&data[offset], src, srcLen); + dest->data = data; + dest->size = encLen; + return CKR_OK; +} + +/* + * Get a Keyring attribute. If content is set to true, then we get the + * content, not the attribute. + */ +static CK_RV +ckmk_GetCommonAttribute( + ckmkInternalObject *io, + SecItemAttr itemAttr, + PRBool content, + NSSItem *item, + char *dbString) +{ + SecKeychainAttributeList *attrList = NULL; + SecKeychainAttributeInfo attrInfo; + PRUint32 len = 0; + PRUint32 dataLen = 0; + PRUint32 attrFormat = 0; + void *dataVal = 0; + void *out = NULL; + CK_RV error = CKR_OK; + OSStatus macErr; + + attrInfo.count = 1; + attrInfo.tag = &itemAttr; + attrInfo.format = &attrFormat; + + macErr = SecKeychainItemCopyAttributesAndData(io->u.item.itemRef, + &attrInfo, NULL, &attrList, &len, &out); + if (noErr != macErr) { + CKMK_MACERR(dbString, macErr); + return CKR_ATTRIBUTE_TYPE_INVALID; + } + dataLen = content ? len : attrList->attr->length; + dataVal = content ? out : attrList->attr->data; + + /* Apple's documentation says this value is DER Encoded, but it clearly isn't + * der encode it before we ship it back off to NSS + */ + if (kSecSerialNumberItemAttr == itemAttr) { + error = ckmk_encodeInt(item, dataVal, dataLen); + goto loser; /* logically 'done' if error == CKR_OK */ + } + item->data = nss_ZNEWARRAY(NULL, char, dataLen); + if (NULL == item->data) { + error = CKR_HOST_MEMORY; + goto loser; + } + nsslibc_memcpy(item->data, dataVal, dataLen); + item->size = dataLen; + +loser: + SecKeychainItemFreeAttributesAndData(attrList, out); + return error; +} + +/* + * change an attribute (does not operate on the content). + */ +static CK_RV +ckmk_updateAttribute( + SecKeychainItemRef itemRef, + SecItemAttr itemAttr, + void *data, + PRUint32 len, + char *dbString) +{ + SecKeychainAttributeList attrList; + SecKeychainAttribute attrAttr; + OSStatus macErr; + CK_RV error = CKR_OK; + + attrList.count = 1; + attrList.attr = &attrAttr; + attrAttr.tag = itemAttr; + attrAttr.data = data; + attrAttr.length = len; + macErr = SecKeychainItemModifyAttributesAndData(itemRef, &attrList, 0, NULL); + if (noErr != macErr) { + CKMK_MACERR(dbString, macErr); + error = CKR_ATTRIBUTE_TYPE_INVALID; + } + return error; +} + +/* + * get an attribute (does not operate on the content) + */ +static CK_RV +ckmk_GetDataAttribute( + ckmkInternalObject *io, + SecItemAttr itemAttr, + NSSItem *item, + char *dbString) +{ + return ckmk_GetCommonAttribute(io, itemAttr, PR_FALSE, item, dbString); +} + +/* + * get an attribute we know is a BOOL. + */ +static CK_RV +ckmk_GetBoolAttribute( + ckmkInternalObject *io, + SecItemAttr itemAttr, + NSSItem *item, + char *dbString) +{ + SecKeychainAttribute attr; + SecKeychainAttributeList attrList; + CK_BBOOL *boolp = NULL; + PRUint32 len = 0; + ; + void *out = NULL; + CK_RV error = CKR_OK; + OSStatus macErr; + + attr.tag = itemAttr; + attr.length = 0; + attr.data = NULL; + attrList.count = 1; + attrList.attr = &attr; + + boolp = nss_ZNEW(NULL, CK_BBOOL); + if ((CK_BBOOL *)NULL == boolp) { + error = CKR_HOST_MEMORY; + goto loser; + } + + macErr = SecKeychainItemCopyContent(io->u.item.itemRef, NULL, + &attrList, &len, &out); + if (noErr != macErr) { + CKMK_MACERR(dbString, macErr); + error = CKR_ATTRIBUTE_TYPE_INVALID; + goto loser; + } + if (sizeof(PRUint32) != attr.length) { + error = CKR_ATTRIBUTE_TYPE_INVALID; + goto loser; + } + *boolp = *(PRUint32 *)attr.data ? 1 : 0; + item->data = boolp; + boolp = NULL; + item->size = sizeof(CK_BBOOL); + +loser: + nss_ZFreeIf(boolp); + SecKeychainItemFreeContent(&attrList, out); + return error; +} + +/* + * macros for fetching attributes into a cache and returning the + * appropriate value. These operate inside switch statements + */ +#define CKMK_HANDLE_ITEM(func, io, type, loc, item, error, str) \ + if (0 == (item)->loc.size) { \ + error = func(io, type, &(item)->loc, str); \ + } \ + return (CKR_OK == (error)) ? &(item)->loc : NULL; + +#define CKMK_HANDLE_OPT_ITEM(func, io, type, loc, item, error, str) \ + if (0 == (item)->loc.size) { \ + (void)func(io, type, &(item)->loc, str); \ + } \ + return &(item)->loc; + +#define CKMK_HANDLE_BOOL_ITEM(io, type, loc, item, error, str) \ + CKMK_HANDLE_ITEM(ckmk_GetBoolAttribute, io, type, loc, item, error, str) +#define CKMK_HANDLE_DATA_ITEM(io, type, loc, item, error, str) \ + CKMK_HANDLE_ITEM(ckmk_GetDataAttribute, io, type, loc, item, error, str) +#define CKMK_HANDLE_OPT_DATA_ITEM(io, type, loc, item, error, str) \ + CKMK_HANDLE_OPT_ITEM(ckmk_GetDataAttribute, io, type, loc, item, error, str) + +/* + * fetch the unique identifier for each object type. + */ +static void +ckmk_FetchHashKey( + ckmkInternalObject *io) +{ + NSSItem *key = &io->hashKey; + + if (io->objClass == CKO_CERTIFICATE) { + ckmk_GetCommonAttribute(io, kSecCertEncodingItemAttr, + PR_TRUE, key, "Fetching HashKey (cert)"); + } else { + ckmk_GetCommonAttribute(io, kSecKeyLabel, + PR_FALSE, key, "Fetching HashKey (key)"); + } +} + +/* + * Apple mucks with the actual subject and issuer, so go fetch + * the real ones ourselves. + */ +static void +ckmk_fetchCert( + ckmkInternalObject *io) +{ + CK_RV error; + unsigned char *cert, *next; + int certSize, thisEntrySize; + + error = ckmk_GetCommonAttribute(io, kSecCertEncodingItemAttr, PR_TRUE, + &io->u.item.derCert, "Fetching Value (cert)"); + if (CKR_OK != error) { + return; + } + /* unwrap the cert bundle */ + cert = nss_ckmk_DERUnwrap((unsigned char *)io->u.item.derCert.data, + io->u.item.derCert.size, + &certSize, NULL); + /* unwrap the cert itself */ + /* cert == certdata */ + cert = nss_ckmk_DERUnwrap(cert, certSize, &certSize, NULL); + + /* skip the optional version */ + if ((cert[0] & 0xa0) == 0xa0) { + nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); + certSize -= next - cert; + cert = next; + } + /* skip the serial number */ + nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); + certSize -= next - cert; + cert = next; + + /* skip the OID */ + nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); + certSize -= next - cert; + cert = next; + + /* save the (wrapped) issuer */ + io->u.item.issuer.data = cert; + nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); + io->u.item.issuer.size = next - cert; + certSize -= io->u.item.issuer.size; + cert = next; + + /* skip the OID */ + nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); + certSize -= next - cert; + cert = next; + + /* save the (wrapped) subject */ + io->u.item.subject.data = cert; + nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); + io->u.item.subject.size = next - cert; + certSize -= io->u.item.subject.size; + cert = next; +} + +static void +ckmk_fetchModulus( + ckmkInternalObject *io) +{ + NSSItem item; + PRInt32 modLen; + CK_RV error; + + /* we can't reliably get the modulus for private keys through CSSM (sigh). + * For NSS this is OK because we really only use this to get the modulus + * length (unless we are trying to get a public key from a private keys, + * something CSSM ALSO does not do!). + */ + error = ckmk_GetDataAttribute(io, kSecKeyKeySizeInBits, &item, + "Key Fetch Modulus"); + if (CKR_OK != error) { + return; + } + + modLen = *(PRInt32 *)item.data; + modLen = modLen / 8; /* convert from bits to bytes */ + + nss_ZFreeIf(item.data); + io->u.item.modulus.data = nss_ZNEWARRAY(NULL, char, modLen); + if (NULL == io->u.item.modulus.data) { + return; + } + *(char *)io->u.item.modulus.data = 0x80; /* fake NSS out or it will + * drop the first byte */ + io->u.item.modulus.size = modLen; + return; +} + +const NSSItem * +ckmk_FetchCertAttribute( + ckmkInternalObject *io, + CK_ATTRIBUTE_TYPE type, + CK_RV *pError) +{ + ckmkItemObject *item = &io->u.item; + *pError = CKR_OK; + switch (type) { + case CKA_CLASS: + return &ckmk_certClassItem; + case CKA_TOKEN: + case CKA_MODIFIABLE: + return &ckmk_trueItem; + case CKA_PRIVATE: + return &ckmk_falseItem; + case CKA_CERTIFICATE_TYPE: + return &ckmk_x509Item; + case CKA_LABEL: + CKMK_HANDLE_OPT_DATA_ITEM(io, kSecLabelItemAttr, label, item, *pError, + "Cert:Label attr") + case CKA_SUBJECT: + /* OK, well apple does provide an subject and issuer attribute, but they + * decided to cannonicalize that value. Probably a good move for them, + * but makes it useless for most users of PKCS #11.. Get the real subject + * from the certificate */ + if (0 == item->derCert.size) { + ckmk_fetchCert(io); + } + return &item->subject; + case CKA_ISSUER: + if (0 == item->derCert.size) { + ckmk_fetchCert(io); + } + return &item->issuer; + case CKA_SERIAL_NUMBER: + CKMK_HANDLE_DATA_ITEM(io, kSecSerialNumberItemAttr, serial, item, *pError, + "Cert:Serial Number attr") + case CKA_VALUE: + if (0 == item->derCert.size) { + ckmk_fetchCert(io); + } + return &item->derCert; + case CKA_ID: + CKMK_HANDLE_OPT_DATA_ITEM(io, kSecPublicKeyHashItemAttr, id, item, *pError, + "Cert:ID attr") + default: + *pError = CKR_ATTRIBUTE_TYPE_INVALID; + break; + } + return NULL; +} + +const NSSItem * +ckmk_FetchPubKeyAttribute( + ckmkInternalObject *io, + CK_ATTRIBUTE_TYPE type, + CK_RV *pError) +{ + ckmkItemObject *item = &io->u.item; + *pError = CKR_OK; + + switch (type) { + case CKA_CLASS: + return &ckmk_pubKeyClassItem; + case CKA_TOKEN: + case CKA_LOCAL: + return &ckmk_trueItem; + case CKA_KEY_TYPE: + return &ckmk_rsaItem; + case CKA_LABEL: + CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyPrintName, label, item, *pError, + "PubKey:Label attr") + case CKA_ENCRYPT: + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyEncrypt, encrypt, item, *pError, + "PubKey:Encrypt attr") + case CKA_VERIFY: + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyVerify, verify, item, *pError, + "PubKey:Verify attr") + case CKA_VERIFY_RECOVER: + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyVerifyRecover, verifyRecover, + item, *pError, "PubKey:VerifyRecover attr") + case CKA_PRIVATE: + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyPrivate, private, item, *pError, + "PubKey:Private attr") + case CKA_MODIFIABLE: + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyModifiable, modify, item, *pError, + "PubKey:Modify attr") + case CKA_DERIVE: + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyDerive, derive, item, *pError, + "PubKey:Derive attr") + case CKA_WRAP: + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyWrap, wrap, item, *pError, + "PubKey:Wrap attr") + case CKA_SUBJECT: + CKMK_HANDLE_OPT_DATA_ITEM(io, kSecSubjectItemAttr, subject, item, *pError, + "PubKey:Subect attr") + case CKA_MODULUS: + return &ckmk_emptyItem; + case CKA_PUBLIC_EXPONENT: + return &ckmk_emptyItem; + case CKA_ID: + CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyLabel, id, item, *pError, + "PubKey:ID attr") + default: + *pError = CKR_ATTRIBUTE_TYPE_INVALID; + break; + } + return NULL; +} + +const NSSItem * +ckmk_FetchPrivKeyAttribute( + ckmkInternalObject *io, + CK_ATTRIBUTE_TYPE type, + CK_RV *pError) +{ + ckmkItemObject *item = &io->u.item; + *pError = CKR_OK; + + switch (type) { + case CKA_CLASS: + return &ckmk_privKeyClassItem; + case CKA_TOKEN: + case CKA_LOCAL: + return &ckmk_trueItem; + case CKA_SENSITIVE: + case CKA_EXTRACTABLE: /* will probably move in the future */ + case CKA_ALWAYS_SENSITIVE: + case CKA_NEVER_EXTRACTABLE: + return &ckmk_falseItem; + case CKA_KEY_TYPE: + return &ckmk_rsaItem; + case CKA_LABEL: + CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyPrintName, label, item, *pError, + "PrivateKey:Label attr") + case CKA_DECRYPT: + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyDecrypt, decrypt, item, *pError, + "PrivateKey:Decrypt attr") + case CKA_SIGN: + CKMK_HANDLE_BOOL_ITEM(io, kSecKeySign, sign, item, *pError, + "PrivateKey:Sign attr") + case CKA_SIGN_RECOVER: + CKMK_HANDLE_BOOL_ITEM(io, kSecKeySignRecover, signRecover, item, *pError, + "PrivateKey:Sign Recover attr") + case CKA_PRIVATE: + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyPrivate, private, item, *pError, + "PrivateKey:Private attr") + case CKA_MODIFIABLE: + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyModifiable, modify, item, *pError, + "PrivateKey:Modify attr") + case CKA_DERIVE: + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyDerive, derive, item, *pError, + "PrivateKey:Derive attr") + case CKA_UNWRAP: + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyUnwrap, unwrap, item, *pError, + "PrivateKey:Unwrap attr") + case CKA_SUBJECT: + CKMK_HANDLE_OPT_DATA_ITEM(io, kSecSubjectItemAttr, subject, item, *pError, + "PrivateKey:Subject attr") + case CKA_MODULUS: + if (0 == item->modulus.size) { + ckmk_fetchModulus(io); + } + return &item->modulus; + case CKA_PUBLIC_EXPONENT: + return &ckmk_emptyItem; +#ifdef notdef + /* the following are sensitive attributes. We could implement them for + * sensitive keys using the key export function, but it's better to + * just support wrap through this token. That will more reliably allow us + * to export any private key that is truly exportable. + */ + case CKA_PRIVATE_EXPONENT: + CKMK_HANDLE_DATA_ITEM(io, kSecPrivateExponentItemAttr, privateExponent, + item, *pError) + case CKA_PRIME_1: + CKMK_HANDLE_DATA_ITEM(io, kSecPrime1ItemAttr, prime1, item, *pError) + case CKA_PRIME_2: + CKMK_HANDLE_DATA_ITEM(io, kSecPrime2ItemAttr, prime2, item, *pError) + case CKA_EXPONENT_1: + CKMK_HANDLE_DATA_ITEM(io, kSecExponent1ItemAttr, exponent1, item, *pError) + case CKA_EXPONENT_2: + CKMK_HANDLE_DATA_ITEM(io, kSecExponent2ItemAttr, exponent2, item, *pError) + case CKA_COEFFICIENT: + CKMK_HANDLE_DATA_ITEM(io, kSecCoefficientItemAttr, coefficient, + item, *pError) +#endif + case CKA_ID: + CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyLabel, id, item, *pError, + "PrivateKey:ID attr") + default: + *pError = CKR_ATTRIBUTE_TYPE_INVALID; + return NULL; + } +} + +const NSSItem * +nss_ckmk_FetchAttribute( + ckmkInternalObject *io, + CK_ATTRIBUTE_TYPE type, + CK_RV *pError) +{ + CK_ULONG i; + const NSSItem *value = NULL; + + if (io->type == ckmkRaw) { + for (i = 0; i < io->u.raw.n; i++) { + if (type == io->u.raw.types[i]) { + return &io->u.raw.items[i]; + } + } + *pError = CKR_ATTRIBUTE_TYPE_INVALID; + return NULL; + } + /* deal with the common attributes */ + switch (io->objClass) { + case CKO_CERTIFICATE: + value = ckmk_FetchCertAttribute(io, type, pError); + break; + case CKO_PRIVATE_KEY: + value = ckmk_FetchPrivKeyAttribute(io, type, pError); + break; + case CKO_PUBLIC_KEY: + value = ckmk_FetchPubKeyAttribute(io, type, pError); + break; + default: + *pError = CKR_OBJECT_HANDLE_INVALID; + return NULL; + } + +#ifdef DEBUG + if (CKA_ID == type) { + itemdump("id: ", value->data, value->size, *pError); + } +#endif + return value; +} + +static void +ckmk_removeObjectFromHash( + ckmkInternalObject *io); + +/* + * + * These are the MSObject functions we need to implement + * + * Finalize - unneeded (actually we should clean up the hashtables) + * Destroy + * IsTokenObject - CK_TRUE + * GetAttributeCount + * GetAttributeTypes + * GetAttributeSize + * GetAttribute + * SetAttribute + * GetObjectSize + */ + +static CK_RV +ckmk_mdObject_Destroy( + NSSCKMDObject *mdObject, + NSSCKFWObject *fwObject, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; + OSStatus macErr; + + if (ckmkRaw == io->type) { + /* there is not 'object write protected' error, use the next best thing */ + return CKR_TOKEN_WRITE_PROTECTED; + } + + /* This API is done well. The following 4 lines are the complete apple + * specific part of this implementation */ + macErr = SecKeychainItemDelete(io->u.item.itemRef); + if (noErr != macErr) { + CKMK_MACERR("Delete object", macErr); + } + + /* remove it from the hash */ + ckmk_removeObjectFromHash(io); + + /* free the puppy.. */ + nss_ckmk_DestroyInternalObject(io); + + return CKR_OK; +} + +static CK_BBOOL +ckmk_mdObject_IsTokenObject( + NSSCKMDObject *mdObject, + NSSCKFWObject *fwObject, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return CK_TRUE; +} + +static CK_ULONG +ckmk_mdObject_GetAttributeCount( + NSSCKMDObject *mdObject, + NSSCKFWObject *fwObject, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; + + if (ckmkRaw == io->type) { + return io->u.raw.n; + } + switch (io->objClass) { + case CKO_CERTIFICATE: + return certAttrsCount; + case CKO_PUBLIC_KEY: + return pubKeyAttrsCount; + case CKO_PRIVATE_KEY: + return privKeyAttrsCount; + default: + break; + } + return 0; +} + +static CK_RV +ckmk_mdObject_GetAttributeTypes( + NSSCKMDObject *mdObject, + NSSCKFWObject *fwObject, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_ATTRIBUTE_TYPE_PTR typeArray, + CK_ULONG ulCount) +{ + ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; + CK_ULONG i; + CK_RV error = CKR_OK; + const CK_ATTRIBUTE_TYPE *attrs = NULL; + CK_ULONG size = ckmk_mdObject_GetAttributeCount( + mdObject, fwObject, mdSession, fwSession, + mdToken, fwToken, mdInstance, fwInstance, &error); + + if (size != ulCount) { + return CKR_BUFFER_TOO_SMALL; + } + if (io->type == ckmkRaw) { + attrs = io->u.raw.types; + } else + switch (io->objClass) { + case CKO_CERTIFICATE: + attrs = + certAttrs; + break; + case CKO_PUBLIC_KEY: + attrs = + pubKeyAttrs; + break; + case CKO_PRIVATE_KEY: + attrs = + privKeyAttrs; + break; + default: + return CKR_OK; + } + + for (i = 0; i < size; i++) { + typeArray[i] = attrs[i]; + } + + return CKR_OK; +} + +static CK_ULONG +ckmk_mdObject_GetAttributeSize( + NSSCKMDObject *mdObject, + NSSCKFWObject *fwObject, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_ATTRIBUTE_TYPE attribute, + CK_RV *pError) +{ + ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; + + const NSSItem *b; + + b = nss_ckmk_FetchAttribute(io, attribute, pError); + + if ((const NSSItem *)NULL == b) { + return 0; + } + return b->size; +} + +static CK_RV +ckmk_mdObject_SetAttribute( + NSSCKMDObject *mdObject, + NSSCKFWObject *fwObject, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_ATTRIBUTE_TYPE attribute, + NSSItem *value) +{ + ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; + SecKeychainItemRef itemRef; + + if (io->type == ckmkRaw) { + return CKR_TOKEN_WRITE_PROTECTED; + } + itemRef = io->u.item.itemRef; + + switch (io->objClass) { + case CKO_PRIVATE_KEY: + case CKO_PUBLIC_KEY: + switch (attribute) { + case CKA_ID: + ckmk_updateAttribute(itemRef, kSecKeyLabel, + value->data, value->size, "Set Attr Key ID"); +#ifdef DEBUG + itemdump("key id: ", value->data, value->size, CKR_OK); +#endif + break; + case CKA_LABEL: + ckmk_updateAttribute(itemRef, kSecKeyPrintName, value->data, + value->size, "Set Attr Key Label"); + break; + default: + break; + } + break; + + case CKO_CERTIFICATE: + switch (attribute) { + case CKA_ID: + ckmk_updateAttribute(itemRef, kSecPublicKeyHashItemAttr, + value->data, value->size, "Set Attr Cert ID"); + break; + case CKA_LABEL: + ckmk_updateAttribute(itemRef, kSecLabelItemAttr, value->data, + value->size, "Set Attr Cert Label"); + break; + default: + break; + } + break; + + default: + break; + } + return CKR_OK; +} + +static NSSCKFWItem +ckmk_mdObject_GetAttribute( + NSSCKMDObject *mdObject, + NSSCKFWObject *fwObject, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_ATTRIBUTE_TYPE attribute, + CK_RV *pError) +{ + NSSCKFWItem mdItem; + ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; + + mdItem.needsFreeing = PR_FALSE; + mdItem.item = (NSSItem *)nss_ckmk_FetchAttribute(io, attribute, pError); + + return mdItem; +} + +static CK_ULONG +ckmk_mdObject_GetObjectSize( + NSSCKMDObject *mdObject, + NSSCKFWObject *fwObject, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + CK_ULONG rv = 1; + + /* size is irrelevant to this token */ + return rv; +} + +static const NSSCKMDObject + ckmk_prototype_mdObject = { + (void *)NULL, /* etc */ + NULL, /* Finalize */ + ckmk_mdObject_Destroy, + ckmk_mdObject_IsTokenObject, + ckmk_mdObject_GetAttributeCount, + ckmk_mdObject_GetAttributeTypes, + ckmk_mdObject_GetAttributeSize, + ckmk_mdObject_GetAttribute, + NULL, /* FreeAttribute */ + ckmk_mdObject_SetAttribute, + ckmk_mdObject_GetObjectSize, + (void *)NULL /* null terminator */ + }; + +static nssHash *ckmkInternalObjectHash = NULL; + +NSS_IMPLEMENT NSSCKMDObject * +nss_ckmk_CreateMDObject( + NSSArena *arena, + ckmkInternalObject *io, + CK_RV *pError) +{ + if ((nssHash *)NULL == ckmkInternalObjectHash) { + ckmkInternalObjectHash = nssHash_CreateItem(NULL, 10); + } + if (ckmkItem == io->type) { + /* the hash key, not a cryptographic key */ + NSSItem *key = &io->hashKey; + ckmkInternalObject *old_o = NULL; + + if (key->size == 0) { + ckmk_FetchHashKey(io); + } + old_o = (ckmkInternalObject *) + nssHash_Lookup(ckmkInternalObjectHash, key); + if (!old_o) { + nssHash_Add(ckmkInternalObjectHash, key, io); + } else if (old_o != io) { + nss_ckmk_DestroyInternalObject(io); + io = old_o; + } + } + + if ((void *)NULL == io->mdObject.etc) { + (void)nsslibc_memcpy(&io->mdObject, &ckmk_prototype_mdObject, + sizeof(ckmk_prototype_mdObject)); + io->mdObject.etc = (void *)io; + } + return &io->mdObject; +} + +static void +ckmk_removeObjectFromHash( + ckmkInternalObject *io) +{ + NSSItem *key = &io->hashKey; + + if ((nssHash *)NULL == ckmkInternalObjectHash) { + return; + } + if (key->size == 0) { + ckmk_FetchHashKey(io); + } + nssHash_Remove(ckmkInternalObjectHash, key); + return; +} + +void +nss_ckmk_DestroyInternalObject( + ckmkInternalObject *io) +{ + switch (io->type) { + case ckmkRaw: + return; + case ckmkItem: + nss_ZFreeIf(io->u.item.modify.data); + nss_ZFreeIf(io->u.item.private.data); + nss_ZFreeIf(io->u.item.encrypt.data); + nss_ZFreeIf(io->u.item.decrypt.data); + nss_ZFreeIf(io->u.item.derive.data); + nss_ZFreeIf(io->u.item.sign.data); + nss_ZFreeIf(io->u.item.signRecover.data); + nss_ZFreeIf(io->u.item.verify.data); + nss_ZFreeIf(io->u.item.verifyRecover.data); + nss_ZFreeIf(io->u.item.wrap.data); + nss_ZFreeIf(io->u.item.unwrap.data); + nss_ZFreeIf(io->u.item.label.data); + /*nss_ZFreeIf(io->u.item.subject.data); */ + /*nss_ZFreeIf(io->u.item.issuer.data); */ + nss_ZFreeIf(io->u.item.serial.data); + nss_ZFreeIf(io->u.item.modulus.data); + nss_ZFreeIf(io->u.item.exponent.data); + nss_ZFreeIf(io->u.item.privateExponent.data); + nss_ZFreeIf(io->u.item.prime1.data); + nss_ZFreeIf(io->u.item.prime2.data); + nss_ZFreeIf(io->u.item.exponent1.data); + nss_ZFreeIf(io->u.item.exponent2.data); + nss_ZFreeIf(io->u.item.coefficient.data); + break; + } + nss_ZFreeIf(io); + return; +} + +static ckmkInternalObject * +nss_ckmk_NewInternalObject( + CK_OBJECT_CLASS objClass, + SecKeychainItemRef itemRef, + SecItemClass itemClass, + CK_RV *pError) +{ + ckmkInternalObject *io = nss_ZNEW(NULL, ckmkInternalObject); + + if ((ckmkInternalObject *)NULL == io) { + *pError = CKR_HOST_MEMORY; + return io; + } + io->type = ckmkItem; + io->objClass = objClass; + io->u.item.itemRef = itemRef; + io->u.item.itemClass = itemClass; + return io; +} + +/* + * Apple doesn't alway have a default keyChain set by the OS, use the + * SearchList to try to find one. + */ +static CK_RV +ckmk_GetSafeDefaultKeychain( + SecKeychainRef *keychainRef) +{ + OSStatus macErr; + CFArrayRef searchList = 0; + CK_RV error = CKR_OK; + + macErr = SecKeychainCopyDefault(keychainRef); + if (noErr != macErr) { + int searchCount = 0; + if (errSecNoDefaultKeychain != macErr) { + CKMK_MACERR("Getting default key chain", macErr); + error = CKR_GENERAL_ERROR; + goto loser; + } + /* ok, we don't have a default key chain, find one */ + macErr = SecKeychainCopySearchList(&searchList); + if (noErr != macErr) { + CKMK_MACERR("failed to find a keyring searchList", macErr); + error = CKR_DEVICE_REMOVED; + goto loser; + } + searchCount = CFArrayGetCount(searchList); + if (searchCount < 1) { + error = CKR_DEVICE_REMOVED; + goto loser; + } + *keychainRef = + (SecKeychainRef)CFRetain(CFArrayGetValueAtIndex(searchList, 0)); + if (0 == *keychainRef) { + error = CKR_DEVICE_REMOVED; + goto loser; + } + /* should we set it as default? */ + } +loser: + if (0 != searchList) { + CFRelease(searchList); + } + return error; +} +static ckmkInternalObject * +nss_ckmk_CreateCertificate( + NSSCKFWSession *fwSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + CK_RV *pError) +{ + NSSItem value; + ckmkInternalObject *io = NULL; + OSStatus macErr; + SecCertificateRef certRef; + SecKeychainItemRef itemRef; + SecKeychainRef keychainRef; + CSSM_DATA certData; + + *pError = nss_ckmk_GetAttribute(CKA_VALUE, pTemplate, + ulAttributeCount, &value); + if (CKR_OK != *pError) { + goto loser; + } + + certData.Data = value.data; + certData.Length = value.size; + macErr = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3, + CSSM_CERT_ENCODING_BER, &certRef); + if (noErr != macErr) { + CKMK_MACERR("Create cert from data Failed", macErr); + *pError = CKR_GENERAL_ERROR; /* need to map macErr */ + goto loser; + } + + *pError = ckmk_GetSafeDefaultKeychain(&keychainRef); + if (CKR_OK != *pError) { + goto loser; + } + + macErr = SecCertificateAddToKeychain(certRef, keychainRef); + itemRef = (SecKeychainItemRef)certRef; + if (errSecDuplicateItem != macErr) { + NSSItem keyID = { NULL, 0 }; + char *nickname = NULL; + CK_RV dummy; + + if (noErr != macErr) { + CKMK_MACERR("Add cert to keychain Failed", macErr); + *pError = CKR_GENERAL_ERROR; /* need to map macErr */ + goto loser; + } + /* these two are optional */ + nickname = nss_ckmk_GetStringAttribute(CKA_LABEL, pTemplate, + ulAttributeCount, &dummy); + /* we've added a new one, update the attributes in the key ring */ + if (nickname) { + ckmk_updateAttribute(itemRef, kSecLabelItemAttr, nickname, + strlen(nickname) + 1, "Modify Cert Label"); + nss_ZFreeIf(nickname); + } + dummy = nss_ckmk_GetAttribute(CKA_ID, pTemplate, + ulAttributeCount, &keyID); + if (CKR_OK == dummy) { + dummy = ckmk_updateAttribute(itemRef, kSecPublicKeyHashItemAttr, + keyID.data, keyID.size, "Modify Cert ID"); + } + } + + io = nss_ckmk_NewInternalObject(CKO_CERTIFICATE, itemRef, + kSecCertificateItemClass, pError); + if ((ckmkInternalObject *)NULL != io) { + itemRef = 0; + } + +loser: + if (0 != itemRef) { + CFRelease(itemRef); + } + if (0 != keychainRef) { + CFRelease(keychainRef); + } + + return io; +} + +/* + * PKCS #8 attributes + */ +struct ckmk_AttributeStr { + SECItem attrType; + SECItem *attrValue; +}; +typedef struct ckmk_AttributeStr ckmk_Attribute; + +/* + ** A PKCS#8 private key info object + */ +struct PrivateKeyInfoStr { + PLArenaPool *arena; + SECItem version; + SECAlgorithmID algorithm; + SECItem privateKey; + ckmk_Attribute **attributes; +}; +typedef struct PrivateKeyInfoStr PrivateKeyInfo; + +const SEC_ASN1Template ckmk_RSAPrivateKeyTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RSAPrivateKey) }, + { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, version) }, + { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, modulus) }, + { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, publicExponent) }, + { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, privateExponent) }, + { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime1) }, + { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime2) }, + { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent1) }, + { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent2) }, + { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, coefficient) }, + { 0 } +}; + +const SEC_ASN1Template ckmk_AttributeTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ckmk_Attribute) }, + { SEC_ASN1_OBJECT_ID, offsetof(ckmk_Attribute, attrType) }, + { SEC_ASN1_SET_OF, offsetof(ckmk_Attribute, attrValue), + SEC_AnyTemplate }, + { 0 } +}; + +const SEC_ASN1Template ckmk_SetOfAttributeTemplate[] = { + { SEC_ASN1_SET_OF, 0, ckmk_AttributeTemplate }, +}; + +SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) + +/* ASN1 Templates for new decoder/encoder */ +const SEC_ASN1Template ckmk_PrivateKeyInfoTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PrivateKeyInfo) }, + { SEC_ASN1_INTEGER, offsetof(PrivateKeyInfo, version) }, + { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(PrivateKeyInfo, algorithm), + SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, + { SEC_ASN1_OCTET_STRING, offsetof(PrivateKeyInfo, privateKey) }, + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, + offsetof(PrivateKeyInfo, attributes), ckmk_SetOfAttributeTemplate }, + { 0 } +}; + +#define CKMK_PRIVATE_KEY_INFO_VERSION 0 +static CK_RV +ckmk_CreateRSAKeyBlob( + RSAPrivateKey *lk, + NSSItem *keyBlob) +{ + PrivateKeyInfo *pki = NULL; + PLArenaPool *arena = NULL; + SECOidTag algorithm = SEC_OID_UNKNOWN; + void *dummy; + SECStatus rv; + SECItem *encodedKey = NULL; + CK_RV error = CKR_OK; + + arena = PORT_NewArena(2048); /* XXX different size? */ + if (!arena) { + error = CKR_HOST_MEMORY; + goto loser; + } + + pki = (PrivateKeyInfo *)PORT_ArenaZAlloc(arena, sizeof(PrivateKeyInfo)); + if (!pki) { + error = CKR_HOST_MEMORY; + goto loser; + } + pki->arena = arena; + + dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk, + ckmk_RSAPrivateKeyTemplate); + algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION; + + if (!dummy) { + error = CKR_DEVICE_ERROR; /* should map NSS SECError */ + goto loser; + } + + rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, algorithm, + (SECItem *)NULL); + if (rv != SECSuccess) { + error = CKR_DEVICE_ERROR; /* should map NSS SECError */ + goto loser; + } + + dummy = SEC_ASN1EncodeInteger(arena, &pki->version, + CKMK_PRIVATE_KEY_INFO_VERSION); + if (!dummy) { + error = CKR_DEVICE_ERROR; /* should map NSS SECError */ + goto loser; + } + + encodedKey = SEC_ASN1EncodeItem(NULL, NULL, pki, + ckmk_PrivateKeyInfoTemplate); + if (!encodedKey) { + error = CKR_DEVICE_ERROR; + goto loser; + } + + keyBlob->data = nss_ZNEWARRAY(NULL, char, encodedKey->len); + if (NULL == keyBlob->data) { + error = CKR_HOST_MEMORY; + goto loser; + } + nsslibc_memcpy(keyBlob->data, encodedKey->data, encodedKey->len); + keyBlob->size = encodedKey->len; + +loser: + if (arena) { + PORT_FreeArena(arena, PR_TRUE); + } + if (encodedKey) { + SECITEM_FreeItem(encodedKey, PR_TRUE); + } + + return error; +} +/* + * There MUST be a better way to do this. For now, find the key based on the + * default name Apple gives it once we import. + */ +#define IMPORTED_NAME "Imported Private Key" +static CK_RV +ckmk_FindImportedKey( + SecKeychainRef keychainRef, + SecItemClass itemClass, + SecKeychainItemRef *outItemRef) +{ + OSStatus macErr; + SecKeychainSearchRef searchRef = 0; + SecKeychainItemRef newItemRef; + + macErr = SecKeychainSearchCreateFromAttributes(keychainRef, itemClass, + NULL, &searchRef); + if (noErr != macErr) { + CKMK_MACERR("Can't search for Key", macErr); + return CKR_GENERAL_ERROR; + } + while (noErr == SecKeychainSearchCopyNext(searchRef, &newItemRef)) { + SecKeychainAttributeList *attrList = NULL; + SecKeychainAttributeInfo attrInfo; + SecItemAttr itemAttr = kSecKeyPrintName; + PRUint32 attrFormat = 0; + OSStatus macErr; + + attrInfo.count = 1; + attrInfo.tag = &itemAttr; + attrInfo.format = &attrFormat; + + macErr = SecKeychainItemCopyAttributesAndData(newItemRef, + &attrInfo, NULL, &attrList, NULL, NULL); + if (noErr == macErr) { + if (nsslibc_memcmp(attrList->attr->data, IMPORTED_NAME, + attrList->attr->length, NULL) == 0) { + *outItemRef = newItemRef; + CFRelease(searchRef); + SecKeychainItemFreeAttributesAndData(attrList, NULL); + return CKR_OK; + } + SecKeychainItemFreeAttributesAndData(attrList, NULL); + } + CFRelease(newItemRef); + } + CFRelease(searchRef); + return CKR_GENERAL_ERROR; /* we can come up with something better! */ +} + +static ckmkInternalObject * +nss_ckmk_CreatePrivateKey( + NSSCKFWSession *fwSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + CK_RV *pError) +{ + NSSItem attribute; + RSAPrivateKey lk; + NSSItem keyID; + char *nickname = NULL; + ckmkInternalObject *io = NULL; + CK_KEY_TYPE keyType; + OSStatus macErr; + SecKeychainItemRef itemRef = 0; + NSSItem keyBlob = { NULL, 0 }; + CFDataRef dataRef = 0; + SecExternalFormat inputFormat = kSecFormatBSAFE; + /*SecExternalFormat inputFormat = kSecFormatOpenSSL; */ + SecExternalItemType itemType = kSecItemTypePrivateKey; + SecKeyImportExportParameters keyParams; + SecKeychainRef targetKeychain = 0; + unsigned char zero = 0; + CK_RV error; + + keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; + keyParams.flags = 0; + keyParams.passphrase = 0; + keyParams.alertTitle = 0; + keyParams.alertPrompt = 0; + keyParams.accessRef = 0; /* default */ + keyParams.keyUsage = 0; /* will get filled in */ + keyParams.keyAttributes = CSSM_KEYATTR_PERMANENT; /* will get filled in */ + keyType = nss_ckmk_GetULongAttribute(CKA_KEY_TYPE, pTemplate, ulAttributeCount, pError); + if (CKR_OK != *pError) { + return (ckmkInternalObject *)NULL; + } + if (CKK_RSA != keyType) { + *pError = CKR_ATTRIBUTE_VALUE_INVALID; + return (ckmkInternalObject *)NULL; + } + if (nss_ckmk_GetBoolAttribute(CKA_DECRYPT, + pTemplate, ulAttributeCount, CK_TRUE)) { + keyParams.keyUsage |= CSSM_KEYUSE_DECRYPT; + } + if (nss_ckmk_GetBoolAttribute(CKA_UNWRAP, + pTemplate, ulAttributeCount, CK_TRUE)) { + keyParams.keyUsage |= CSSM_KEYUSE_UNWRAP; + } + if (nss_ckmk_GetBoolAttribute(CKA_SIGN, + pTemplate, ulAttributeCount, CK_TRUE)) { + keyParams.keyUsage |= CSSM_KEYUSE_SIGN; + } + if (nss_ckmk_GetBoolAttribute(CKA_DERIVE, + pTemplate, ulAttributeCount, CK_FALSE)) { + keyParams.keyUsage |= CSSM_KEYUSE_DERIVE; + } + if (nss_ckmk_GetBoolAttribute(CKA_SENSITIVE, + pTemplate, ulAttributeCount, CK_TRUE)) { + keyParams.keyAttributes |= CSSM_KEYATTR_SENSITIVE; + } + if (nss_ckmk_GetBoolAttribute(CKA_EXTRACTABLE, + pTemplate, ulAttributeCount, CK_TRUE)) { + keyParams.keyAttributes |= CSSM_KEYATTR_EXTRACTABLE; + } + + lk.version.type = siUnsignedInteger; + lk.version.data = &zero; + lk.version.len = 1; + + *pError = nss_ckmk_GetAttribute(CKA_MODULUS, pTemplate, + ulAttributeCount, &attribute); + if (CKR_OK != *pError) { + return (ckmkInternalObject *)NULL; + } + lk.modulus.type = siUnsignedInteger; + lk.modulus.data = attribute.data; + lk.modulus.len = attribute.size; + + *pError = nss_ckmk_GetAttribute(CKA_PUBLIC_EXPONENT, pTemplate, + ulAttributeCount, &attribute); + if (CKR_OK != *pError) { + return (ckmkInternalObject *)NULL; + } + lk.publicExponent.type = siUnsignedInteger; + lk.publicExponent.data = attribute.data; + lk.publicExponent.len = attribute.size; + + *pError = nss_ckmk_GetAttribute(CKA_PRIVATE_EXPONENT, pTemplate, + ulAttributeCount, &attribute); + if (CKR_OK != *pError) { + return (ckmkInternalObject *)NULL; + } + lk.privateExponent.type = siUnsignedInteger; + lk.privateExponent.data = attribute.data; + lk.privateExponent.len = attribute.size; + + *pError = nss_ckmk_GetAttribute(CKA_PRIME_1, pTemplate, + ulAttributeCount, &attribute); + if (CKR_OK != *pError) { + return (ckmkInternalObject *)NULL; + } + lk.prime1.type = siUnsignedInteger; + lk.prime1.data = attribute.data; + lk.prime1.len = attribute.size; + + *pError = nss_ckmk_GetAttribute(CKA_PRIME_2, pTemplate, + ulAttributeCount, &attribute); + if (CKR_OK != *pError) { + return (ckmkInternalObject *)NULL; + } + lk.prime2.type = siUnsignedInteger; + lk.prime2.data = attribute.data; + lk.prime2.len = attribute.size; + + *pError = nss_ckmk_GetAttribute(CKA_EXPONENT_1, pTemplate, + ulAttributeCount, &attribute); + if (CKR_OK != *pError) { + return (ckmkInternalObject *)NULL; + } + lk.exponent1.type = siUnsignedInteger; + lk.exponent1.data = attribute.data; + lk.exponent1.len = attribute.size; + + *pError = nss_ckmk_GetAttribute(CKA_EXPONENT_2, pTemplate, + ulAttributeCount, &attribute); + if (CKR_OK != *pError) { + return (ckmkInternalObject *)NULL; + } + lk.exponent2.type = siUnsignedInteger; + lk.exponent2.data = attribute.data; + lk.exponent2.len = attribute.size; + + *pError = nss_ckmk_GetAttribute(CKA_COEFFICIENT, pTemplate, + ulAttributeCount, &attribute); + if (CKR_OK != *pError) { + return (ckmkInternalObject *)NULL; + } + lk.coefficient.type = siUnsignedInteger; + lk.coefficient.data = attribute.data; + lk.coefficient.len = attribute.size; + + /* ASN1 Encode the pkcs8 structure... look at softoken to see how this + * is done... */ + error = ckmk_CreateRSAKeyBlob(&lk, &keyBlob); + if (CKR_OK != error) { + goto loser; + } + + dataRef = CFDataCreate(NULL, (UInt8 *)keyBlob.data, keyBlob.size); + if (0 == dataRef) { + *pError = CKR_HOST_MEMORY; + goto loser; + } + + *pError == ckmk_GetSafeDefaultKeychain(&targetKeychain); + if (CKR_OK != *pError) { + goto loser; + } + + /* the itemArray that is returned is useless. the item does not + * is 'not on the key chain' so none of the modify calls work on it. + * It also has a key that isn't the same key as the one in the actual + * key chain. In short it isn't the item we want, and it gives us zero + * information about the item we want, so don't even bother with it... + */ + macErr = SecKeychainItemImport(dataRef, NULL, &inputFormat, &itemType, 0, + &keyParams, targetKeychain, NULL); + if (noErr != macErr) { + CKMK_MACERR("Import Private Key", macErr); + *pError = CKR_GENERAL_ERROR; + goto loser; + } + + *pError = ckmk_FindImportedKey(targetKeychain, + CSSM_DL_DB_RECORD_PRIVATE_KEY, + &itemRef); + if (CKR_OK != *pError) { +#ifdef DEBUG + fprintf(stderr, "couldn't find key in keychain \n"); +#endif + goto loser; + } + + /* set the CKA_ID and the CKA_LABEL */ + error = nss_ckmk_GetAttribute(CKA_ID, pTemplate, + ulAttributeCount, &keyID); + if (CKR_OK == error) { + error = ckmk_updateAttribute(itemRef, kSecKeyLabel, + keyID.data, keyID.size, "Modify Key ID"); +#ifdef DEBUG + itemdump("key id: ", keyID.data, keyID.size, error); +#endif + } + nickname = nss_ckmk_GetStringAttribute(CKA_LABEL, pTemplate, + ulAttributeCount, &error); + if (nickname) { + ckmk_updateAttribute(itemRef, kSecKeyPrintName, nickname, + strlen(nickname) + 1, "Modify Key Label"); + } else { +#define DEFAULT_NICKNAME "NSS Imported Key" + ckmk_updateAttribute(itemRef, kSecKeyPrintName, DEFAULT_NICKNAME, + sizeof(DEFAULT_NICKNAME), "Modify Key Label"); + } + + io = nss_ckmk_NewInternalObject(CKO_PRIVATE_KEY, itemRef, + CSSM_DL_DB_RECORD_PRIVATE_KEY, pError); + if ((ckmkInternalObject *)NULL == io) { + CFRelease(itemRef); + } + + return io; + +loser: + /* free the key blob */ + if (keyBlob.data) { + nss_ZFreeIf(keyBlob.data); + } + if (0 != targetKeychain) { + CFRelease(targetKeychain); + } + if (0 != dataRef) { + CFRelease(dataRef); + } + return io; +} + +NSS_EXTERN NSSCKMDObject * +nss_ckmk_CreateObject( + NSSCKFWSession *fwSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + CK_RV *pError) +{ + CK_OBJECT_CLASS objClass; + ckmkInternalObject *io = NULL; + CK_BBOOL isToken; + + /* + * only create token objects + */ + isToken = nss_ckmk_GetBoolAttribute(CKA_TOKEN, pTemplate, + ulAttributeCount, CK_FALSE); + if (!isToken) { + *pError = CKR_ATTRIBUTE_VALUE_INVALID; + return (NSSCKMDObject *)NULL; + } + + /* + * only create keys and certs. + */ + objClass = nss_ckmk_GetULongAttribute(CKA_CLASS, pTemplate, + ulAttributeCount, pError); + if (CKR_OK != *pError) { + return (NSSCKMDObject *)NULL; + } +#ifdef notdef + if (objClass == CKO_PUBLIC_KEY) { + return CKR_OK; /* fake public key creation, happens as a side effect of + * private key creation */ + } +#endif + if (objClass == CKO_CERTIFICATE) { + io = nss_ckmk_CreateCertificate(fwSession, pTemplate, + ulAttributeCount, pError); + } else if (objClass == CKO_PRIVATE_KEY) { + io = nss_ckmk_CreatePrivateKey(fwSession, pTemplate, + ulAttributeCount, pError); + } else { + *pError = CKR_ATTRIBUTE_VALUE_INVALID; + } + + if ((ckmkInternalObject *)NULL == io) { + return (NSSCKMDObject *)NULL; + } + return nss_ckmk_CreateMDObject(NULL, io, pError); +} diff --git a/security/nss/lib/ckfw/nssmkey/mrsa.c b/security/nss/lib/ckfw/nssmkey/mrsa.c new file mode 100644 index 000000000..00175b47a --- /dev/null +++ b/security/nss/lib/ckfw/nssmkey/mrsa.c @@ -0,0 +1,479 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ckmk.h" + +/* Sigh, For all the talk about 'ease of use', apple has hidden the interfaces + * needed to be able to truly use CSSM. These came from their modification + * to NSS's S/MIME code. The following two functions currently are not + * part of the SecKey.h interface. + */ +OSStatus +SecKeyGetCredentials( + SecKeyRef keyRef, + CSSM_ACL_AUTHORIZATION_TAG authTag, + int type, + const CSSM_ACCESS_CREDENTIALS **creds); + +/* this function could be implemented using 'SecKeychainItemCopyKeychain' and + * 'SecKeychainGetCSPHandle' */ +OSStatus +SecKeyGetCSPHandle( + SecKeyRef keyRef, + CSSM_CSP_HANDLE *cspHandle); + +typedef struct ckmkInternalCryptoOperationRSAPrivStr + ckmkInternalCryptoOperationRSAPriv; +struct ckmkInternalCryptoOperationRSAPrivStr { + NSSCKMDCryptoOperation mdOperation; + NSSCKMDMechanism *mdMechanism; + ckmkInternalObject *iKey; + NSSItem *buffer; + CSSM_CC_HANDLE cssmContext; +}; + +typedef enum { + CKMK_DECRYPT, + CKMK_SIGN +} ckmkRSAOpType; + +/* + * ckmk_mdCryptoOperationRSAPriv_Create + */ +static NSSCKMDCryptoOperation * +ckmk_mdCryptoOperationRSAPriv_Create( + const NSSCKMDCryptoOperation *proto, + NSSCKMDMechanism *mdMechanism, + NSSCKMDObject *mdKey, + ckmkRSAOpType type, + CK_RV *pError) +{ + ckmkInternalObject *iKey = (ckmkInternalObject *)mdKey->etc; + const NSSItem *classItem = nss_ckmk_FetchAttribute(iKey, CKA_CLASS, pError); + const NSSItem *keyType = nss_ckmk_FetchAttribute(iKey, CKA_KEY_TYPE, pError); + ckmkInternalCryptoOperationRSAPriv *iOperation; + SecKeyRef privateKey; + OSStatus macErr; + CSSM_RETURN cssmErr; + const CSSM_KEY *cssmKey; + CSSM_CSP_HANDLE cspHandle; + const CSSM_ACCESS_CREDENTIALS *creds = NULL; + CSSM_CC_HANDLE cssmContext; + CSSM_ACL_AUTHORIZATION_TAG authType; + + /* make sure we have the right objects */ + if (((const NSSItem *)NULL == classItem) || + (sizeof(CK_OBJECT_CLASS) != classItem->size) || + (CKO_PRIVATE_KEY != *(CK_OBJECT_CLASS *)classItem->data) || + ((const NSSItem *)NULL == keyType) || + (sizeof(CK_KEY_TYPE) != keyType->size) || + (CKK_RSA != *(CK_KEY_TYPE *)keyType->data)) { + *pError = CKR_KEY_TYPE_INCONSISTENT; + return (NSSCKMDCryptoOperation *)NULL; + } + + privateKey = (SecKeyRef)iKey->u.item.itemRef; + macErr = SecKeyGetCSSMKey(privateKey, &cssmKey); + if (noErr != macErr) { + CKMK_MACERR("Getting CSSM Key", macErr); + *pError = CKR_KEY_HANDLE_INVALID; + return (NSSCKMDCryptoOperation *)NULL; + } + macErr = SecKeyGetCSPHandle(privateKey, &cspHandle); + if (noErr != macErr) { + CKMK_MACERR("Getting CSP for Key", macErr); + *pError = CKR_KEY_HANDLE_INVALID; + return (NSSCKMDCryptoOperation *)NULL; + } + switch (type) { + case CKMK_DECRYPT: + authType = CSSM_ACL_AUTHORIZATION_DECRYPT; + break; + case CKMK_SIGN: + authType = CSSM_ACL_AUTHORIZATION_SIGN; + break; + default: + *pError = CKR_GENERAL_ERROR; +#ifdef DEBUG + fprintf(stderr, "RSAPriv_Create: bad type = %d\n", type); +#endif + return (NSSCKMDCryptoOperation *)NULL; + } + + macErr = SecKeyGetCredentials(privateKey, authType, 0, &creds); + if (noErr != macErr) { + CKMK_MACERR("Getting Credentials for Key", macErr); + *pError = CKR_KEY_HANDLE_INVALID; + return (NSSCKMDCryptoOperation *)NULL; + } + + switch (type) { + case CKMK_DECRYPT: + cssmErr = CSSM_CSP_CreateAsymmetricContext(cspHandle, CSSM_ALGID_RSA, + creds, cssmKey, CSSM_PADDING_PKCS1, &cssmContext); + break; + case CKMK_SIGN: + cssmErr = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA, + creds, cssmKey, &cssmContext); + break; + default: + *pError = CKR_GENERAL_ERROR; +#ifdef DEBUG + fprintf(stderr, "RSAPriv_Create: bad type = %d\n", type); +#endif + return (NSSCKMDCryptoOperation *)NULL; + } + if (noErr != cssmErr) { + CKMK_MACERR("Getting Context for Key", cssmErr); + *pError = CKR_GENERAL_ERROR; + return (NSSCKMDCryptoOperation *)NULL; + } + + iOperation = nss_ZNEW(NULL, ckmkInternalCryptoOperationRSAPriv); + if ((ckmkInternalCryptoOperationRSAPriv *)NULL == iOperation) { + *pError = CKR_HOST_MEMORY; + return (NSSCKMDCryptoOperation *)NULL; + } + iOperation->mdMechanism = mdMechanism; + iOperation->iKey = iKey; + iOperation->cssmContext = cssmContext; + + nsslibc_memcpy(&iOperation->mdOperation, + proto, sizeof(NSSCKMDCryptoOperation)); + iOperation->mdOperation.etc = iOperation; + + return &iOperation->mdOperation; +} + +static void +ckmk_mdCryptoOperationRSAPriv_Destroy( + NSSCKMDCryptoOperation *mdOperation, + NSSCKFWCryptoOperation *fwOperation, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + ckmkInternalCryptoOperationRSAPriv *iOperation = + (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc; + + if (iOperation->buffer) { + nssItem_Destroy(iOperation->buffer); + } + if (iOperation->cssmContext) { + CSSM_DeleteContext(iOperation->cssmContext); + } + nss_ZFreeIf(iOperation); + return; +} + +static CK_ULONG +ckmk_mdCryptoOperationRSA_GetFinalLength( + NSSCKMDCryptoOperation *mdOperation, + NSSCKFWCryptoOperation *fwOperation, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + ckmkInternalCryptoOperationRSAPriv *iOperation = + (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc; + const NSSItem *modulus = + nss_ckmk_FetchAttribute(iOperation->iKey, CKA_MODULUS, pError); + + return modulus->size; +} + +/* + * ckmk_mdCryptoOperationRSADecrypt_GetOperationLength + * we won't know the length until we actually decrypt the + * input block. Since we go to all the work to decrypt the + * the block, we'll save if for when the block is asked for + */ +static CK_ULONG +ckmk_mdCryptoOperationRSADecrypt_GetOperationLength( + NSSCKMDCryptoOperation *mdOperation, + NSSCKFWCryptoOperation *fwOperation, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + const NSSItem *input, + CK_RV *pError) +{ + ckmkInternalCryptoOperationRSAPriv *iOperation = + (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc; + CSSM_DATA cssmInput; + CSSM_DATA cssmOutput = { 0, NULL }; + PRUint32 bytesDecrypted; + CSSM_DATA remainder = { 0, NULL }; + NSSItem output; + CSSM_RETURN cssmErr; + + if (iOperation->buffer) { + return iOperation->buffer->size; + } + + cssmInput.Data = input->data; + cssmInput.Length = input->size; + + cssmErr = CSSM_DecryptData(iOperation->cssmContext, + &cssmInput, 1, &cssmOutput, 1, + &bytesDecrypted, &remainder); + if (CSSM_OK != cssmErr) { + CKMK_MACERR("Decrypt Failed", cssmErr); + *pError = CKR_DATA_INVALID; + return 0; + } + /* we didn't suppy any buffers, so it should all be in remainder */ + output.data = nss_ZNEWARRAY(NULL, char, bytesDecrypted + remainder.Length); + if (NULL == output.data) { + free(cssmOutput.Data); + free(remainder.Data); + *pError = CKR_HOST_MEMORY; + return 0; + } + output.size = bytesDecrypted + remainder.Length; + + if (0 != bytesDecrypted) { + nsslibc_memcpy(output.data, cssmOutput.Data, bytesDecrypted); + free(cssmOutput.Data); + } + if (0 != remainder.Length) { + nsslibc_memcpy(((char *)output.data) + bytesDecrypted, + remainder.Data, remainder.Length); + free(remainder.Data); + } + + iOperation->buffer = nssItem_Duplicate(&output, NULL, NULL); + nss_ZFreeIf(output.data); + if ((NSSItem *)NULL == iOperation->buffer) { + *pError = CKR_HOST_MEMORY; + return 0; + } + + return iOperation->buffer->size; +} + +/* + * ckmk_mdCryptoOperationRSADecrypt_UpdateFinal + * + * NOTE: ckmk_mdCryptoOperationRSADecrypt_GetOperationLength is presumed to + * have been called previously. + */ +static CK_RV +ckmk_mdCryptoOperationRSADecrypt_UpdateFinal( + NSSCKMDCryptoOperation *mdOperation, + NSSCKFWCryptoOperation *fwOperation, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + const NSSItem *input, + NSSItem *output) +{ + ckmkInternalCryptoOperationRSAPriv *iOperation = + (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc; + NSSItem *buffer = iOperation->buffer; + + if ((NSSItem *)NULL == buffer) { + return CKR_GENERAL_ERROR; + } + nsslibc_memcpy(output->data, buffer->data, buffer->size); + output->size = buffer->size; + return CKR_OK; +} + +/* + * ckmk_mdCryptoOperationRSASign_UpdateFinal + * + */ +static CK_RV +ckmk_mdCryptoOperationRSASign_UpdateFinal( + NSSCKMDCryptoOperation *mdOperation, + NSSCKFWCryptoOperation *fwOperation, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + const NSSItem *input, + NSSItem *output) +{ + ckmkInternalCryptoOperationRSAPriv *iOperation = + (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc; + CSSM_DATA cssmInput; + CSSM_DATA cssmOutput = { 0, NULL }; + CSSM_RETURN cssmErr; + + cssmInput.Data = input->data; + cssmInput.Length = input->size; + + cssmErr = CSSM_SignData(iOperation->cssmContext, &cssmInput, 1, + CSSM_ALGID_NONE, &cssmOutput); + if (CSSM_OK != cssmErr) { + CKMK_MACERR("Signed Failed", cssmErr); + return CKR_FUNCTION_FAILED; + } + if (cssmOutput.Length > output->size) { + free(cssmOutput.Data); + return CKR_BUFFER_TOO_SMALL; + } + nsslibc_memcpy(output->data, cssmOutput.Data, cssmOutput.Length); + free(cssmOutput.Data); + output->size = cssmOutput.Length; + + return CKR_OK; +} + +NSS_IMPLEMENT_DATA const NSSCKMDCryptoOperation + ckmk_mdCryptoOperationRSADecrypt_proto = { + NULL, /* etc */ + ckmk_mdCryptoOperationRSAPriv_Destroy, + NULL, /* GetFinalLengh - not needed for one shot Decrypt/Encrypt */ + ckmk_mdCryptoOperationRSADecrypt_GetOperationLength, + NULL, /* Final - not needed for one shot operation */ + NULL, /* Update - not needed for one shot operation */ + NULL, /* DigetUpdate - not needed for one shot operation */ + ckmk_mdCryptoOperationRSADecrypt_UpdateFinal, + NULL, /* UpdateCombo - not needed for one shot operation */ + NULL, /* DigetKey - not needed for one shot operation */ + (void *)NULL /* null terminator */ + }; + +NSS_IMPLEMENT_DATA const NSSCKMDCryptoOperation + ckmk_mdCryptoOperationRSASign_proto = { + NULL, /* etc */ + ckmk_mdCryptoOperationRSAPriv_Destroy, + ckmk_mdCryptoOperationRSA_GetFinalLength, + NULL, /* GetOperationLengh - not needed for one shot Sign/Verify */ + NULL, /* Final - not needed for one shot operation */ + NULL, /* Update - not needed for one shot operation */ + NULL, /* DigetUpdate - not needed for one shot operation */ + ckmk_mdCryptoOperationRSASign_UpdateFinal, + NULL, /* UpdateCombo - not needed for one shot operation */ + NULL, /* DigetKey - not needed for one shot operation */ + (void *)NULL /* null terminator */ + }; + +/********** NSSCKMDMechansim functions ***********************/ +/* + * ckmk_mdMechanismRSA_Destroy + */ +static void +ckmk_mdMechanismRSA_Destroy( + NSSCKMDMechanism *mdMechanism, + NSSCKFWMechanism *fwMechanism, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + nss_ZFreeIf(fwMechanism); +} + +/* + * ckmk_mdMechanismRSA_GetMinKeySize + */ +static CK_ULONG +ckmk_mdMechanismRSA_GetMinKeySize( + NSSCKMDMechanism *mdMechanism, + NSSCKFWMechanism *fwMechanism, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return 384; +} + +/* + * ckmk_mdMechanismRSA_GetMaxKeySize + */ +static CK_ULONG +ckmk_mdMechanismRSA_GetMaxKeySize( + NSSCKMDMechanism *mdMechanism, + NSSCKFWMechanism *fwMechanism, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return 16384; +} + +/* + * ckmk_mdMechanismRSA_DecryptInit + */ +static NSSCKMDCryptoOperation * +ckmk_mdMechanismRSA_DecryptInit( + NSSCKMDMechanism *mdMechanism, + NSSCKFWMechanism *fwMechanism, + CK_MECHANISM *pMechanism, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + NSSCKMDObject *mdKey, + NSSCKFWObject *fwKey, + CK_RV *pError) +{ + return ckmk_mdCryptoOperationRSAPriv_Create( + &ckmk_mdCryptoOperationRSADecrypt_proto, + mdMechanism, mdKey, CKMK_DECRYPT, pError); +} + +/* + * ckmk_mdMechanismRSA_SignInit + */ +static NSSCKMDCryptoOperation * +ckmk_mdMechanismRSA_SignInit( + NSSCKMDMechanism *mdMechanism, + NSSCKFWMechanism *fwMechanism, + CK_MECHANISM *pMechanism, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + NSSCKMDObject *mdKey, + NSSCKFWObject *fwKey, + CK_RV *pError) +{ + return ckmk_mdCryptoOperationRSAPriv_Create( + &ckmk_mdCryptoOperationRSASign_proto, + mdMechanism, mdKey, CKMK_SIGN, pError); +} + +NSS_IMPLEMENT_DATA const NSSCKMDMechanism + nss_ckmk_mdMechanismRSA = { + (void *)NULL, /* etc */ + ckmk_mdMechanismRSA_Destroy, + ckmk_mdMechanismRSA_GetMinKeySize, + ckmk_mdMechanismRSA_GetMaxKeySize, + NULL, /* GetInHardware - default false */ + NULL, /* EncryptInit - default errs */ + ckmk_mdMechanismRSA_DecryptInit, + NULL, /* DigestInit - default errs*/ + ckmk_mdMechanismRSA_SignInit, + NULL, /* VerifyInit - default errs */ + ckmk_mdMechanismRSA_SignInit, /* SignRecoverInit */ + NULL, /* VerifyRecoverInit - default errs */ + NULL, /* GenerateKey - default errs */ + NULL, /* GenerateKeyPair - default errs */ + NULL, /* GetWrapKeyLength - default errs */ + NULL, /* WrapKey - default errs */ + NULL, /* UnwrapKey - default errs */ + NULL, /* DeriveKey - default errs */ + (void *)NULL /* null terminator */ + }; diff --git a/security/nss/lib/ckfw/nssmkey/msession.c b/security/nss/lib/ckfw/nssmkey/msession.c new file mode 100644 index 000000000..e6a29244a --- /dev/null +++ b/security/nss/lib/ckfw/nssmkey/msession.c @@ -0,0 +1,87 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ckmk.h" + +/* + * nssmkey/msession.c + * + * This file implements the NSSCKMDSession object for the + * "nssmkey" cryptoki module. + */ + +static NSSCKMDFindObjects * +ckmk_mdSession_FindObjectsInit( + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + CK_RV *pError) +{ + return nss_ckmk_FindObjectsInit(fwSession, pTemplate, ulAttributeCount, pError); +} + +static NSSCKMDObject * +ckmk_mdSession_CreateObject( + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + NSSArena *arena, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + CK_RV *pError) +{ + return nss_ckmk_CreateObject(fwSession, pTemplate, ulAttributeCount, pError); +} + +NSS_IMPLEMENT NSSCKMDSession * +nss_ckmk_CreateSession( + NSSCKFWSession *fwSession, + CK_RV *pError) +{ + NSSArena *arena; + NSSCKMDSession *rv; + + arena = NSSCKFWSession_GetArena(fwSession, pError); + if ((NSSArena *)NULL == arena) { + return (NSSCKMDSession *)NULL; + } + + rv = nss_ZNEW(arena, NSSCKMDSession); + if ((NSSCKMDSession *)NULL == rv) { + *pError = CKR_HOST_MEMORY; + return (NSSCKMDSession *)NULL; + } + + /* + * rv was zeroed when allocated, so we only + * need to set the non-zero members. + */ + + rv->etc = (void *)fwSession; + /* rv->Close */ + /* rv->GetDeviceError */ + /* rv->Login */ + /* rv->Logout */ + /* rv->InitPIN */ + /* rv->SetPIN */ + /* rv->GetOperationStateLen */ + /* rv->GetOperationState */ + /* rv->SetOperationState */ + rv->CreateObject = ckmk_mdSession_CreateObject; + /* rv->CopyObject */ + rv->FindObjectsInit = ckmk_mdSession_FindObjectsInit; + /* rv->SeedRandom */ + /* rv->GetRandom */ + /* rv->null */ + + return rv; +} diff --git a/security/nss/lib/ckfw/nssmkey/mslot.c b/security/nss/lib/ckfw/nssmkey/mslot.c new file mode 100644 index 000000000..b2747ff7b --- /dev/null +++ b/security/nss/lib/ckfw/nssmkey/mslot.c @@ -0,0 +1,81 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ckmk.h" + +/* + * nssmkey/mslot.c + * + * This file implements the NSSCKMDSlot object for the + * "nssmkey" cryptoki module. + */ + +static NSSUTF8 * +ckmk_mdSlot_GetSlotDescription( + NSSCKMDSlot *mdSlot, + NSSCKFWSlot *fwSlot, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (NSSUTF8 *)nss_ckmk_SlotDescription; +} + +static NSSUTF8 * +ckmk_mdSlot_GetManufacturerID( + NSSCKMDSlot *mdSlot, + NSSCKFWSlot *fwSlot, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (NSSUTF8 *)nss_ckmk_ManufacturerID; +} + +static CK_VERSION +ckmk_mdSlot_GetHardwareVersion( + NSSCKMDSlot *mdSlot, + NSSCKFWSlot *fwSlot, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return nss_ckmk_HardwareVersion; +} + +static CK_VERSION +ckmk_mdSlot_GetFirmwareVersion( + NSSCKMDSlot *mdSlot, + NSSCKFWSlot *fwSlot, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return nss_ckmk_FirmwareVersion; +} + +static NSSCKMDToken * +ckmk_mdSlot_GetToken( + NSSCKMDSlot *mdSlot, + NSSCKFWSlot *fwSlot, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (NSSCKMDToken *)&nss_ckmk_mdToken; +} + +NSS_IMPLEMENT_DATA const NSSCKMDSlot + nss_ckmk_mdSlot = { + (void *)NULL, /* etc */ + NULL, /* Initialize */ + NULL, /* Destroy */ + ckmk_mdSlot_GetSlotDescription, + ckmk_mdSlot_GetManufacturerID, + NULL, /* GetTokenPresent -- defaults to true */ + NULL, /* GetRemovableDevice -- defaults to false */ + NULL, /* GetHardwareSlot -- defaults to false */ + ckmk_mdSlot_GetHardwareVersion, + ckmk_mdSlot_GetFirmwareVersion, + ckmk_mdSlot_GetToken, + (void *)NULL /* null terminator */ + }; diff --git a/security/nss/lib/ckfw/nssmkey/mtoken.c b/security/nss/lib/ckfw/nssmkey/mtoken.c new file mode 100644 index 000000000..e18d61240 --- /dev/null +++ b/security/nss/lib/ckfw/nssmkey/mtoken.c @@ -0,0 +1,184 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ckmk.h" + +/* + * nssmkey/mtoken.c + * + * This file implements the NSSCKMDToken object for the + * "nssmkey" cryptoki module. + */ + +static NSSUTF8 * +ckmk_mdToken_GetLabel( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (NSSUTF8 *)nss_ckmk_TokenLabel; +} + +static NSSUTF8 * +ckmk_mdToken_GetManufacturerID( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (NSSUTF8 *)nss_ckmk_ManufacturerID; +} + +static NSSUTF8 * +ckmk_mdToken_GetModel( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (NSSUTF8 *)nss_ckmk_TokenModel; +} + +static NSSUTF8 * +ckmk_mdToken_GetSerialNumber( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (NSSUTF8 *)nss_ckmk_TokenSerialNumber; +} + +static CK_BBOOL +ckmk_mdToken_GetIsWriteProtected( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return CK_FALSE; +} + +/* fake out Mozilla so we don't try to initialize the token */ +static CK_BBOOL +ckmk_mdToken_GetUserPinInitialized( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return CK_TRUE; +} + +static CK_VERSION +ckmk_mdToken_GetHardwareVersion( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return nss_ckmk_HardwareVersion; +} + +static CK_VERSION +ckmk_mdToken_GetFirmwareVersion( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return nss_ckmk_FirmwareVersion; +} + +static NSSCKMDSession * +ckmk_mdToken_OpenSession( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + NSSCKFWSession *fwSession, + CK_BBOOL rw, + CK_RV *pError) +{ + return nss_ckmk_CreateSession(fwSession, pError); +} + +static CK_ULONG +ckmk_mdToken_GetMechanismCount( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return (CK_ULONG)1; +} + +static CK_RV +ckmk_mdToken_GetMechanismTypes( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_MECHANISM_TYPE types[]) +{ + types[0] = CKM_RSA_PKCS; + return CKR_OK; +} + +static NSSCKMDMechanism * +ckmk_mdToken_GetMechanism( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_MECHANISM_TYPE which, + CK_RV *pError) +{ + if (which != CKM_RSA_PKCS) { + *pError = CKR_MECHANISM_INVALID; + return (NSSCKMDMechanism *)NULL; + } + return (NSSCKMDMechanism *)&nss_ckmk_mdMechanismRSA; +} + +NSS_IMPLEMENT_DATA const NSSCKMDToken + nss_ckmk_mdToken = { + (void *)NULL, /* etc */ + NULL, /* Setup */ + NULL, /* Invalidate */ + NULL, /* InitToken -- default errs */ + ckmk_mdToken_GetLabel, + ckmk_mdToken_GetManufacturerID, + ckmk_mdToken_GetModel, + ckmk_mdToken_GetSerialNumber, + NULL, /* GetHasRNG -- default is false */ + ckmk_mdToken_GetIsWriteProtected, + NULL, /* GetLoginRequired -- default is false */ + ckmk_mdToken_GetUserPinInitialized, + NULL, /* GetRestoreKeyNotNeeded -- irrelevant */ + NULL, /* GetHasClockOnToken -- default is false */ + NULL, /* GetHasProtectedAuthenticationPath -- default is false */ + NULL, /* GetSupportsDualCryptoOperations -- default is false */ + NULL, /* GetMaxSessionCount -- default is CK_UNAVAILABLE_INFORMATION */ + NULL, /* GetMaxRwSessionCount -- default is CK_UNAVAILABLE_INFORMATION */ + NULL, /* GetMaxPinLen -- irrelevant */ + NULL, /* GetMinPinLen -- irrelevant */ + NULL, /* GetTotalPublicMemory -- default is CK_UNAVAILABLE_INFORMATION */ + NULL, /* GetFreePublicMemory -- default is CK_UNAVAILABLE_INFORMATION */ + NULL, /* GetTotalPrivateMemory -- default is CK_UNAVAILABLE_INFORMATION */ + NULL, /* GetFreePrivateMemory -- default is CK_UNAVAILABLE_INFORMATION */ + ckmk_mdToken_GetHardwareVersion, + ckmk_mdToken_GetFirmwareVersion, + NULL, /* GetUTCTime -- no clock */ + ckmk_mdToken_OpenSession, + ckmk_mdToken_GetMechanismCount, + ckmk_mdToken_GetMechanismTypes, + ckmk_mdToken_GetMechanism, + (void *)NULL /* null terminator */ + }; diff --git a/security/nss/lib/ckfw/nssmkey/nssmkey.def b/security/nss/lib/ckfw/nssmkey/nssmkey.def new file mode 100644 index 000000000..45d307ff0 --- /dev/null +++ b/security/nss/lib/ckfw/nssmkey/nssmkey.def @@ -0,0 +1,26 @@ +;+# +;+# This Source Code Form is subject to the terms of the Mozilla Public +;+# License, v. 2.0. If a copy of the MPL was not distributed with this +;+# file, You can obtain one at http://mozilla.org/MPL/2.0/. +;+# +;+# OK, this file is meant to support SUN, LINUX, AIX and WINDOWS +;+# 1. For all unix platforms, the string ";-" means "remove this line" +;+# 2. For all unix platforms, the string " DATA " will be removed from any +;+# line on which it occurs. +;+# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX. +;+# On AIX, lines containing ";+" will be removed. +;+# 4. For all unix platforms, the string ";;" will thave the ";;" removed. +;+# 5. For all unix platforms, after the above processing has taken place, +;+# all characters after the first ";" on the line will be removed. +;+# And for AIX, the first ";" will also be removed. +;+# This file is passed directly to windows. Since ';' is a comment, all UNIX +;+# directives are hidden behind ";", ";+", and ";-" +;+ +;+NSSMKEY_3.0 { # First release of nssmkey +;+ global: +LIBRARY nssmkey ;- +EXPORTS ;- +C_GetFunctionList; +;+ local: +;+*; +;+}; diff --git a/security/nss/lib/ckfw/nssmkey/nssmkey.h b/security/nss/lib/ckfw/nssmkey/nssmkey.h new file mode 100644 index 000000000..ba58233e6 --- /dev/null +++ b/security/nss/lib/ckfw/nssmkey/nssmkey.h @@ -0,0 +1,41 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NSSMKEY_H +#define NSSMKEY_H + +/* + * NSS CKMK Version numbers. + * + * These are the version numbers for the nssmkey module packaged with + * this release on NSS. To determine the version numbers of the builtin + * module you are using, use the appropriate PKCS #11 calls. + * + * These version numbers detail changes to the PKCS #11 interface. They map + * to the PKCS #11 spec versions. + */ +#define NSS_CKMK_CRYPTOKI_VERSION_MAJOR 2 +#define NSS_CKMK_CRYPTOKI_VERSION_MINOR 20 + +/* These version numbers detail the changes + * to the list of trusted certificates. + * + * NSS_CKMK_LIBRARY_VERSION_MINOR is a CK_BYTE. It's not clear + * whether we may use its full range (0-255) or only 0-99 because + * of the comment in the CK_VERSION type definition. + */ +#define NSS_CKMK_LIBRARY_VERSION_MAJOR 1 +#define NSS_CKMK_LIBRARY_VERSION_MINOR 1 +#define NSS_CKMK_LIBRARY_VERSION "1.1" + +/* These version numbers detail the semantic changes to the ckfw engine. */ +#define NSS_CKMK_HARDWARE_VERSION_MAJOR 1 +#define NSS_CKMK_HARDWARE_VERSION_MINOR 0 + +/* These version numbers detail the semantic changes to ckbi itself + * (new PKCS #11 objects), etc. */ +#define NSS_CKMK_FIRMWARE_VERSION_MAJOR 1 +#define NSS_CKMK_FIRMWARE_VERSION_MINOR 0 + +#endif /* NSSMKEY_H */ diff --git a/security/nss/lib/ckfw/nssmkey/staticobj.c b/security/nss/lib/ckfw/nssmkey/staticobj.c new file mode 100644 index 000000000..5f3bb7c72 --- /dev/null +++ b/security/nss/lib/ckfw/nssmkey/staticobj.c @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef CKMK_H +#include "ckmk.h" +#endif /* CKMK_H */ + +static const CK_TRUST ckt_netscape_valid = CKT_NETSCAPE_VALID; +static const CK_OBJECT_CLASS cko_certificate = CKO_CERTIFICATE; +static const CK_TRUST ckt_netscape_trusted_delegator = CKT_NETSCAPE_TRUSTED_DELEGATOR; +static const CK_OBJECT_CLASS cko_netscape_trust = CKO_NETSCAPE_TRUST; +static const CK_BBOOL ck_true = CK_TRUE; +static const CK_OBJECT_CLASS cko_data = CKO_DATA; +static const CK_CERTIFICATE_TYPE ckc_x_509 = CKC_X_509; +static const CK_BBOOL ck_false = CK_FALSE; +static const CK_OBJECT_CLASS cko_netscape_builtin_root_list = CKO_NETSCAPE_BUILTIN_ROOT_LIST; + +/* example of a static object */ +static const CK_ATTRIBUTE_TYPE nss_ckmk_types_1[] = { + CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_MODIFIABLE, CKA_LABEL +}; + +static const NSSItem nss_ckmk_items_1[] = { + { (void *)&cko_data, (PRUint32)sizeof(CK_OBJECT_CLASS) }, + { (void *)&ck_true, (PRUint32)sizeof(CK_BBOOL) }, + { (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL) }, + { (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL) }, + { (void *)"Mozilla Mac Key Ring Access", (PRUint32)28 } +}; + +ckmkInternalObject nss_ckmk_data[] = { + { ckmkRaw, { { 5, nss_ckmk_types_1, nss_ckmk_items_1 } }, CKO_DATA, { NULL } }, +}; + +const PRUint32 nss_ckmk_nObjects = 1; |