From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- security/nss/lib/ckfw/capi/Makefile | 82 ++ security/nss/lib/ckfw/capi/README | 7 + security/nss/lib/ckfw/capi/anchor.c | 17 + security/nss/lib/ckfw/capi/cfind.c | 561 ++++++++ security/nss/lib/ckfw/capi/cinst.c | 97 ++ security/nss/lib/ckfw/capi/ckcapi.h | 242 ++++ security/nss/lib/ckfw/capi/ckcapiver.c | 17 + security/nss/lib/ckfw/capi/cobject.c | 2226 ++++++++++++++++++++++++++++++++ security/nss/lib/ckfw/capi/constants.c | 63 + security/nss/lib/ckfw/capi/crsa.c | 687 ++++++++++ security/nss/lib/ckfw/capi/csession.c | 87 ++ security/nss/lib/ckfw/capi/cslot.c | 81 ++ security/nss/lib/ckfw/capi/ctoken.c | 184 +++ security/nss/lib/ckfw/capi/manifest.mn | 35 + security/nss/lib/ckfw/capi/nsscapi.def | 26 + security/nss/lib/ckfw/capi/nsscapi.h | 41 + security/nss/lib/ckfw/capi/nsscapi.rc | 64 + security/nss/lib/ckfw/capi/staticobj.c | 40 + 18 files changed, 4557 insertions(+) create mode 100644 security/nss/lib/ckfw/capi/Makefile create mode 100644 security/nss/lib/ckfw/capi/README create mode 100644 security/nss/lib/ckfw/capi/anchor.c create mode 100644 security/nss/lib/ckfw/capi/cfind.c create mode 100644 security/nss/lib/ckfw/capi/cinst.c create mode 100644 security/nss/lib/ckfw/capi/ckcapi.h create mode 100644 security/nss/lib/ckfw/capi/ckcapiver.c create mode 100644 security/nss/lib/ckfw/capi/cobject.c create mode 100644 security/nss/lib/ckfw/capi/constants.c create mode 100644 security/nss/lib/ckfw/capi/crsa.c create mode 100644 security/nss/lib/ckfw/capi/csession.c create mode 100644 security/nss/lib/ckfw/capi/cslot.c create mode 100644 security/nss/lib/ckfw/capi/ctoken.c create mode 100644 security/nss/lib/ckfw/capi/manifest.mn create mode 100644 security/nss/lib/ckfw/capi/nsscapi.def create mode 100644 security/nss/lib/ckfw/capi/nsscapi.h create mode 100644 security/nss/lib/ckfw/capi/nsscapi.rc create mode 100644 security/nss/lib/ckfw/capi/staticobj.c (limited to 'security/nss/lib/ckfw/capi') diff --git a/security/nss/lib/ckfw/capi/Makefile b/security/nss/lib/ckfw/capi/Makefile new file mode 100644 index 0000000000..3949d18e29 --- /dev/null +++ b/security/nss/lib/ckfw/capi/Makefile @@ -0,0 +1,82 @@ +# +# 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 + +ifdef BUILD_IDG +DEFINES += -DNSSDEBUG +endif + +# +# To create a loadable module on Darwin, we must use -bundle. +# +ifeq ($(OS_TARGET),Darwin) +DSO_LDOPTS = -bundle +endif + +EXTRA_LIBS = \ + $(DIST)/lib/$(LIB_PREFIX)nssckfw.$(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 \ + -lcrypt32 \ + -ladvapi32 \ + -lrpcrt4 \ + $(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 \ + crypt32.lib \ + advapi32.lib \ + rpcrt4.lib \ + $(NULL) +endif # NS_USE_GCC +else + +EXTRA_LIBS += \ + -L$(NSPR_LIB_DIR) \ + -lplc4 \ + -lplds4 \ + -lnspr4 \ + $(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) | $$(@D)/d + 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/capi/README b/security/nss/lib/ckfw/capi/README new file mode 100644 index 0000000000..9fc5720a9c --- /dev/null +++ b/security/nss/lib/ckfw/capi/README @@ -0,0 +1,7 @@ +This Cryptoki module provides acces to certs and keys stored in +Microsofts CAPI certificate store. + +It does not import or export CA Root trust from the CAPI. +It does not import or export CRLs from the CAPI. +It does not handle S/MIME objects (pkcs #7 in capi terms?). +It does not yet handle it's own PIN. (CAPI does all the pin prompting). diff --git a/security/nss/lib/ckfw/capi/anchor.c b/security/nss/lib/ckfw/capi/anchor.c new file mode 100644 index 0000000000..2d1523e4c2 --- /dev/null +++ b/security/nss/lib/ckfw/capi/anchor.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/. */ + +/* + * capi/canchor.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 "ckcapi.h" + +#define MODULE_NAME ckcapi +#define INSTANCE_NAME (NSSCKMDInstance *)&nss_ckcapi_mdInstance +#include "nssck.api" diff --git a/security/nss/lib/ckfw/capi/cfind.c b/security/nss/lib/ckfw/capi/cfind.c new file mode 100644 index 0000000000..9c4d4f1e77 --- /dev/null +++ b/security/nss/lib/ckfw/capi/cfind.c @@ -0,0 +1,561 @@ +/* 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 CKCAPI_H +#include "ckcapi.h" +#endif /* CKCAPI_H */ + +/* + * ckcapi/cfind.c + * + * This file implements the NSSCKMDFindObjects object for the + * "capi" cryptoki module. + */ + +struct ckcapiFOStr { + NSSArena *arena; + CK_ULONG n; + CK_ULONG i; + ckcapiInternalObject **objs; +}; + +static void +ckcapi_mdFindObjects_Final( + NSSCKMDFindObjects *mdFindObjects, + NSSCKFWFindObjects *fwFindObjects, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + struct ckcapiFOStr *fo = (struct ckcapiFOStr *)mdFindObjects->etc; + NSSArena *arena = fo->arena; + PRUint32 i; + + /* walk down an free the unused 'objs' */ + for (i = fo->i; i < fo->n; i++) { + nss_ckcapi_DestroyInternalObject(fo->objs[i]); + } + + nss_ZFreeIf(fo->objs); + nss_ZFreeIf(fo); + nss_ZFreeIf(mdFindObjects); + if ((NSSArena *)NULL != arena) { + NSSArena_Destroy(arena); + } + + return; +} + +static NSSCKMDObject * +ckcapi_mdFindObjects_Next( + NSSCKMDFindObjects *mdFindObjects, + NSSCKFWFindObjects *fwFindObjects, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + NSSArena *arena, + CK_RV *pError) +{ + struct ckcapiFOStr *fo = (struct ckcapiFOStr *)mdFindObjects->etc; + ckcapiInternalObject *io; + + if (fo->i == fo->n) { + *pError = CKR_OK; + return (NSSCKMDObject *)NULL; + } + + io = fo->objs[fo->i]; + fo->i++; + + return nss_ckcapi_CreateMDObject(arena, io, pError); +} + +static CK_BBOOL +ckcapi_attrmatch( + CK_ATTRIBUTE_PTR a, + ckcapiInternalObject *o) +{ + PRBool prb; + const NSSItem *b; + + b = nss_ckcapi_FetchAttribute(o, a->type); + 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)) { + unsigned int len; + unsigned char *data; + + data = nss_ckcapi_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 +ckcapi_match( + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + ckcapiInternalObject *o) +{ + CK_ULONG i; + + for (i = 0; i < ulAttributeCount; i++) { + if (CK_FALSE == ckcapi_attrmatch(&pTemplate[i], o)) { + return CK_FALSE; + } + } + + /* Every attribute passed */ + return CK_TRUE; +} + +#define CKAPI_ITEM_CHUNK 20 + +#define PUT_Object(obj, err) \ + { \ + if (count >= size) { \ + *listp = *listp ? nss_ZREALLOCARRAY(*listp, ckcapiInternalObject *, \ + (size + \ + CKAPI_ITEM_CHUNK)) \ + : nss_ZNEWARRAY(NULL, ckcapiInternalObject *, \ + (size + \ + CKAPI_ITEM_CHUNK)); \ + if ((ckcapiInternalObject **)NULL == *listp) { \ + err = CKR_HOST_MEMORY; \ + goto loser; \ + } \ + size += CKAPI_ITEM_CHUNK; \ + } \ + (*listp)[count] = (obj); \ + count++; \ + } + +/* + * pass parameters back through the callback. + */ +typedef struct BareCollectParamsStr { + CK_OBJECT_CLASS objClass; + CK_ATTRIBUTE_PTR pTemplate; + CK_ULONG ulAttributeCount; + ckcapiInternalObject ***listp; + PRUint32 size; + PRUint32 count; +} BareCollectParams; + +/* collect_bare's callback. Called for each object that + * supposedly has a PROVINDER_INFO property */ +static BOOL WINAPI +doBareCollect( + const CRYPT_HASH_BLOB *msKeyID, + DWORD flags, + void *reserved, + void *args, + DWORD cProp, + DWORD *propID, + void **propData, + DWORD *propSize) +{ + BareCollectParams *bcp = (BareCollectParams *)args; + PRUint32 size = bcp->size; + PRUint32 count = bcp->count; + ckcapiInternalObject ***listp = bcp->listp; + ckcapiInternalObject *io = NULL; + DWORD i; + CRYPT_KEY_PROV_INFO *keyProvInfo = NULL; + void *idData; + CK_RV error; + + /* make sure there is a Key Provider Info property */ + for (i = 0; i < cProp; i++) { + if (CERT_KEY_PROV_INFO_PROP_ID == propID[i]) { + keyProvInfo = (CRYPT_KEY_PROV_INFO *)propData[i]; + break; + } + } + if ((CRYPT_KEY_PROV_INFO *)NULL == keyProvInfo) { + return 1; + } + + /* copy the key ID */ + idData = nss_ZNEWARRAY(NULL, char, msKeyID->cbData); + if ((void *)NULL == idData) { + goto loser; + } + nsslibc_memcpy(idData, msKeyID->pbData, msKeyID->cbData); + + /* build a bare internal object */ + io = nss_ZNEW(NULL, ckcapiInternalObject); + if ((ckcapiInternalObject *)NULL == io) { + goto loser; + } + io->type = ckcapiBareKey; + io->objClass = bcp->objClass; + io->u.key.provInfo = *keyProvInfo; + io->u.key.provInfo.pwszContainerName = + nss_ckcapi_WideDup(keyProvInfo->pwszContainerName); + io->u.key.provInfo.pwszProvName = + nss_ckcapi_WideDup(keyProvInfo->pwszProvName); + io->u.key.provName = nss_ckcapi_WideToUTF8(keyProvInfo->pwszProvName); + io->u.key.containerName = + nss_ckcapi_WideToUTF8(keyProvInfo->pwszContainerName); + io->u.key.hProv = 0; + io->idData = idData; + io->id.data = idData; + io->id.size = msKeyID->cbData; + idData = NULL; + + /* see if it matches */ + if (CK_FALSE == ckcapi_match(bcp->pTemplate, bcp->ulAttributeCount, io)) { + goto loser; + } + PUT_Object(io, error); + bcp->size = size; + bcp->count = count; + return 1; + +loser: + if (io) { + nss_ckcapi_DestroyInternalObject(io); + } + nss_ZFreeIf(idData); + return 1; +} + +/* + * collect the bare keys running around + */ +static PRUint32 +collect_bare( + CK_OBJECT_CLASS objClass, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + ckcapiInternalObject ***listp, + PRUint32 *sizep, + PRUint32 count, + CK_RV *pError) +{ + BOOL rc; + BareCollectParams bareCollectParams; + + bareCollectParams.objClass = objClass; + bareCollectParams.pTemplate = pTemplate; + bareCollectParams.ulAttributeCount = ulAttributeCount; + bareCollectParams.listp = listp; + bareCollectParams.size = *sizep; + bareCollectParams.count = count; + + rc = CryptEnumKeyIdentifierProperties(NULL, CERT_KEY_PROV_INFO_PROP_ID, 0, + NULL, NULL, &bareCollectParams, doBareCollect); + + *sizep = bareCollectParams.size; + return bareCollectParams.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, + LPCSTR storeStr, + PRBool hasID, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + ckcapiInternalObject ***listp, + PRUint32 *sizep, + PRUint32 count, + CK_RV *pError) +{ + PRUint32 size = *sizep; + ckcapiInternalObject *next = NULL; + HCERTSTORE hStore; + PCCERT_CONTEXT certContext = NULL; + PRBool isKey = + (objClass == CKO_PUBLIC_KEY) | (objClass == CKO_PRIVATE_KEY); + + hStore = CertOpenSystemStore((HCRYPTPROV)NULL, storeStr); + if (NULL == hStore) { + return count; /* none found does not imply an error */ + } + + /* FUTURE: use CertFindCertificateInStore to filter better -- so we don't + * have to enumerate all the certificates */ + while ((PCERT_CONTEXT)NULL != + (certContext = CertEnumCertificatesInStore(hStore, certContext))) { + /* first filter out non user certs if we are looking for keys */ + if (isKey) { + /* make sure there is a Key Provider Info property */ + CRYPT_KEY_PROV_INFO *keyProvInfo; + DWORD size = 0; + BOOL rv; + rv = CertGetCertificateContextProperty(certContext, + CERT_KEY_PROV_INFO_PROP_ID, NULL, &size); + if (!rv) { + int reason = GetLastError(); + /* we only care if it exists, we don't really need to fetch it yet */ + if (reason == CRYPT_E_NOT_FOUND) { + continue; + } + } + /* filter out the non-microsoft providers */ + keyProvInfo = (CRYPT_KEY_PROV_INFO *)nss_ZAlloc(NULL, size); + if (keyProvInfo) { + rv = CertGetCertificateContextProperty(certContext, + CERT_KEY_PROV_INFO_PROP_ID, keyProvInfo, &size); + if (rv) { + char *provName = + nss_ckcapi_WideToUTF8(keyProvInfo->pwszProvName); + nss_ZFreeIf(keyProvInfo); + + if (provName && + (strncmp(provName, "Microsoft", sizeof("Microsoft") - 1) != 0)) { + continue; + } + } else { + int reason = + GetLastError(); + /* we only care if it exists, we don't really need to fetch it yet */ + nss_ZFreeIf(keyProvInfo); + if (reason == + CRYPT_E_NOT_FOUND) { + continue; + } + } + } + } + + if ((ckcapiInternalObject *)NULL == next) { + next = nss_ZNEW(NULL, ckcapiInternalObject); + if ((ckcapiInternalObject *)NULL == next) { + *pError = CKR_HOST_MEMORY; + goto loser; + } + } + next->type = ckcapiCert; + next->objClass = objClass; + next->u.cert.certContext = certContext; + next->u.cert.hasID = hasID; + next->u.cert.certStore = storeStr; + if (CK_TRUE == ckcapi_match(pTemplate, ulAttributeCount, next)) { + /* clear cached values that may be dependent on our old certContext */ + memset(&next->u.cert, 0, sizeof(next->u.cert)); + /* get a 'permanent' context */ + next->u.cert.certContext = CertDuplicateCertificateContext(certContext); + next->objClass = objClass; + next->u.cert.certContext = certContext; + next->u.cert.hasID = hasID; + next->u.cert.certStore = storeStr; + PUT_Object(next, *pError); + next = NULL; /* need to allocate a new one now */ + } else { + /* don't cache the values we just loaded */ + memset(&next->u.cert, 0, sizeof(next->u.cert)); + } + } +loser: + CertCloseStore(hStore, 0); + nss_ZFreeIf(next); + *sizep = size; + return count; +} + +NSS_IMPLEMENT PRUint32 +nss_ckcapi_collect_all_certs( + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + ckcapiInternalObject ***listp, + PRUint32 *sizep, + PRUint32 count, + CK_RV *pError) +{ + count = collect_class(CKO_CERTIFICATE, "My", PR_TRUE, pTemplate, + ulAttributeCount, listp, sizep, count, pError); + /*count = collect_class(CKO_CERTIFICATE, "AddressBook", PR_FALSE, pTemplate, + ulAttributeCount, listp, sizep, count, pError); */ + count = collect_class(CKO_CERTIFICATE, "CA", PR_FALSE, pTemplate, + ulAttributeCount, listp, sizep, count, pError); + count = collect_class(CKO_CERTIFICATE, "Root", PR_FALSE, pTemplate, + ulAttributeCount, listp, sizep, count, pError); + count = collect_class(CKO_CERTIFICATE, "Trust", PR_FALSE, pTemplate, + ulAttributeCount, listp, sizep, count, pError); + count = collect_class(CKO_CERTIFICATE, "TrustedPeople", PR_FALSE, pTemplate, + ulAttributeCount, listp, sizep, count, pError); + count = collect_class(CKO_CERTIFICATE, "AuthRoot", PR_FALSE, pTemplate, + ulAttributeCount, listp, sizep, count, pError); + return count; +} + +CK_OBJECT_CLASS +ckcapi_GetObjectClass(CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount) +{ + CK_ULONG i; + + for (i = 0; i < ulAttributeCount; i++) { + if (pTemplate[i].type == CKA_CLASS) { + return *(CK_OBJECT_CLASS *)pTemplate[i].pValue; + } + } + /* need to return a value that says 'fetch them all' */ + return CK_INVALID_HANDLE; +} + +static PRUint32 +collect_objects( + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + ckcapiInternalObject ***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_ckcapi_nObjects; i++) { + ckcapiInternalObject *o = (ckcapiInternalObject *)&nss_ckcapi_data[i]; + + if (CK_TRUE == ckcapi_match(pTemplate, ulAttributeCount, o)) { + PUT_Object(o, *pError); + } + } + + /* + * now handle the various object types + */ + objClass = ckcapi_GetObjectClass(pTemplate, ulAttributeCount); + *pError = CKR_OK; + switch (objClass) { + case CKO_CERTIFICATE: + count = nss_ckcapi_collect_all_certs(pTemplate, ulAttributeCount, listp, + &size, count, pError); + break; + case CKO_PUBLIC_KEY: + count = collect_class(objClass, "My", PR_TRUE, pTemplate, + ulAttributeCount, listp, &size, count, pError); + count = collect_bare(objClass, pTemplate, ulAttributeCount, listp, + &size, count, pError); + break; + case CKO_PRIVATE_KEY: + count = collect_class(objClass, "My", PR_TRUE, pTemplate, + ulAttributeCount, listp, &size, count, pError); + count = collect_bare(objClass, pTemplate, ulAttributeCount, listp, + &size, count, pError); + break; + /* all of them */ + case CK_INVALID_HANDLE: + count = nss_ckcapi_collect_all_certs(pTemplate, ulAttributeCount, listp, + &size, count, pError); + count = collect_class(CKO_PUBLIC_KEY, "My", PR_TRUE, pTemplate, + ulAttributeCount, listp, &size, count, pError); + count = collect_bare(CKO_PUBLIC_KEY, pTemplate, ulAttributeCount, listp, + &size, count, pError); + count = collect_class(CKO_PRIVATE_KEY, "My", PR_TRUE, pTemplate, + ulAttributeCount, listp, &size, count, pError); + count = collect_bare(CKO_PRIVATE_KEY, pTemplate, ulAttributeCount, listp, + &size, count, pError); + break; + default: + goto done; /* no other object types we understand in this module */ + } + if (CKR_OK != *pError) { + goto loser; + } + +done: + return count; +loser: + nss_ZFreeIf(*listp); + return 0; +} + +NSS_IMPLEMENT NSSCKMDFindObjects * +nss_ckcapi_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 ckcapiFOStr *fo = (struct ckcapiFOStr *)NULL; + ckcapiInternalObject **temp = (ckcapiInternalObject **)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 ckcapiFOStr); + if ((struct ckcapiFOStr *)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 = ckcapi_mdFindObjects_Final; + rv->Next = ckcapi_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, ckcapiInternalObject *, fo->n); + if ((ckcapiInternalObject **)NULL == fo->objs) { + *pError = CKR_HOST_MEMORY; + goto loser; + } + + (void)nsslibc_memcpy(fo->objs, temp, sizeof(ckcapiInternalObject *) * fo->n); + nss_ZFreeIf(temp); + temp = (ckcapiInternalObject **)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/capi/cinst.c b/security/nss/lib/ckfw/capi/cinst.c new file mode 100644 index 0000000000..937c289a19 --- /dev/null +++ b/security/nss/lib/ckfw/capi/cinst.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 "ckcapi.h" + +/* + * ckcapi/cinstance.c + * + * This file implements the NSSCKMDInstance object for the + * "capi" cryptoki module. + */ + +/* + * NSSCKMDInstance methods + */ + +static CK_ULONG +ckcapi_mdInstance_GetNSlots( + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (CK_ULONG)1; +} + +static CK_VERSION +ckcapi_mdInstance_GetCryptokiVersion( + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return nss_ckcapi_CryptokiVersion; +} + +static NSSUTF8 * +ckcapi_mdInstance_GetManufacturerID( + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (NSSUTF8 *)nss_ckcapi_ManufacturerID; +} + +static NSSUTF8 * +ckcapi_mdInstance_GetLibraryDescription( + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (NSSUTF8 *)nss_ckcapi_LibraryDescription; +} + +static CK_VERSION +ckcapi_mdInstance_GetLibraryVersion( + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return nss_ckcapi_LibraryVersion; +} + +static CK_RV +ckcapi_mdInstance_GetSlots( + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + NSSCKMDSlot *slots[]) +{ + slots[0] = (NSSCKMDSlot *)&nss_ckcapi_mdSlot; + return CKR_OK; +} + +static CK_BBOOL +ckcapi_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_ckcapi_mdInstance = { + (void *)NULL, /* etc */ + NULL, /* Initialize */ + NULL, /* Finalize */ + ckcapi_mdInstance_GetNSlots, + ckcapi_mdInstance_GetCryptokiVersion, + ckcapi_mdInstance_GetManufacturerID, + ckcapi_mdInstance_GetLibraryDescription, + ckcapi_mdInstance_GetLibraryVersion, + ckcapi_mdInstance_ModuleHandlesSessionObjects, + /*NULL, /* HandleSessionObjects */ + ckcapi_mdInstance_GetSlots, + NULL, /* WaitForSlotEvent */ + (void *)NULL /* null terminator */ + }; diff --git a/security/nss/lib/ckfw/capi/ckcapi.h b/security/nss/lib/ckfw/capi/ckcapi.h new file mode 100644 index 0000000000..2c4b12aac3 --- /dev/null +++ b/security/nss/lib/ckfw/capi/ckcapi.h @@ -0,0 +1,242 @@ +/* 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 CKCAPI_H +#define CKCAPI_H 1 + +#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 */ + +#include "wtypes.h" +#include "wincrypt.h" + +/* + * statically defined raw objects. Allows us to data description objects + * to this PKCS #11 module. + */ +struct ckcapiRawObjectStr { + CK_ULONG n; + const CK_ATTRIBUTE_TYPE *types; + const NSSItem *items; +}; +typedef struct ckcapiRawObjectStr ckcapiRawObject; + +/* + * common values needed for both bare keys and cert referenced keys. + */ +struct ckcapiKeyParamsStr { + NSSItem modulus; + NSSItem exponent; + NSSItem privateExponent; + NSSItem prime1; + NSSItem prime2; + NSSItem exponent1; + NSSItem exponent2; + NSSItem coefficient; + unsigned char publicExponentData[sizeof(CK_ULONG)]; + void *privateKey; + void *pubKey; +}; +typedef struct ckcapiKeyParamsStr ckcapiKeyParams; + +/* + * Key objects. Handles bare keys which do not yet have certs associated + * with them. These are usually short lived, but may exist for several days + * while the CA is issuing the certificate. + */ +struct ckcapiKeyObjectStr { + CRYPT_KEY_PROV_INFO provInfo; + char *provName; + char *containerName; + HCRYPTPROV hProv; + ckcapiKeyParams key; +}; +typedef struct ckcapiKeyObjectStr ckcapiKeyObject; + +/* + * Certificate and certificate referenced keys. + */ +struct ckcapiCertObjectStr { + PCCERT_CONTEXT certContext; + PRBool hasID; + const char *certStore; + NSSItem label; + NSSItem subject; + NSSItem issuer; + NSSItem serial; + NSSItem derCert; + ckcapiKeyParams key; + unsigned char *labelData; + /* static data: to do, make this dynamic like labelData */ + unsigned char derSerial[128]; +}; +typedef struct ckcapiCertObjectStr ckcapiCertObject; + +typedef enum { + ckcapiRaw, + ckcapiCert, + ckcapiBareKey +} ckcapiObjectType; + +/* + * all the various types of objects are abstracted away in cobject and + * cfind as ckcapiInternalObjects. + */ +struct ckcapiInternalObjectStr { + ckcapiObjectType type; + union { + ckcapiRawObject raw; + ckcapiCertObject cert; + ckcapiKeyObject key; + } u; + CK_OBJECT_CLASS objClass; + NSSItem hashKey; + NSSItem id; + void *idData; + unsigned char hashKeyData[128]; + NSSCKMDObject mdObject; +}; +typedef struct ckcapiInternalObjectStr ckcapiInternalObject; + +/* our raw object data array */ +NSS_EXTERN_DATA ckcapiInternalObject nss_ckcapi_data[]; +NSS_EXTERN_DATA const PRUint32 nss_ckcapi_nObjects; + +NSS_EXTERN_DATA const CK_VERSION nss_ckcapi_CryptokiVersion; +NSS_EXTERN_DATA const NSSUTF8 *nss_ckcapi_ManufacturerID; +NSS_EXTERN_DATA const NSSUTF8 *nss_ckcapi_LibraryDescription; +NSS_EXTERN_DATA const CK_VERSION nss_ckcapi_LibraryVersion; +NSS_EXTERN_DATA const NSSUTF8 *nss_ckcapi_SlotDescription; +NSS_EXTERN_DATA const CK_VERSION nss_ckcapi_HardwareVersion; +NSS_EXTERN_DATA const CK_VERSION nss_ckcapi_FirmwareVersion; +NSS_EXTERN_DATA const NSSUTF8 *nss_ckcapi_TokenLabel; +NSS_EXTERN_DATA const NSSUTF8 *nss_ckcapi_TokenModel; +NSS_EXTERN_DATA const NSSUTF8 *nss_ckcapi_TokenSerialNumber; + +NSS_EXTERN_DATA const NSSCKMDInstance nss_ckcapi_mdInstance; +NSS_EXTERN_DATA const NSSCKMDSlot nss_ckcapi_mdSlot; +NSS_EXTERN_DATA const NSSCKMDToken nss_ckcapi_mdToken; +NSS_EXTERN_DATA const NSSCKMDMechanism nss_ckcapi_mdMechanismRSA; + +NSS_EXTERN NSSCKMDSession * +nss_ckcapi_CreateSession( + NSSCKFWSession *fwSession, + CK_RV *pError); + +NSS_EXTERN NSSCKMDFindObjects * +nss_ckcapi_FindObjectsInit( + NSSCKFWSession *fwSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + CK_RV *pError); + +/* + * Object Utilities + */ +NSS_EXTERN NSSCKMDObject * +nss_ckcapi_CreateMDObject( + NSSArena *arena, + ckcapiInternalObject *io, + CK_RV *pError); + +NSS_EXTERN NSSCKMDObject * +nss_ckcapi_CreateObject( + NSSCKFWSession *fwSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + CK_RV *pError); + +NSS_EXTERN const NSSItem * +nss_ckcapi_FetchAttribute( + ckcapiInternalObject *io, + CK_ATTRIBUTE_TYPE type); + +NSS_EXTERN void +nss_ckcapi_DestroyInternalObject( + ckcapiInternalObject *io); + +NSS_EXTERN CK_RV +nss_ckcapi_FetchKeyContainer( + ckcapiInternalObject *iKey, + HCRYPTPROV *hProv, + DWORD *keySpec, + HCRYPTKEY *hKey); + +/* + * generic utilities + */ + +/* + * So everyone else in the worlds stores their bignum data MSB first, but not + * Microsoft, we need to byte swap everything coming into and out of CAPI. + */ +void +ckcapi_ReverseData( + NSSItem *item); + +/* + * unwrap a single DER value + */ +unsigned char * +nss_ckcapi_DERUnwrap( + unsigned char *src, + unsigned int size, + unsigned int *outSize, + unsigned char **next); + +/* + * Return the size in bytes of a wide string + */ +int +nss_ckcapi_WideSize( + LPCWSTR wide); + +/* + * Covert a Unicode wide character string to a UTF8 string + */ +char * +nss_ckcapi_WideToUTF8( + LPCWSTR wide); + +/* + * Return a Wide String duplicated with nss allocated memory. + */ +LPWSTR +nss_ckcapi_WideDup( + LPCWSTR wide); + +/* + * Covert a UTF8 string to Unicode wide character + */ +LPWSTR +nss_ckcapi_UTF8ToWide( + char *buf); + +NSS_EXTERN PRUint32 +nss_ckcapi_collect_all_certs( + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + ckcapiInternalObject ***listp, + PRUint32 *sizep, + PRUint32 count, + CK_RV *pError); + +#define NSS_CKCAPI_ARRAY_SIZE(x) ((sizeof(x)) / (sizeof((x)[0]))) + +#endif diff --git a/security/nss/lib/ckfw/capi/ckcapiver.c b/security/nss/lib/ckfw/capi/ckcapiver.c new file mode 100644 index 0000000000..825b630740 --- /dev/null +++ b/security/nss/lib/ckfw/capi/ckcapiver.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 "nsscapi.h" + +#if defined(DEBUG) +#define _DEBUG_STRING " (debug)" +#else +#define _DEBUG_STRING "" +#endif + +/* + * Version information + */ +const char __nss_ckcapi_version[] = "Version: NSS Access to Microsoft Certificate Store " NSS_CKCAPI_LIBRARY_VERSION _DEBUG_STRING; diff --git a/security/nss/lib/ckfw/capi/cobject.c b/security/nss/lib/ckfw/capi/cobject.c new file mode 100644 index 0000000000..c4b77d27ae --- /dev/null +++ b/security/nss/lib/ckfw/capi/cobject.c @@ -0,0 +1,2226 @@ +/* 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 "ckcapi.h" +#include "nssbase.h" + +/* + * ckcapi/cobject.c + * + * This file implements the NSSCKMDObject object for the + * "nss to capi objects" 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_CKCAPI_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_CKCAPI_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_CKCAPI_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 ckcapi_trueItem = { + (void *)&ck_true, (PRUint32)sizeof(CK_BBOOL) +}; +static const NSSItem ckcapi_falseItem = { + (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL) +}; +static const NSSItem ckcapi_x509Item = { + (void *)&ckc_x509, (PRUint32)sizeof(CK_CERTIFICATE_TYPE) +}; +static const NSSItem ckcapi_rsaItem = { + (void *)&ckk_rsa, (PRUint32)sizeof(CK_KEY_TYPE) +}; +static const NSSItem ckcapi_certClassItem = { + (void *)&cko_certificate, (PRUint32)sizeof(CK_OBJECT_CLASS) +}; +static const NSSItem ckcapi_privKeyClassItem = { + (void *)&cko_private_key, (PRUint32)sizeof(CK_OBJECT_CLASS) +}; +static const NSSItem ckcapi_pubKeyClassItem = { + (void *)&cko_public_key, (PRUint32)sizeof(CK_OBJECT_CLASS) +}; +static const NSSItem ckcapi_emptyItem = { + (void *)&ck_true, 0 +}; + +/* + * these are utilities. The chould be moved to a new utilities file. + */ + +/* + * unwrap a single DER value + */ +unsigned char * +nss_ckcapi_DERUnwrap( + unsigned char *src, + unsigned int size, + unsigned int *outSize, + unsigned char **next) +{ + unsigned char *start = src; + unsigned char *end = src + size; + 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) { + unsigned int count = len & 0x7f; + len = 0; + + if (count + 2 > size) { + return start; + } + while (count-- > 0) { + len = (len << 8) | (unsigned)*src++; + } + } + if (len + (src - start) > size) { + return start; + } + if (next) { + *next = src + len; + } + *outSize = len; + + return src; +} + +/* + * convert a PKCS #11 bytestrin into a CK_ULONG, the byte stream must be + * less than sizeof (CK_ULONG). + */ +CK_ULONG +nss_ckcapi_DataToInt( + NSSItem *data, + CK_RV *pError) +{ + CK_ULONG value = 0; + unsigned long count = data->size; + unsigned char *dataPtr = data->data; + unsigned long size = 0; + + *pError = CKR_OK; + + while (count--) { + value = value << 8; + value = value + *dataPtr++; + if (size || value) { + size++; + } + } + if (size > sizeof(CK_ULONG)) { + *pError = CKR_ATTRIBUTE_VALUE_INVALID; + } + return value; +} + +/* + * convert a CK_ULONG to a bytestream. Data is stored in the buffer 'buf' + * and must be at least CK_ULONG. Caller must provide buf. + */ +CK_ULONG +nss_ckcapi_IntToData( + CK_ULONG value, + NSSItem *data, + unsigned char *dataPtr, + CK_RV *pError) +{ + unsigned long count = 0; + unsigned long i; +#define SHIFT ((sizeof(CK_ULONG) - 1) * 8) + PRBool first = 0; + + *pError = CKR_OK; + + data->data = dataPtr; + for (i = 0; i < sizeof(CK_ULONG); i++) { + unsigned char digit = (unsigned char)((value >> SHIFT) & 0xff); + + value = value << 8; + + /* drop leading zero bytes */ + if (first && (0 == digit)) { + continue; + } + *dataPtr++ = digit; + count++; + } + data->size = count; + return count; +} + +/* + * get an attribute from a template. Value is returned in NSS item. + * data for the item is owned by the template. + */ +CK_RV +nss_ckcapi_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_ckcapi_GetULongAttribute( + CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *template, + CK_ULONG templateSize, + CK_RV *pError) +{ + NSSItem item; + + *pError = nss_ckcapi_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_ckcapi_GetBoolAttribute( + CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *template, + CK_ULONG templateSize, + CK_RV *pError) +{ + NSSItem item; + + *pError = nss_ckcapi_GetAttribute(type, template, templateSize, &item); + if (CKR_OK != *pError) { + return (CK_BBOOL)0; + } + if (item.size != sizeof(CK_BBOOL)) { + *pError = CKR_ATTRIBUTE_VALUE_INVALID; + return (CK_BBOOL)0; + } + return *(CK_BBOOL *)item.data; +} + +/* + * get an attribute which is type CK_BBOOL. + */ +char * +nss_ckcapi_GetStringAttribute( + CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *template, + CK_ULONG templateSize, + CK_RV *pError) +{ + NSSItem item; + char *str; + + /* get the attribute */ + *pError = nss_ckcapi_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; +} + +/* + * Return the size in bytes of a wide string, including the terminating null + * character + */ +int +nss_ckcapi_WideSize( + LPCWSTR wide) +{ + DWORD size; + + if ((LPWSTR)NULL == wide) { + return 0; + } + size = wcslen(wide) + 1; + return size * sizeof(WCHAR); +} + +/* + * Covert a Unicode wide character string to a UTF8 string + */ +char * +nss_ckcapi_WideToUTF8( + LPCWSTR wide) +{ + DWORD size; + char *buf; + + if ((LPWSTR)NULL == wide) { + return (char *)NULL; + } + + size = WideCharToMultiByte(CP_UTF8, 0, wide, -1, NULL, 0, NULL, 0); + if (size == 0) { + return (char *)NULL; + } + buf = nss_ZNEWARRAY(NULL, char, size); + size = WideCharToMultiByte(CP_UTF8, 0, wide, -1, buf, size, NULL, 0); + if (size == 0) { + nss_ZFreeIf(buf); + return (char *)NULL; + } + return buf; +} + +/* + * Return a Wide String duplicated with nss allocated memory. + */ +LPWSTR +nss_ckcapi_WideDup( + LPCWSTR wide) +{ + DWORD len; + LPWSTR buf; + + if ((LPWSTR)NULL == wide) { + return (LPWSTR)NULL; + } + + len = wcslen(wide) + 1; + + buf = nss_ZNEWARRAY(NULL, WCHAR, len); + if ((LPWSTR)NULL == buf) { + return buf; + } + nsslibc_memcpy(buf, wide, len * sizeof(WCHAR)); + return buf; +} + +/* + * Covert a UTF8 string to Unicode wide character + */ +LPWSTR +nss_ckcapi_UTF8ToWide( + char *buf) +{ + DWORD size; + LPWSTR wide; + + if ((char *)NULL == buf) { + return (LPWSTR)NULL; + } + + size = MultiByteToWideChar(CP_UTF8, 0, buf, -1, NULL, 0); + if (size == 0) { + return (LPWSTR)NULL; + } + wide = nss_ZNEWARRAY(NULL, WCHAR, size); + size = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wide, size); + if (size == 0) { + nss_ZFreeIf(wide); + return (LPWSTR)NULL; + } + return wide; +} + +/* + * keep all the knowlege of how the internalObject is laid out in this function + * + * nss_ckcapi_FetchKeyContainer + * + * fetches the Provider container and info as well as a key handle for a + * private key. If something other than a private key is passed in, + * this function fails with CKR_KEY_TYPE_INCONSISTENT + */ +NSS_EXTERN CK_RV +nss_ckcapi_FetchKeyContainer( + ckcapiInternalObject *iKey, + HCRYPTPROV *hProv, + DWORD *keySpec, + HCRYPTKEY *hKey) +{ + ckcapiCertObject *co; + ckcapiKeyObject *ko; + BOOL rc, dummy; + DWORD msError; + + switch (iKey->type) { + default: + case ckcapiRaw: + /* can't have raw private keys */ + return CKR_KEY_TYPE_INCONSISTENT; + case ckcapiCert: + if (iKey->objClass != CKO_PRIVATE_KEY) { + /* Only private keys have private key provider handles */ + return CKR_KEY_TYPE_INCONSISTENT; + } + co = &iKey->u.cert; + + /* OK, get the Provider */ + rc = CryptAcquireCertificatePrivateKey(co->certContext, + CRYPT_ACQUIRE_CACHE_FLAG | + CRYPT_ACQUIRE_COMPARE_KEY_FLAG, + NULL, hProv, + keySpec, &dummy); + if (!rc) { + goto loser; + } + break; + case ckcapiBareKey: + if (iKey->objClass != CKO_PRIVATE_KEY) { + /* Only private keys have private key provider handles */ + return CKR_KEY_TYPE_INCONSISTENT; + } + ko = &iKey->u.key; + + /* OK, get the Provider */ + if (0 == ko->hProv) { + rc = + CryptAcquireContext(hProv, + ko->containerName, + ko->provName, + ko->provInfo.dwProvType, 0); + if (!rc) { + goto loser; + } + } else { + *hProv = + ko->hProv; + } + *keySpec = ko->provInfo.dwKeySpec; + break; + } + + /* and get the crypto handle */ + rc = CryptGetUserKey(*hProv, *keySpec, hKey); + if (!rc) { + goto loser; + } + return CKR_OK; +loser: + /* map the microsoft error before leaving */ + msError = GetLastError(); + switch (msError) { + case ERROR_INVALID_HANDLE: + case ERROR_INVALID_PARAMETER: + case NTE_BAD_KEY: + case NTE_NO_KEY: + case NTE_BAD_PUBLIC_KEY: + case NTE_BAD_KEYSET: + case NTE_KEYSET_NOT_DEF: + return CKR_KEY_TYPE_INCONSISTENT; + case NTE_BAD_UID: + case NTE_KEYSET_ENTRY_BAD: + return CKR_DEVICE_ERROR; + } + return CKR_GENERAL_ERROR; +} + +/* + * take a DER PUBLIC Key block and return the modulus and exponent + */ +static void +ckcapi_CertPopulateModulusExponent( + ckcapiInternalObject *io) +{ + ckcapiKeyParams *kp = &io->u.cert.key; + PCCERT_CONTEXT certContext = io->u.cert.certContext; + unsigned char *pkData = + certContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData; + unsigned int size = + certContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData; + unsigned int newSize; + unsigned char *ptr, *newptr; + + /* find the start of the modulus -- this will not give good results if + * the key isn't an rsa key! */ + ptr = nss_ckcapi_DERUnwrap(pkData, size, &newSize, NULL); + kp->modulus.data = nss_ckcapi_DERUnwrap(ptr, newSize, + &kp->modulus.size, &newptr); + /* changed from signed to unsigned int */ + if (0 == *(char *)kp->modulus.data) { + kp->modulus.data = ((char *)kp->modulus.data) + 1; + kp->modulus.size = kp->modulus.size - 1; + } + /* changed from signed to unsigned int */ + kp->exponent.data = nss_ckcapi_DERUnwrap(newptr, (newptr - ptr) + newSize, + &kp->exponent.size, NULL); + if (0 == *(char *)kp->exponent.data) { + kp->exponent.data = ((char *)kp->exponent.data) + 1; + kp->exponent.size = kp->exponent.size - 1; + } + return; +} + +typedef struct _CAPI_RSA_KEY_BLOB { + PUBLICKEYSTRUC header; + RSAPUBKEY rsa; + char data[1]; +} CAPI_RSA_KEY_BLOB; + +#define CAPI_MODULUS_OFFSET(modSize) 0 +#define CAPI_PRIME_1_OFFSET(modSize) (modSize) +#define CAPI_PRIME_2_OFFSET(modSize) ((modSize) + (modSize) / 2) +#define CAPI_EXPONENT_1_OFFSET(modSize) ((modSize)*2) +#define CAPI_EXPONENT_2_OFFSET(modSize) ((modSize)*2 + (modSize) / 2) +#define CAPI_COEFFICIENT_OFFSET(modSize) ((modSize)*3) +#define CAPI_PRIVATE_EXP_OFFSET(modSize) ((modSize)*3 + (modSize) / 2) + +void +ckcapi_FetchPublicKey( + ckcapiInternalObject *io) +{ + ckcapiKeyParams *kp; + HCRYPTPROV hProv; + DWORD keySpec; + HCRYPTKEY hKey = 0; + CK_RV error; + DWORD bufLen; + BOOL rc; + unsigned long modulus; + char *buf = NULL; + CAPI_RSA_KEY_BLOB *blob; + + error = nss_ckcapi_FetchKeyContainer(io, &hProv, &keySpec, &hKey); + if (CKR_OK != error) { + goto loser; + } + kp = (ckcapiCert == io->type) ? &io->u.cert.key : &io->u.key.key; + + rc = CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, buf, &bufLen); + if (!rc) { + goto loser; + } + buf = nss_ZNEWARRAY(NULL, char, bufLen); + rc = CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, buf, &bufLen); + if (!rc) { + goto loser; + } + /* validate the blob */ + blob = (CAPI_RSA_KEY_BLOB *)buf; + if ((PUBLICKEYBLOB != blob->header.bType) || + (0x02 != blob->header.bVersion) || + (0x31415352 != blob->rsa.magic)) { + goto loser; + } + modulus = blob->rsa.bitlen / 8; + kp->pubKey = buf; + buf = NULL; + + kp->modulus.data = &blob->data[CAPI_MODULUS_OFFSET(modulus)]; + kp->modulus.size = modulus; + ckcapi_ReverseData(&kp->modulus); + nss_ckcapi_IntToData(blob->rsa.pubexp, &kp->exponent, + kp->publicExponentData, &error); + +loser: + nss_ZFreeIf(buf); + if (0 != hKey) { + CryptDestroyKey(hKey); + } + return; +} + +void +ckcapi_FetchPrivateKey( + ckcapiInternalObject *io) +{ + ckcapiKeyParams *kp; + HCRYPTPROV hProv; + DWORD keySpec; + HCRYPTKEY hKey = 0; + CK_RV error; + DWORD bufLen; + BOOL rc; + unsigned long modulus; + char *buf = NULL; + CAPI_RSA_KEY_BLOB *blob; + + error = nss_ckcapi_FetchKeyContainer(io, &hProv, &keySpec, &hKey); + if (CKR_OK != error) { + goto loser; + } + kp = (ckcapiCert == io->type) ? &io->u.cert.key : &io->u.key.key; + + rc = CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, buf, &bufLen); + if (!rc) { + goto loser; + } + buf = nss_ZNEWARRAY(NULL, char, bufLen); + rc = CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, buf, &bufLen); + if (!rc) { + goto loser; + } + /* validate the blob */ + blob = (CAPI_RSA_KEY_BLOB *)buf; + if ((PRIVATEKEYBLOB != blob->header.bType) || + (0x02 != blob->header.bVersion) || + (0x32415352 != blob->rsa.magic)) { + goto loser; + } + modulus = blob->rsa.bitlen / 8; + kp->privateKey = buf; + buf = NULL; + + kp->privateExponent.data = &blob->data[CAPI_PRIVATE_EXP_OFFSET(modulus)]; + kp->privateExponent.size = modulus; + ckcapi_ReverseData(&kp->privateExponent); + kp->prime1.data = &blob->data[CAPI_PRIME_1_OFFSET(modulus)]; + kp->prime1.size = modulus / 2; + ckcapi_ReverseData(&kp->prime1); + kp->prime2.data = &blob->data[CAPI_PRIME_2_OFFSET(modulus)]; + kp->prime2.size = modulus / 2; + ckcapi_ReverseData(&kp->prime2); + kp->exponent1.data = &blob->data[CAPI_EXPONENT_1_OFFSET(modulus)]; + kp->exponent1.size = modulus / 2; + ckcapi_ReverseData(&kp->exponent1); + kp->exponent2.data = &blob->data[CAPI_EXPONENT_2_OFFSET(modulus)]; + kp->exponent2.size = modulus / 2; + ckcapi_ReverseData(&kp->exponent2); + kp->coefficient.data = &blob->data[CAPI_COEFFICIENT_OFFSET(modulus)]; + kp->coefficient.size = modulus / 2; + ckcapi_ReverseData(&kp->coefficient); + +loser: + nss_ZFreeIf(buf); + if (0 != hKey) { + CryptDestroyKey(hKey); + } + return; +} + +void +ckcapi_PopulateModulusExponent( + ckcapiInternalObject *io) +{ + if (ckcapiCert == io->type) { + ckcapi_CertPopulateModulusExponent(io); + } else { + ckcapi_FetchPublicKey(io); + } + return; +} + +/* + * fetch the friendly name attribute. + * can only be called with ckcapiCert type objects! + */ +void +ckcapi_FetchLabel( + ckcapiInternalObject *io) +{ + ckcapiCertObject *co = &io->u.cert; + char *label; + PCCERT_CONTEXT certContext = io->u.cert.certContext; + char labelDataUTF16[128]; + DWORD size = sizeof(labelDataUTF16); + DWORD size8 = sizeof(co->labelData); + BOOL rv; + + rv = CertGetCertificateContextProperty(certContext, + CERT_FRIENDLY_NAME_PROP_ID, labelDataUTF16, &size); + if (rv) { + co->labelData = nss_ckcapi_WideToUTF8((LPCWSTR)labelDataUTF16); + if ((CHAR *)NULL == co->labelData) { + rv = 0; + } else { + size = strlen(co->labelData); + } + } + label = co->labelData; + /* we are presuming a user cert, make sure it has a nickname, even if + * Microsoft never gave it one */ + if (!rv && co->hasID) { + DWORD mserror = GetLastError(); +#define DEFAULT_NICKNAME "no Microsoft nickname" + label = DEFAULT_NICKNAME; + size = sizeof(DEFAULT_NICKNAME); + rv = 1; + } + + if (rv) { + co->label.data = label; + co->label.size = size; + } + return; +} + +void +ckcapi_FetchSerial( + ckcapiInternalObject *io) +{ + ckcapiCertObject *co = &io->u.cert; + PCCERT_CONTEXT certContext = io->u.cert.certContext; + DWORD size = sizeof(co->derSerial); + + BOOL rc = CryptEncodeObject(X509_ASN_ENCODING, + X509_MULTI_BYTE_INTEGER, + &certContext->pCertInfo->SerialNumber, + co->derSerial, + &size); + if (rc) { + co->serial.data = co->derSerial; + co->serial.size = size; + } + return; +} + +/* + * fetch the key ID. + */ +void +ckcapi_FetchID( + ckcapiInternalObject *io) +{ + PCCERT_CONTEXT certContext = io->u.cert.certContext; + DWORD size = 0; + BOOL rc; + + rc = CertGetCertificateContextProperty(certContext, + CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size); + if (!rc) { + return; + } + io->idData = nss_ZNEWARRAY(NULL, char, size); + if (io->idData == NULL) { + return; + } + + rc = CertGetCertificateContextProperty(certContext, + CERT_KEY_IDENTIFIER_PROP_ID, io->idData, &size); + if (!rc) { + nss_ZFreeIf(io->idData); + io->idData = NULL; + return; + } + io->id.data = io->idData; + io->id.size = size; + return; +} + +/* + * fetch the hash key. + */ +void +ckcapi_CertFetchHashKey( + ckcapiInternalObject *io) +{ + ckcapiCertObject *co = &io->u.cert; + PCCERT_CONTEXT certContext = io->u.cert.certContext; + DWORD size = certContext->cbCertEncoded; + DWORD max = sizeof(io->hashKeyData) - 1; + DWORD offset = 0; + + /* make sure we don't over flow. NOTE: cutting the top of a cert is + * not a big issue because the signature for will be unique for the cert */ + if (size > max) { + offset = size - max; + size = max; + } + + nsslibc_memcpy(io->hashKeyData, certContext->pbCertEncoded + offset, size); + io->hashKeyData[size] = (char)(io->objClass & 0xff); + + io->hashKey.data = io->hashKeyData; + io->hashKey.size = size + 1; + return; +} + +/* + * fetch the hash key. + */ +void +ckcapi_KeyFetchHashKey( + ckcapiInternalObject *io) +{ + ckcapiKeyObject *ko = &io->u.key; + DWORD size; + DWORD max = sizeof(io->hashKeyData) - 2; + DWORD offset = 0; + DWORD provLen = strlen(ko->provName); + DWORD containerLen = strlen(ko->containerName); + + size = provLen + containerLen; + + /* make sure we don't overflow, try to keep things unique */ + if (size > max) { + DWORD diff = ((size - max) + 1) / 2; + provLen -= diff; + containerLen -= diff; + size = provLen + containerLen; + } + + nsslibc_memcpy(io->hashKeyData, ko->provName, provLen); + nsslibc_memcpy(&io->hashKeyData[provLen], + ko->containerName, + containerLen); + io->hashKeyData[size] = (char)(io->objClass & 0xff); + io->hashKeyData[size + 1] = (char)(ko->provInfo.dwKeySpec & 0xff); + + io->hashKey.data = io->hashKeyData; + io->hashKey.size = size + 2; + return; +} + +/* + * fetch the hash key. + */ +void +ckcapi_FetchHashKey( + ckcapiInternalObject *io) +{ + if (ckcapiCert == io->type) { + ckcapi_CertFetchHashKey(io); + } else { + ckcapi_KeyFetchHashKey(io); + } + return; +} + +const NSSItem * +ckcapi_FetchCertAttribute( + ckcapiInternalObject *io, + CK_ATTRIBUTE_TYPE type) +{ + PCCERT_CONTEXT certContext = io->u.cert.certContext; + switch (type) { + case CKA_CLASS: + return &ckcapi_certClassItem; + case CKA_TOKEN: + return &ckcapi_trueItem; + case CKA_MODIFIABLE: + case CKA_PRIVATE: + return &ckcapi_falseItem; + case CKA_CERTIFICATE_TYPE: + return &ckcapi_x509Item; + case CKA_LABEL: + if (0 == io->u.cert.label.size) { + ckcapi_FetchLabel(io); + } + return &io->u.cert.label; + case CKA_SUBJECT: + if (0 == io->u.cert.subject.size) { + io->u.cert.subject.data = + certContext->pCertInfo->Subject.pbData; + io->u.cert.subject.size = + certContext->pCertInfo->Subject.cbData; + } + return &io->u.cert.subject; + case CKA_ISSUER: + if (0 == io->u.cert.issuer.size) { + io->u.cert.issuer.data = + certContext->pCertInfo->Issuer.pbData; + io->u.cert.issuer.size = + certContext->pCertInfo->Issuer.cbData; + } + return &io->u.cert.issuer; + case CKA_SERIAL_NUMBER: + if (0 == io->u.cert.serial.size) { + /* not exactly right. This should be the encoded serial number, but + * it's the decoded serial number! */ + ckcapi_FetchSerial(io); + } + return &io->u.cert.serial; + case CKA_VALUE: + if (0 == io->u.cert.derCert.size) { + io->u.cert.derCert.data = + io->u.cert.certContext->pbCertEncoded; + io->u.cert.derCert.size = + io->u.cert.certContext->cbCertEncoded; + } + return &io->u.cert.derCert; + case CKA_ID: + if (!io->u.cert.hasID) { + return NULL; + } + if (0 == io->id.size) { + ckcapi_FetchID(io); + } + return &io->id; + default: + break; + } + return NULL; +} + +const NSSItem * +ckcapi_FetchPubKeyAttribute( + ckcapiInternalObject *io, + CK_ATTRIBUTE_TYPE type) +{ + PRBool isCertType = (ckcapiCert == io->type); + ckcapiKeyParams *kp = isCertType ? &io->u.cert.key : &io->u.key.key; + + switch (type) { + case CKA_CLASS: + return &ckcapi_pubKeyClassItem; + case CKA_TOKEN: + case CKA_LOCAL: + case CKA_ENCRYPT: + case CKA_VERIFY: + case CKA_VERIFY_RECOVER: + return &ckcapi_trueItem; + case CKA_PRIVATE: + case CKA_MODIFIABLE: + case CKA_DERIVE: + case CKA_WRAP: + return &ckcapi_falseItem; + case CKA_KEY_TYPE: + return &ckcapi_rsaItem; + case CKA_LABEL: + if (!isCertType) { + return &ckcapi_emptyItem; + } + if (0 == io->u.cert.label.size) { + ckcapi_FetchLabel(io); + } + return &io->u.cert.label; + case CKA_SUBJECT: + if (!isCertType) { + return &ckcapi_emptyItem; + } + if (0 == io->u.cert.subject.size) { + PCCERT_CONTEXT certContext = + io->u.cert.certContext; + io->u.cert.subject.data = + certContext->pCertInfo->Subject.pbData; + io->u.cert.subject.size = + certContext->pCertInfo->Subject.cbData; + } + return &io->u.cert.subject; + case CKA_MODULUS: + if (0 == kp->modulus.size) { + ckcapi_PopulateModulusExponent(io); + } + return &kp->modulus; + case CKA_PUBLIC_EXPONENT: + if (0 == kp->modulus.size) { + ckcapi_PopulateModulusExponent(io); + } + return &kp->exponent; + case CKA_ID: + if (0 == io->id.size) { + ckcapi_FetchID(io); + } + return &io->id; + default: + break; + } + return NULL; +} + +const NSSItem * +ckcapi_FetchPrivKeyAttribute( + ckcapiInternalObject *io, + CK_ATTRIBUTE_TYPE type) +{ + PRBool isCertType = (ckcapiCert == io->type); + ckcapiKeyParams *kp = isCertType ? &io->u.cert.key : &io->u.key.key; + + switch (type) { + case CKA_CLASS: + return &ckcapi_privKeyClassItem; + case CKA_TOKEN: + case CKA_LOCAL: + case CKA_SIGN: + case CKA_DECRYPT: + case CKA_SIGN_RECOVER: + return &ckcapi_trueItem; + case CKA_SENSITIVE: + case CKA_PRIVATE: /* should move in the future */ + case CKA_MODIFIABLE: + case CKA_DERIVE: + case CKA_UNWRAP: + case CKA_EXTRACTABLE: /* will probably move in the future */ + case CKA_ALWAYS_SENSITIVE: + case CKA_NEVER_EXTRACTABLE: + return &ckcapi_falseItem; + case CKA_KEY_TYPE: + return &ckcapi_rsaItem; + case CKA_LABEL: + if (!isCertType) { + return &ckcapi_emptyItem; + } + if (0 == io->u.cert.label.size) { + ckcapi_FetchLabel(io); + } + return &io->u.cert.label; + case CKA_SUBJECT: + if (!isCertType) { + return &ckcapi_emptyItem; + } + if (0 == io->u.cert.subject.size) { + PCCERT_CONTEXT certContext = + io->u.cert.certContext; + io->u.cert.subject.data = + certContext->pCertInfo->Subject.pbData; + io->u.cert.subject.size = + certContext->pCertInfo->Subject.cbData; + } + return &io->u.cert.subject; + case CKA_MODULUS: + if (0 == kp->modulus.size) { + ckcapi_PopulateModulusExponent(io); + } + return &kp->modulus; + case CKA_PUBLIC_EXPONENT: + if (0 == kp->modulus.size) { + ckcapi_PopulateModulusExponent(io); + } + return &kp->exponent; + case CKA_PRIVATE_EXPONENT: + if (0 == kp->privateExponent.size) { + ckcapi_FetchPrivateKey(io); + } + return &kp->privateExponent; + case CKA_PRIME_1: + if (0 == kp->privateExponent.size) { + ckcapi_FetchPrivateKey(io); + } + return &kp->prime1; + case CKA_PRIME_2: + if (0 == kp->privateExponent.size) { + ckcapi_FetchPrivateKey(io); + } + return &kp->prime2; + case CKA_EXPONENT_1: + if (0 == kp->privateExponent.size) { + ckcapi_FetchPrivateKey(io); + } + return &kp->exponent1; + case CKA_EXPONENT_2: + if (0 == kp->privateExponent.size) { + ckcapi_FetchPrivateKey(io); + } + return &kp->exponent2; + case CKA_COEFFICIENT: + if (0 == kp->privateExponent.size) { + ckcapi_FetchPrivateKey(io); + } + return &kp->coefficient; + case CKA_ID: + if (0 == io->id.size) { + ckcapi_FetchID(io); + } + return &io->id; + default: + return NULL; + } +} + +const NSSItem * +nss_ckcapi_FetchAttribute( + ckcapiInternalObject *io, + CK_ATTRIBUTE_TYPE type) +{ + CK_ULONG i; + + if (io->type == ckcapiRaw) { + for (i = 0; i < io->u.raw.n; i++) { + if (type == io->u.raw.types[i]) { + return &io->u.raw.items[i]; + } + } + return NULL; + } + /* deal with the common attributes */ + switch (io->objClass) { + case CKO_CERTIFICATE: + return ckcapi_FetchCertAttribute(io, type); + case CKO_PRIVATE_KEY: + return ckcapi_FetchPrivKeyAttribute(io, type); + case CKO_PUBLIC_KEY: + return ckcapi_FetchPubKeyAttribute(io, type); + } + return NULL; +} + +/* + * check to see if the certificate already exists + */ +static PRBool +ckcapi_cert_exists( + NSSItem *value, + ckcapiInternalObject **io) +{ + int count, i; + PRUint32 size = 0; + ckcapiInternalObject **listp = NULL; + CK_ATTRIBUTE myTemplate[2]; + CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE; + CK_ULONG templateCount = 2; + CK_RV error; + PRBool found = PR_FALSE; + + myTemplate[0].type = CKA_CLASS; + myTemplate[0].pValue = &cert_class; + myTemplate[0].ulValueLen = sizeof(cert_class); + myTemplate[1].type = CKA_VALUE; + myTemplate[1].pValue = value->data; + myTemplate[1].ulValueLen = value->size; + + count = nss_ckcapi_collect_all_certs(myTemplate, templateCount, &listp, + &size, 0, &error); + + /* free them */ + if (count > 1) { + *io = listp[0]; + found = PR_TRUE; + } + + for (i = 1; i < count; i++) { + nss_ckcapi_DestroyInternalObject(listp[i]); + } + nss_ZFreeIf(listp); + return found; +} + +static PRBool +ckcapi_cert_hasEmail( + PCCERT_CONTEXT certContext) +{ + int count; + + count = CertGetNameString(certContext, CERT_NAME_EMAIL_TYPE, + 0, NULL, NULL, 0); + + return count > 1 ? PR_TRUE : PR_FALSE; +} + +static PRBool +ckcapi_cert_isRoot( + PCCERT_CONTEXT certContext) +{ + return CertCompareCertificateName(certContext->dwCertEncodingType, + &certContext->pCertInfo->Issuer, &certContext->pCertInfo->Subject); +} + +static PRBool +ckcapi_cert_isCA( + PCCERT_CONTEXT certContext) +{ + PCERT_EXTENSION extension; + CERT_BASIC_CONSTRAINTS2_INFO basicInfo; + DWORD size = sizeof(basicInfo); + BOOL rc; + + extension = CertFindExtension(szOID_BASIC_CONSTRAINTS, + certContext->pCertInfo->cExtension, + certContext->pCertInfo->rgExtension); + if ((PCERT_EXTENSION)NULL == extension) { + return PR_FALSE; + } + rc = CryptDecodeObject(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS2, + extension->Value.pbData, extension->Value.cbData, + 0, &basicInfo, &size); + if (!rc) { + return PR_FALSE; + } + return (PRBool)basicInfo.fCA; +} + +static CRYPT_KEY_PROV_INFO * +ckcapi_cert_getPrivateKeyInfo( + PCCERT_CONTEXT certContext, + NSSItem *keyID) +{ + BOOL rc; + CRYPT_HASH_BLOB msKeyID; + DWORD size = 0; + CRYPT_KEY_PROV_INFO *prov = NULL; + + msKeyID.cbData = keyID->size; + msKeyID.pbData = keyID->data; + + rc = CryptGetKeyIdentifierProperty( + &msKeyID, + CERT_KEY_PROV_INFO_PROP_ID, + 0, NULL, NULL, NULL, &size); + if (!rc) { + return (CRYPT_KEY_PROV_INFO *)NULL; + } + prov = (CRYPT_KEY_PROV_INFO *)nss_ZAlloc(NULL, size); + if ((CRYPT_KEY_PROV_INFO *)prov == NULL) { + return (CRYPT_KEY_PROV_INFO *)NULL; + } + rc = CryptGetKeyIdentifierProperty( + &msKeyID, + CERT_KEY_PROV_INFO_PROP_ID, + 0, NULL, NULL, prov, &size); + if (!rc) { + nss_ZFreeIf(prov); + return (CRYPT_KEY_PROV_INFO *)NULL; + } + + return prov; +} + +static CRYPT_KEY_PROV_INFO * +ckcapi_cert_getProvInfo( + ckcapiInternalObject *io) +{ + BOOL rc; + DWORD size = 0; + CRYPT_KEY_PROV_INFO *prov = NULL; + + rc = CertGetCertificateContextProperty( + io->u.cert.certContext, + CERT_KEY_PROV_INFO_PROP_ID, + NULL, &size); + if (!rc) { + return (CRYPT_KEY_PROV_INFO *)NULL; + } + prov = (CRYPT_KEY_PROV_INFO *)nss_ZAlloc(NULL, size); + if ((CRYPT_KEY_PROV_INFO *)prov == NULL) { + return (CRYPT_KEY_PROV_INFO *)NULL; + } + rc = CertGetCertificateContextProperty( + io->u.cert.certContext, + CERT_KEY_PROV_INFO_PROP_ID, + prov, &size); + if (!rc) { + nss_ZFreeIf(prov); + return (CRYPT_KEY_PROV_INFO *)NULL; + } + + return prov; +} + +/* forward declaration */ +static void +ckcapi_removeObjectFromHash( + ckcapiInternalObject *io); + +/* + * Finalize - unneeded + * Destroy + * IsTokenObject - CK_TRUE + * GetAttributeCount + * GetAttributeTypes + * GetAttributeSize + * GetAttribute + * SetAttribute + * GetObjectSize + */ + +static CK_RV +ckcapi_mdObject_Destroy( + NSSCKMDObject *mdObject, + NSSCKFWObject *fwObject, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc; + CK_OBJECT_CLASS objClass; + BOOL rc; + DWORD provType; + DWORD msError; + PRBool isCertType = (PRBool)(ckcapiCert == io->type); + HCERTSTORE hStore = 0; + + if (ckcapiRaw == io->type) { + /* there is not 'object write protected' error, use the next best thing */ + return CKR_TOKEN_WRITE_PROTECTED; + } + + objClass = io->objClass; + if (CKO_CERTIFICATE == objClass) { + PCCERT_CONTEXT certContext; + + /* get the store */ + hStore = CertOpenSystemStore(0, io->u.cert.certStore); + if (0 == hStore) { + rc = 0; + goto loser; + } + certContext = CertFindCertificateInStore(hStore, X509_ASN_ENCODING, 0, + CERT_FIND_EXISTING, io->u.cert.certContext, NULL); + if ((PCCERT_CONTEXT)NULL == certContext) { + rc = 0; + goto loser; + } + rc = CertDeleteCertificateFromStore(certContext); + } else { + char *provName = NULL; + char *containerName = NULL; + HCRYPTPROV hProv; + CRYPT_HASH_BLOB msKeyID; + + if (0 == io->id.size) { + ckcapi_FetchID(io); + } + + if (isCertType) { + CRYPT_KEY_PROV_INFO *provInfo = ckcapi_cert_getProvInfo(io); + provName = nss_ckcapi_WideToUTF8(provInfo->pwszProvName); + containerName = nss_ckcapi_WideToUTF8(provInfo->pwszContainerName); + provType = provInfo->dwProvType; + nss_ZFreeIf(provInfo); + } else { + provName = io->u.key.provName; + containerName = io->u.key.containerName; + provType = io->u.key.provInfo.dwProvType; + io->u.key.provName = NULL; + io->u.key.containerName = NULL; + } + /* first remove the key id pointer */ + msKeyID.cbData = io->id.size; + msKeyID.pbData = io->id.data; + rc = CryptSetKeyIdentifierProperty(&msKeyID, + CERT_KEY_PROV_INFO_PROP_ID, CRYPT_KEYID_DELETE_FLAG, NULL, NULL, NULL); + if (rc) { + rc = CryptAcquireContext(&hProv, containerName, provName, provType, + CRYPT_DELETEKEYSET); + } + nss_ZFreeIf(provName); + nss_ZFreeIf(containerName); + } +loser: + + if (hStore) { + CertCloseStore(hStore, 0); + } + if (!rc) { + msError = GetLastError(); + return CKR_GENERAL_ERROR; + } + + /* remove it from the hash */ + ckcapi_removeObjectFromHash(io); + + /* free the puppy.. */ + nss_ckcapi_DestroyInternalObject(io); + return CKR_OK; +} + +static CK_BBOOL +ckcapi_mdObject_IsTokenObject( + NSSCKMDObject *mdObject, + NSSCKFWObject *fwObject, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return CK_TRUE; +} + +static CK_ULONG +ckcapi_mdObject_GetAttributeCount( + NSSCKMDObject *mdObject, + NSSCKFWObject *fwObject, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc; + + if (ckcapiRaw == 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 +ckcapi_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) +{ + ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc; + CK_ULONG i; + CK_RV error = CKR_OK; + const CK_ATTRIBUTE_TYPE *attrs = NULL; + CK_ULONG size = ckcapi_mdObject_GetAttributeCount( + mdObject, fwObject, mdSession, fwSession, + mdToken, fwToken, mdInstance, fwInstance, &error); + + if (size != ulCount) { + return CKR_BUFFER_TOO_SMALL; + } + if (io->type == ckcapiRaw) { + 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 +ckcapi_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) +{ + ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc; + + const NSSItem *b; + + b = nss_ckcapi_FetchAttribute(io, attribute); + + if ((const NSSItem *)NULL == b) { + *pError = CKR_ATTRIBUTE_TYPE_INVALID; + return 0; + } + return b->size; +} + +static CK_RV +ckcapi_mdObject_SetAttribute( + NSSCKMDObject *mdObject, + NSSCKFWObject *fwObject, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_ATTRIBUTE_TYPE attribute, + NSSItem *value) +{ + return CKR_OK; +} + +static NSSCKFWItem +ckcapi_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; + ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc; + + mdItem.needsFreeing = PR_FALSE; + mdItem.item = (NSSItem *)nss_ckcapi_FetchAttribute(io, attribute); + + if ((NSSItem *)NULL == mdItem.item) { + *pError = CKR_ATTRIBUTE_TYPE_INVALID; + } + + return mdItem; +} + +static CK_ULONG +ckcapi_mdObject_GetObjectSize( + NSSCKMDObject *mdObject, + NSSCKFWObject *fwObject, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc; + CK_ULONG rv = 1; + + /* size is irrelevant to this token */ + return rv; +} + +static const NSSCKMDObject + ckcapi_prototype_mdObject = { + (void *)NULL, /* etc */ + NULL, /* Finalize */ + ckcapi_mdObject_Destroy, + ckcapi_mdObject_IsTokenObject, + ckcapi_mdObject_GetAttributeCount, + ckcapi_mdObject_GetAttributeTypes, + ckcapi_mdObject_GetAttributeSize, + ckcapi_mdObject_GetAttribute, + NULL, /* FreeAttribute */ + ckcapi_mdObject_SetAttribute, + ckcapi_mdObject_GetObjectSize, + (void *)NULL /* null terminator */ + }; + +static nssHash *ckcapiInternalObjectHash = NULL; + +NSS_IMPLEMENT NSSCKMDObject * +nss_ckcapi_CreateMDObject( + NSSArena *arena, + ckcapiInternalObject *io, + CK_RV *pError) +{ + if ((nssHash *)NULL == ckcapiInternalObjectHash) { + ckcapiInternalObjectHash = nssHash_CreateItem(NULL, 10); + } + if (ckcapiCert == io->type) { + /* the hash key, not a cryptographic key */ + NSSItem *key = &io->hashKey; + ckcapiInternalObject *old_o = NULL; + + if (key->size == 0) { + ckcapi_FetchHashKey(io); + } + old_o = (ckcapiInternalObject *) + nssHash_Lookup(ckcapiInternalObjectHash, key); + if (!old_o) { + nssHash_Add(ckcapiInternalObjectHash, key, io); + } else if (old_o != io) { + nss_ckcapi_DestroyInternalObject(io); + io = old_o; + } + } + + if ((void *)NULL == io->mdObject.etc) { + (void)nsslibc_memcpy(&io->mdObject, &ckcapi_prototype_mdObject, + sizeof(ckcapi_prototype_mdObject)); + io->mdObject.etc = (void *)io; + } + return &io->mdObject; +} + +static void +ckcapi_removeObjectFromHash( + ckcapiInternalObject *io) +{ + NSSItem *key = &io->hashKey; + + if ((nssHash *)NULL == ckcapiInternalObjectHash) { + return; + } + if (key->size == 0) { + ckcapi_FetchHashKey(io); + } + nssHash_Remove(ckcapiInternalObjectHash, key); + return; +} + +void +nss_ckcapi_DestroyInternalObject( + ckcapiInternalObject *io) +{ + switch (io->type) { + case ckcapiRaw: + return; + case ckcapiCert: + CertFreeCertificateContext(io->u.cert.certContext); + nss_ZFreeIf(io->u.cert.labelData); + nss_ZFreeIf(io->u.cert.key.privateKey); + nss_ZFreeIf(io->u.cert.key.pubKey); + nss_ZFreeIf(io->idData); + break; + case ckcapiBareKey: + nss_ZFreeIf(io->u.key.provInfo.pwszContainerName); + nss_ZFreeIf(io->u.key.provInfo.pwszProvName); + nss_ZFreeIf(io->u.key.provName); + nss_ZFreeIf(io->u.key.containerName); + nss_ZFreeIf(io->u.key.key.privateKey); + nss_ZFreeIf(io->u.key.key.pubKey); + if (0 != io->u.key.hProv) { + CryptReleaseContext(io->u.key.hProv, 0); + } + nss_ZFreeIf(io->idData); + break; + } + nss_ZFreeIf(io); + return; +} + +static ckcapiInternalObject * +nss_ckcapi_CreateCertificate( + NSSCKFWSession *fwSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + CK_RV *pError) +{ + NSSItem value; + NSSItem keyID; + char *storeStr; + ckcapiInternalObject *io = NULL; + PCCERT_CONTEXT certContext = NULL; + PCCERT_CONTEXT storedCertContext = NULL; + CRYPT_KEY_PROV_INFO *prov_info = NULL; + char *nickname = NULL; + HCERTSTORE hStore = 0; + DWORD msError = 0; + PRBool hasID; + CK_RV dummy; + BOOL rc; + + *pError = nss_ckcapi_GetAttribute(CKA_VALUE, pTemplate, + ulAttributeCount, &value); + + if (CKR_OK != *pError) { + return (ckcapiInternalObject *)NULL; + } + + *pError = nss_ckcapi_GetAttribute(CKA_ID, pTemplate, + ulAttributeCount, &keyID); + + if (CKR_OK != *pError) { + return (ckcapiInternalObject *)NULL; + } + + if (ckcapi_cert_exists(&value, &io)) { + return io; + } + + /* OK, we are creating a new one, figure out what store it belongs to.. + * first get a certContext handle.. */ + certContext = CertCreateCertificateContext(X509_ASN_ENCODING, + value.data, value.size); + if ((PCCERT_CONTEXT)NULL == certContext) { + msError = GetLastError(); + *pError = CKR_ATTRIBUTE_VALUE_INVALID; + goto loser; + } + + /* do we have a private key laying around... */ + prov_info = ckcapi_cert_getPrivateKeyInfo(certContext, &keyID); + if (prov_info) { + CRYPT_DATA_BLOB msKeyID; + storeStr = "My"; + hasID = PR_TRUE; + rc = CertSetCertificateContextProperty(certContext, + CERT_KEY_PROV_INFO_PROP_ID, + 0, prov_info); + nss_ZFreeIf(prov_info); + if (!rc) { + msError = GetLastError(); + *pError = CKR_DEVICE_ERROR; + goto loser; + } + msKeyID.cbData = keyID.size; + msKeyID.pbData = keyID.data; + rc = CertSetCertificateContextProperty(certContext, + CERT_KEY_IDENTIFIER_PROP_ID, + 0, &msKeyID); + if (!rc) { + msError = GetLastError(); + *pError = CKR_DEVICE_ERROR; + goto loser; + } + + /* does it look like a CA */ + } else if (ckcapi_cert_isCA(certContext)) { + storeStr = ckcapi_cert_isRoot(certContext) ? "CA" : "Root"; + /* does it look like an S/MIME cert */ + } else if (ckcapi_cert_hasEmail(certContext)) { + storeStr = "AddressBook"; + } else { + /* just pick a store */ + storeStr = "CA"; + } + + /* get the nickname, not an error if we can't find it */ + nickname = nss_ckcapi_GetStringAttribute(CKA_LABEL, pTemplate, + ulAttributeCount, &dummy); + if (nickname) { + LPWSTR nicknameUTF16 = NULL; + CRYPT_DATA_BLOB nicknameBlob; + + nicknameUTF16 = nss_ckcapi_UTF8ToWide(nickname); + nss_ZFreeIf(nickname); + nickname = NULL; + if ((LPWSTR)NULL == nicknameUTF16) { + *pError = CKR_HOST_MEMORY; + goto loser; + } + nicknameBlob.cbData = nss_ckcapi_WideSize(nicknameUTF16); + nicknameBlob.pbData = (BYTE *)nicknameUTF16; + rc = CertSetCertificateContextProperty(certContext, + CERT_FRIENDLY_NAME_PROP_ID, 0, &nicknameBlob); + nss_ZFreeIf(nicknameUTF16); + if (!rc) { + msError = GetLastError(); + *pError = CKR_DEVICE_ERROR; + goto loser; + } + } + + hStore = CertOpenSystemStore((HCRYPTPROV)NULL, storeStr); + if (0 == hStore) { + msError = GetLastError(); + *pError = CKR_DEVICE_ERROR; + goto loser; + } + + rc = CertAddCertificateContextToStore(hStore, certContext, + CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, &storedCertContext); + CertFreeCertificateContext(certContext); + certContext = NULL; + CertCloseStore(hStore, 0); + hStore = 0; + if (!rc) { + msError = GetLastError(); + *pError = CKR_DEVICE_ERROR; + goto loser; + } + + io = nss_ZNEW(NULL, ckcapiInternalObject); + if ((ckcapiInternalObject *)NULL == io) { + *pError = CKR_HOST_MEMORY; + goto loser; + } + io->type = ckcapiCert; + io->objClass = CKO_CERTIFICATE; + io->u.cert.certContext = storedCertContext; + io->u.cert.hasID = hasID; + return io; + +loser: + if (certContext) { + CertFreeCertificateContext(certContext); + certContext = NULL; + } + if (storedCertContext) { + CertFreeCertificateContext(storedCertContext); + storedCertContext = NULL; + } + if (0 != hStore) { + CertCloseStore(hStore, 0); + } + return (ckcapiInternalObject *)NULL; +} + +static char * +ckcapi_getDefaultProvider( + CK_RV *pError) +{ + char *name = NULL; + BOOL rc; + DWORD nameLength = 0; + + rc = CryptGetDefaultProvider(PROV_RSA_FULL, NULL, CRYPT_USER_DEFAULT, NULL, + &nameLength); + if (!rc) { + return (char *)NULL; + } + + name = nss_ZNEWARRAY(NULL, char, nameLength); + if ((char *)NULL == name) { + return (char *)NULL; + } + rc = CryptGetDefaultProvider(PROV_RSA_FULL, NULL, CRYPT_USER_DEFAULT, name, + &nameLength); + if (!rc) { + nss_ZFreeIf(name); + return (char *)NULL; + } + + return name; +} + +static char * +ckcapi_getContainer( + CK_RV *pError, + NSSItem *id) +{ + RPC_STATUS rstat; + UUID uuid; + char *uuidStr; + char *container; + + rstat = UuidCreate(&uuid); + rstat = UuidToString(&uuid, &uuidStr); + + /* convert it from rcp memory to our own */ + container = nssUTF8_Duplicate(uuidStr, NULL); + RpcStringFree(&uuidStr); + + return container; +} + +static CK_RV +ckcapi_buildPrivateKeyBlob( + NSSItem *keyBlob, + NSSItem *modulus, + NSSItem *publicExponent, + NSSItem *privateExponent, + NSSItem *prime1, + NSSItem *prime2, + NSSItem *exponent1, + NSSItem *exponent2, + NSSItem *coefficient, + PRBool isKeyExchange) +{ + CAPI_RSA_KEY_BLOB *keyBlobData = NULL; + unsigned char *target; + unsigned long modSize = modulus->size; + unsigned long dataSize; + CK_RV error = CKR_OK; + + /* validate extras */ + if (privateExponent->size != modSize) { + error = CKR_ATTRIBUTE_VALUE_INVALID; + goto loser; + } + if (prime1->size != modSize / 2) { + error = CKR_ATTRIBUTE_VALUE_INVALID; + goto loser; + } + if (prime2->size != modSize / 2) { + error = CKR_ATTRIBUTE_VALUE_INVALID; + goto loser; + } + if (exponent1->size != modSize / 2) { + error = CKR_ATTRIBUTE_VALUE_INVALID; + goto loser; + } + if (exponent2->size != modSize / 2) { + error = CKR_ATTRIBUTE_VALUE_INVALID; + goto loser; + } + if (coefficient->size != modSize / 2) { + error = CKR_ATTRIBUTE_VALUE_INVALID; + goto loser; + } + dataSize = (modSize * 4) + (modSize / 2) + sizeof(CAPI_RSA_KEY_BLOB); + keyBlobData = (CAPI_RSA_KEY_BLOB *)nss_ZAlloc(NULL, dataSize); + if ((CAPI_RSA_KEY_BLOB *)NULL == keyBlobData) { + error = CKR_HOST_MEMORY; + goto loser; + } + + keyBlobData->header.bType = PRIVATEKEYBLOB; + keyBlobData->header.bVersion = 0x02; + keyBlobData->header.reserved = 0x00; + keyBlobData->header.aiKeyAlg = isKeyExchange ? CALG_RSA_KEYX : CALG_RSA_SIGN; + keyBlobData->rsa.magic = 0x32415352; + keyBlobData->rsa.bitlen = modSize * 8; + keyBlobData->rsa.pubexp = nss_ckcapi_DataToInt(publicExponent, &error); + if (CKR_OK != error) { + goto loser; + } + + target = &keyBlobData->data[CAPI_MODULUS_OFFSET(modSize)]; + nsslibc_memcpy(target, modulus->data, modulus->size); + modulus->data = target; + ckcapi_ReverseData(modulus); + + target = &keyBlobData->data[CAPI_PRIVATE_EXP_OFFSET(modSize)]; + nsslibc_memcpy(target, privateExponent->data, privateExponent->size); + privateExponent->data = target; + ckcapi_ReverseData(privateExponent); + + target = &keyBlobData->data[CAPI_PRIME_1_OFFSET(modSize)]; + nsslibc_memcpy(target, prime1->data, prime1->size); + prime1->data = target; + ckcapi_ReverseData(prime1); + + target = &keyBlobData->data[CAPI_PRIME_2_OFFSET(modSize)]; + nsslibc_memcpy(target, prime2->data, prime2->size); + prime2->data = target; + ckcapi_ReverseData(prime2); + + target = &keyBlobData->data[CAPI_EXPONENT_1_OFFSET(modSize)]; + nsslibc_memcpy(target, exponent1->data, exponent1->size); + exponent1->data = target; + ckcapi_ReverseData(exponent1); + + target = &keyBlobData->data[CAPI_EXPONENT_2_OFFSET(modSize)]; + nsslibc_memcpy(target, exponent2->data, exponent2->size); + exponent2->data = target; + ckcapi_ReverseData(exponent2); + + target = &keyBlobData->data[CAPI_COEFFICIENT_OFFSET(modSize)]; + nsslibc_memcpy(target, coefficient->data, coefficient->size); + coefficient->data = target; + ckcapi_ReverseData(coefficient); + + keyBlob->data = keyBlobData; + keyBlob->size = dataSize; + + return CKR_OK; + +loser: + nss_ZFreeIf(keyBlobData); + return error; +} + +static ckcapiInternalObject * +nss_ckcapi_CreatePrivateKey( + NSSCKFWSession *fwSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + CK_RV *pError) +{ + NSSItem modulus; + NSSItem publicExponent; + NSSItem privateExponent; + NSSItem exponent1; + NSSItem exponent2; + NSSItem prime1; + NSSItem prime2; + NSSItem coefficient; + NSSItem keyID; + NSSItem keyBlob; + ckcapiInternalObject *io = NULL; + char *providerName = NULL; + char *containerName = NULL; + char *idData = NULL; + CRYPT_KEY_PROV_INFO provInfo; + CRYPT_HASH_BLOB msKeyID; + CK_KEY_TYPE keyType; + HCRYPTPROV hProv = 0; + HCRYPTKEY hKey = 0; + PRBool decrypt; + DWORD keySpec; + DWORD msError; + BOOL rc; + + keyType = nss_ckcapi_GetULongAttribute(CKA_KEY_TYPE, pTemplate, ulAttributeCount, pError); + if (CKR_OK != *pError) { + return (ckcapiInternalObject *)NULL; + } + if (CKK_RSA != keyType) { + *pError = CKR_ATTRIBUTE_VALUE_INVALID; + return (ckcapiInternalObject *)NULL; + } + + decrypt = nss_ckcapi_GetBoolAttribute(CKA_DECRYPT, + pTemplate, ulAttributeCount, pError); + if (CKR_TEMPLATE_INCOMPLETE == *pError) { + decrypt = PR_TRUE; /* default to true */ + } + decrypt = decrypt || nss_ckcapi_GetBoolAttribute(CKA_UNWRAP, + pTemplate, ulAttributeCount, pError); + if (CKR_TEMPLATE_INCOMPLETE == *pError) { + decrypt = PR_TRUE; /* default to true */ + } + keySpec = decrypt ? AT_KEYEXCHANGE : AT_SIGNATURE; + + *pError = nss_ckcapi_GetAttribute(CKA_MODULUS, pTemplate, + ulAttributeCount, &modulus); + if (CKR_OK != *pError) { + return (ckcapiInternalObject *)NULL; + } + *pError = nss_ckcapi_GetAttribute(CKA_PUBLIC_EXPONENT, pTemplate, + ulAttributeCount, &publicExponent); + if (CKR_OK != *pError) { + return (ckcapiInternalObject *)NULL; + } + *pError = nss_ckcapi_GetAttribute(CKA_PRIVATE_EXPONENT, pTemplate, + ulAttributeCount, &privateExponent); + if (CKR_OK != *pError) { + return (ckcapiInternalObject *)NULL; + } + *pError = nss_ckcapi_GetAttribute(CKA_PRIME_1, pTemplate, + ulAttributeCount, &prime1); + if (CKR_OK != *pError) { + return (ckcapiInternalObject *)NULL; + } + *pError = nss_ckcapi_GetAttribute(CKA_PRIME_2, pTemplate, + ulAttributeCount, &prime2); + if (CKR_OK != *pError) { + return (ckcapiInternalObject *)NULL; + } + *pError = nss_ckcapi_GetAttribute(CKA_EXPONENT_1, pTemplate, + ulAttributeCount, &exponent1); + if (CKR_OK != *pError) { + return (ckcapiInternalObject *)NULL; + } + *pError = nss_ckcapi_GetAttribute(CKA_EXPONENT_2, pTemplate, + ulAttributeCount, &exponent2); + if (CKR_OK != *pError) { + return (ckcapiInternalObject *)NULL; + } + *pError = nss_ckcapi_GetAttribute(CKA_COEFFICIENT, pTemplate, + ulAttributeCount, &coefficient); + if (CKR_OK != *pError) { + return (ckcapiInternalObject *)NULL; + } + *pError = nss_ckcapi_GetAttribute(CKA_ID, pTemplate, + ulAttributeCount, &keyID); + if (CKR_OK != *pError) { + return (ckcapiInternalObject *)NULL; + } + providerName = ckcapi_getDefaultProvider(pError); + if ((char *)NULL == providerName) { + return (ckcapiInternalObject *)NULL; + } + containerName = ckcapi_getContainer(pError, &keyID); + if ((char *)NULL == containerName) { + goto loser; + } + rc = CryptAcquireContext(&hProv, containerName, providerName, + PROV_RSA_FULL, CRYPT_NEWKEYSET); + if (!rc) { + msError = GetLastError(); + *pError = CKR_DEVICE_ERROR; + goto loser; + } + + *pError = ckcapi_buildPrivateKeyBlob( + &keyBlob, + &modulus, + &publicExponent, + &privateExponent, + &prime1, + &prime2, + &exponent1, + &exponent2, + &coefficient, + decrypt); + if (CKR_OK != *pError) { + goto loser; + } + + rc = CryptImportKey(hProv, keyBlob.data, keyBlob.size, + 0, CRYPT_EXPORTABLE, &hKey); + if (!rc) { + msError = GetLastError(); + *pError = CKR_DEVICE_ERROR; + goto loser; + } + + idData = nss_ZNEWARRAY(NULL, char, keyID.size); + if ((void *)NULL == idData) { + *pError = CKR_HOST_MEMORY; + goto loser; + } + nsslibc_memcpy(idData, keyID.data, keyID.size); + + provInfo.pwszContainerName = nss_ckcapi_UTF8ToWide(containerName); + provInfo.pwszProvName = nss_ckcapi_UTF8ToWide(providerName); + provInfo.dwProvType = PROV_RSA_FULL; + provInfo.dwFlags = 0; + provInfo.cProvParam = 0; + provInfo.rgProvParam = NULL; + provInfo.dwKeySpec = keySpec; + + msKeyID.cbData = keyID.size; + msKeyID.pbData = keyID.data; + + rc = CryptSetKeyIdentifierProperty(&msKeyID, CERT_KEY_PROV_INFO_PROP_ID, + 0, NULL, NULL, &provInfo); + if (!rc) { + goto loser; + } + + /* handle error here */ + io = nss_ZNEW(NULL, ckcapiInternalObject); + if ((ckcapiInternalObject *)NULL == io) { + *pError = CKR_HOST_MEMORY; + goto loser; + } + io->type = ckcapiBareKey; + io->objClass = CKO_PRIVATE_KEY; + io->u.key.provInfo = provInfo; + io->u.key.provName = providerName; + io->u.key.containerName = containerName; + io->u.key.hProv = hProv; /* save the handle */ + io->idData = idData; + io->id.data = idData; + io->id.size = keyID.size; + /* done with the key handle */ + CryptDestroyKey(hKey); + return io; + +loser: + nss_ZFreeIf(containerName); + nss_ZFreeIf(providerName); + nss_ZFreeIf(idData); + if (0 != hProv) { + CryptReleaseContext(hProv, 0); + } + if (0 != hKey) { + CryptDestroyKey(hKey); + } + return (ckcapiInternalObject *)NULL; +} + +NSS_EXTERN NSSCKMDObject * +nss_ckcapi_CreateObject( + NSSCKFWSession *fwSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + CK_RV *pError) +{ + CK_OBJECT_CLASS objClass; + ckcapiInternalObject *io = NULL; + CK_BBOOL isToken; + + /* + * only create token objects + */ + isToken = nss_ckcapi_GetBoolAttribute(CKA_TOKEN, pTemplate, + ulAttributeCount, pError); + if (CKR_OK != *pError) { + return (NSSCKMDObject *)NULL; + } + if (!isToken) { + *pError = CKR_ATTRIBUTE_VALUE_INVALID; + return (NSSCKMDObject *)NULL; + } + + /* + * only create keys and certs. + */ + objClass = nss_ckcapi_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_ckcapi_CreateCertificate(fwSession, pTemplate, + ulAttributeCount, pError); + } else if (objClass == CKO_PRIVATE_KEY) { + io = nss_ckcapi_CreatePrivateKey(fwSession, pTemplate, + ulAttributeCount, pError); + } else { + *pError = CKR_ATTRIBUTE_VALUE_INVALID; + } + + if ((ckcapiInternalObject *)NULL == io) { + return (NSSCKMDObject *)NULL; + } + return nss_ckcapi_CreateMDObject(NULL, io, pError); +} diff --git a/security/nss/lib/ckfw/capi/constants.c b/security/nss/lib/ckfw/capi/constants.c new file mode 100644 index 0000000000..0d4b70110e --- /dev/null +++ b/security/nss/lib/ckfw/capi/constants.c @@ -0,0 +1,63 @@ +/* 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/. */ + +/* + * ckcapi/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 */ + +#ifndef NSSCAPI_H +#include "nsscapi.h" +#endif /* NSSCAPI_H */ + +NSS_IMPLEMENT_DATA const CK_VERSION + nss_ckcapi_CryptokiVersion = { + NSS_CKCAPI_CRYPTOKI_VERSION_MAJOR, + NSS_CKCAPI_CRYPTOKI_VERSION_MINOR + }; + +NSS_IMPLEMENT_DATA const NSSUTF8 * + nss_ckcapi_ManufacturerID = (NSSUTF8 *)"Mozilla Foundation"; + +NSS_IMPLEMENT_DATA const NSSUTF8 * + nss_ckcapi_LibraryDescription = (NSSUTF8 *)"NSS Access to Microsoft Certificate Store"; + +NSS_IMPLEMENT_DATA const CK_VERSION + nss_ckcapi_LibraryVersion = { + NSS_CKCAPI_LIBRARY_VERSION_MAJOR, + NSS_CKCAPI_LIBRARY_VERSION_MINOR + }; + +NSS_IMPLEMENT_DATA const NSSUTF8 * + nss_ckcapi_SlotDescription = (NSSUTF8 *)"Microsoft Certificate Store"; + +NSS_IMPLEMENT_DATA const CK_VERSION + nss_ckcapi_HardwareVersion = { + NSS_CKCAPI_HARDWARE_VERSION_MAJOR, + NSS_CKCAPI_HARDWARE_VERSION_MINOR + }; + +NSS_IMPLEMENT_DATA const CK_VERSION + nss_ckcapi_FirmwareVersion = { + NSS_CKCAPI_FIRMWARE_VERSION_MAJOR, + NSS_CKCAPI_FIRMWARE_VERSION_MINOR + }; + +NSS_IMPLEMENT_DATA const NSSUTF8 * + nss_ckcapi_TokenLabel = (NSSUTF8 *)"Microsoft Certificate Store"; + +NSS_IMPLEMENT_DATA const NSSUTF8 * + nss_ckcapi_TokenModel = (NSSUTF8 *)"1"; + +NSS_IMPLEMENT_DATA const NSSUTF8 * + nss_ckcapi_TokenSerialNumber = (NSSUTF8 *)"1"; diff --git a/security/nss/lib/ckfw/capi/crsa.c b/security/nss/lib/ckfw/capi/crsa.c new file mode 100644 index 0000000000..62f90acb6a --- /dev/null +++ b/security/nss/lib/ckfw/capi/crsa.c @@ -0,0 +1,687 @@ +/* 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 "ckcapi.h" +#include "secdert.h" + +#define SSL3_SHAMD5_HASH_SIZE 36 /* LEN_MD5 (16) + LEN_SHA1 (20) */ + +/* + * ckcapi/crsa.c + * + * This file implements the NSSCKMDMechnaism and NSSCKMDCryptoOperation objects + * for the RSA operation on the CAPI cryptoki module. + */ + +/* + * write a Decimal value to a string + */ + +static char * +putDecimalString(char *cstr, unsigned long value) +{ + unsigned long tenpower; + int first = 1; + + for (tenpower = 10000000; tenpower; tenpower /= 10) { + unsigned char digit = (unsigned char)(value / tenpower); + value = value % tenpower; + + /* drop leading zeros */ + if (first && (0 == digit)) { + continue; + } + first = 0; + *cstr++ = digit + '0'; + } + + /* if value was zero, put one of them out */ + if (first) { + *cstr++ = '0'; + } + return cstr; +} + +/* + * Create a Capi OID string value from a DER OID + */ +static char * +nss_ckcapi_GetOidString( + unsigned char *oidTag, + unsigned int oidTagSize, + CK_RV *pError) +{ + unsigned char *oid; + char *oidStr; + char *cstr; + unsigned long value; + unsigned int oidSize; + + if (DER_OBJECT_ID != *oidTag) { + /* wasn't an oid */ + *pError = CKR_DATA_INVALID; + return NULL; + } + oid = nss_ckcapi_DERUnwrap(oidTag, oidTagSize, &oidSize, NULL); + + if (oidSize < 2) { + *pError = CKR_DATA_INVALID; + return NULL; + } + + oidStr = nss_ZNEWARRAY(NULL, char, oidSize * 4); + if ((char *)NULL == oidStr) { + *pError = CKR_HOST_MEMORY; + return NULL; + } + cstr = oidStr; + cstr = putDecimalString(cstr, (*oid) / 40); + *cstr++ = '.'; + cstr = putDecimalString(cstr, (*oid) % 40); + oidSize--; + + value = 0; + while (oidSize--) { + oid++; + value = (value << 7) + (*oid & 0x7f); + if (0 == (*oid & 0x80)) { + *cstr++ = '.'; + cstr = putDecimalString(cstr, value); + value = 0; + } + } + + *cstr = 0; /* NULL terminate */ + + if (value != 0) { + nss_ZFreeIf(oidStr); + *pError = CKR_DATA_INVALID; + return NULL; + } + return oidStr; +} + +/* + * PKCS #11 sign for RSA expects to take a fully DER-encoded hash value, + * which includes the hash OID. CAPI expects to take a Hash Context. While + * CAPI does have the capability of setting a raw hash value, it does not + * have the ability to sign an arbitrary value. This function tries to + * reduce the passed in data into something that CAPI could actually sign. + */ +static CK_RV +ckcapi_GetRawHash( + const NSSItem *input, + NSSItem *hash, + ALG_ID *hashAlg) +{ + unsigned char *current; + unsigned char *algid; + unsigned char *oid; + unsigned char *hashData; + char *oidStr; + CK_RV error; + unsigned int oidSize; + unsigned int size; + /* + * there are 2 types of hashes NSS typically tries to sign, regular + * RSA signature format (with encoded DER_OIDS), and SSL3 Signed hashes. + * CAPI knows not to add any oids to SSL3_Signed hashes, so if we have any + * random hash that is exactly the same size as an SSL3 hash, then we can + * just pass the data through. CAPI has know way of knowing if the value + * is really a combined hash or some other arbitrary data, so it's safe to + * handle this case first. + */ + if (SSL3_SHAMD5_HASH_SIZE == input->size) { + hash->data = input->data; + hash->size = input->size; + *hashAlg = CALG_SSL3_SHAMD5; + return CKR_OK; + } + + current = (unsigned char *)input->data; + + /* make sure we have a sequence tag */ + if ((DER_SEQUENCE | DER_CONSTRUCTED) != *current) { + return CKR_DATA_INVALID; + } + + /* parse the input block to get 1) the hash oid, and 2) the raw hash value. + * unfortunatly CAPI doesn't have a builtin function to do this work, so + * we go ahead and do it by hand here. + * + * format is: + * SEQUENCE { + * SECQUENCE { // algid + * OID {} // oid + * ANY {} // optional params + * } + * OCTECT {} // hash + */ + + /* unwrap */ + algid = nss_ckcapi_DERUnwrap(current, input->size, &size, NULL); + + if (algid + size != current + input->size) { + /* make sure there is not extra data at the end */ + return CKR_DATA_INVALID; + } + + if ((DER_SEQUENCE | DER_CONSTRUCTED) != *algid) { + /* wasn't an algid */ + return CKR_DATA_INVALID; + } + oid = nss_ckcapi_DERUnwrap(algid, size, &oidSize, &hashData); + + if (DER_OCTET_STRING != *hashData) { + /* wasn't a hash */ + return CKR_DATA_INVALID; + } + + /* get the real hash */ + current = hashData; + size = size - (hashData - algid); + hash->data = nss_ckcapi_DERUnwrap(current, size, &hash->size, NULL); + + /* get the real oid as a string. Again, Microsoft does not + * export anything that does this for us */ + oidStr = nss_ckcapi_GetOidString(oid, oidSize, &error); + if ((char *)NULL == oidStr) { + return error; + } + + /* look up the hash alg from the oid (fortunately CAPI does to this) */ + *hashAlg = CertOIDToAlgId(oidStr); + nss_ZFreeIf(oidStr); + if (0 == *hashAlg) { + return CKR_HOST_MEMORY; + } + + /* hash looks reasonably consistent, we should be able to sign it now */ + return CKR_OK; +} + +/* + * So everyone else in the worlds stores their bignum data MSB first, but not + * Microsoft, we need to byte swap everything coming into and out of CAPI. + */ +void +ckcapi_ReverseData(NSSItem *item) +{ + int end = (item->size) - 1; + int middle = (item->size) / 2; + unsigned char *buf = item->data; + int i; + + for (i = 0; i < middle; i++) { + unsigned char tmp = buf[i]; + buf[i] = buf[end - i]; + buf[end - i] = tmp; + } + return; +} + +typedef struct ckcapiInternalCryptoOperationRSAPrivStr + ckcapiInternalCryptoOperationRSAPriv; +struct ckcapiInternalCryptoOperationRSAPrivStr { + NSSCKMDCryptoOperation mdOperation; + NSSCKMDMechanism *mdMechanism; + ckcapiInternalObject *iKey; + HCRYPTPROV hProv; + DWORD keySpec; + HCRYPTKEY hKey; + NSSItem *buffer; +}; + +/* + * ckcapi_mdCryptoOperationRSAPriv_Create + */ +static NSSCKMDCryptoOperation * +ckcapi_mdCryptoOperationRSAPriv_Create( + const NSSCKMDCryptoOperation *proto, + NSSCKMDMechanism *mdMechanism, + NSSCKMDObject *mdKey, + CK_RV *pError) +{ + ckcapiInternalObject *iKey = (ckcapiInternalObject *)mdKey->etc; + const NSSItem *classItem = nss_ckcapi_FetchAttribute(iKey, CKA_CLASS); + const NSSItem *keyType = nss_ckcapi_FetchAttribute(iKey, CKA_KEY_TYPE); + ckcapiInternalCryptoOperationRSAPriv *iOperation; + CK_RV error; + HCRYPTPROV hProv; + DWORD keySpec; + HCRYPTKEY hKey; + + /* 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; + } + + error = nss_ckcapi_FetchKeyContainer(iKey, &hProv, &keySpec, &hKey); + if (error != CKR_OK) { + *pError = error; + return (NSSCKMDCryptoOperation *)NULL; + } + + iOperation = nss_ZNEW(NULL, ckcapiInternalCryptoOperationRSAPriv); + if ((ckcapiInternalCryptoOperationRSAPriv *)NULL == iOperation) { + *pError = CKR_HOST_MEMORY; + return (NSSCKMDCryptoOperation *)NULL; + } + iOperation->mdMechanism = mdMechanism; + iOperation->iKey = iKey; + iOperation->hProv = hProv; + iOperation->keySpec = keySpec; + iOperation->hKey = hKey; + + nsslibc_memcpy(&iOperation->mdOperation, + proto, sizeof(NSSCKMDCryptoOperation)); + iOperation->mdOperation.etc = iOperation; + + return &iOperation->mdOperation; +} + +static CK_RV +ckcapi_mdCryptoOperationRSAPriv_Destroy( + NSSCKMDCryptoOperation *mdOperation, + NSSCKFWCryptoOperation *fwOperation, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + ckcapiInternalCryptoOperationRSAPriv *iOperation = + (ckcapiInternalCryptoOperationRSAPriv *)mdOperation->etc; + + if (iOperation->hKey) { + CryptDestroyKey(iOperation->hKey); + } + if (iOperation->buffer) { + nssItem_Destroy(iOperation->buffer); + } + nss_ZFreeIf(iOperation); + return CKR_OK; +} + +static CK_ULONG +ckcapi_mdCryptoOperationRSA_GetFinalLength( + NSSCKMDCryptoOperation *mdOperation, + NSSCKFWCryptoOperation *fwOperation, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + ckcapiInternalCryptoOperationRSAPriv *iOperation = + (ckcapiInternalCryptoOperationRSAPriv *)mdOperation->etc; + const NSSItem *modulus = + nss_ckcapi_FetchAttribute(iOperation->iKey, CKA_MODULUS); + + return modulus->size; +} + +/* + * ckcapi_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 +ckcapi_mdCryptoOperationRSADecrypt_GetOperationLength( + NSSCKMDCryptoOperation *mdOperation, + NSSCKFWCryptoOperation *fwOperation, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + const NSSItem *input, + CK_RV *pError) +{ + ckcapiInternalCryptoOperationRSAPriv *iOperation = + (ckcapiInternalCryptoOperationRSAPriv *)mdOperation->etc; + BOOL rc; + + /* Microsoft's Decrypt operation works in place. Since we don't want + * to trash our input buffer, we make a copy of it */ + iOperation->buffer = nssItem_Duplicate((NSSItem *)input, NULL, NULL); + if ((NSSItem *)NULL == iOperation->buffer) { + *pError = CKR_HOST_MEMORY; + return 0; + } + /* Sigh, reverse it */ + ckcapi_ReverseData(iOperation->buffer); + + rc = CryptDecrypt(iOperation->hKey, 0, TRUE, 0, + iOperation->buffer->data, &iOperation->buffer->size); + if (!rc) { + DWORD msError = GetLastError(); + switch (msError) { + case NTE_BAD_DATA: + *pError = + CKR_ENCRYPTED_DATA_INVALID; + break; + case NTE_FAIL: + case NTE_BAD_UID: + *pError = + CKR_DEVICE_ERROR; + break; + default: + *pError = + CKR_GENERAL_ERROR; + } + return 0; + } + + return iOperation->buffer->size; +} + +/* + * ckcapi_mdCryptoOperationRSADecrypt_UpdateFinal + * + * NOTE: ckcapi_mdCryptoOperationRSADecrypt_GetOperationLength is presumed to + * have been called previously. + */ +static CK_RV +ckcapi_mdCryptoOperationRSADecrypt_UpdateFinal( + NSSCKMDCryptoOperation *mdOperation, + NSSCKFWCryptoOperation *fwOperation, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + const NSSItem *input, + NSSItem *output) +{ + ckcapiInternalCryptoOperationRSAPriv *iOperation = + (ckcapiInternalCryptoOperationRSAPriv *)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; +} + +/* + * ckcapi_mdCryptoOperationRSASign_UpdateFinal + * + */ +static CK_RV +ckcapi_mdCryptoOperationRSASign_UpdateFinal( + NSSCKMDCryptoOperation *mdOperation, + NSSCKFWCryptoOperation *fwOperation, + NSSCKMDSession *mdSession, + NSSCKFWSession *fwSession, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + const NSSItem *input, + NSSItem *output) +{ + ckcapiInternalCryptoOperationRSAPriv *iOperation = + (ckcapiInternalCryptoOperationRSAPriv *)mdOperation->etc; + CK_RV error = CKR_OK; + DWORD msError; + NSSItem hash; + HCRYPTHASH hHash = 0; + ALG_ID hashAlg; + DWORD hashSize; + DWORD len; /* temp length value we throw away */ + BOOL rc; + + /* + * PKCS #11 sign for RSA expects to take a fully DER-encoded hash value, + * which includes the hash OID. CAPI expects to take a Hash Context. While + * CAPI does have the capability of setting a raw hash value, it does not + * have the ability to sign an arbitrary value. This function tries to + * reduce the passed in data into something that CAPI could actually sign. + */ + error = ckcapi_GetRawHash(input, &hash, &hashAlg); + if (CKR_OK != error) { + goto loser; + } + + rc = CryptCreateHash(iOperation->hProv, hashAlg, 0, 0, &hHash); + if (!rc) { + goto loser; + } + + /* make sure the hash lens match before we set it */ + len = sizeof(DWORD); + rc = CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&hashSize, &len, 0); + if (!rc) { + goto loser; + } + + if (hash.size != hashSize) { + /* The input must have been bad for this to happen */ + error = CKR_DATA_INVALID; + goto loser; + } + + /* we have an explicit hash, set it, note that the length is + * implicit by the hashAlg used in create */ + rc = CryptSetHashParam(hHash, HP_HASHVAL, hash.data, 0); + if (!rc) { + goto loser; + } + + /* OK, we have the data in a hash structure, sign it! */ + rc = CryptSignHash(hHash, iOperation->keySpec, NULL, 0, + output->data, &output->size); + if (!rc) { + goto loser; + } + + /* Don't return a signature that might have been broken because of a cosmic + * ray, or a broken processor, verify that it is valid... */ + rc = CryptVerifySignature(hHash, output->data, output->size, + iOperation->hKey, NULL, 0); + if (!rc) { + goto loser; + } + + /* OK, Microsoft likes to do things completely differently than anyone + * else. We need to reverse the data we received here */ + ckcapi_ReverseData(output); + CryptDestroyHash(hHash); + return CKR_OK; + +loser: + /* map the microsoft error */ + if (CKR_OK == error) { + msError = GetLastError(); + switch (msError) { + case ERROR_NOT_ENOUGH_MEMORY: + error = + CKR_HOST_MEMORY; + break; + case NTE_NO_MEMORY: + error = + CKR_DEVICE_MEMORY; + break; + case ERROR_MORE_DATA: + return CKR_BUFFER_TOO_SMALL; + case ERROR_INVALID_PARAMETER: /* these params were derived from the */ + case ERROR_INVALID_HANDLE: /* inputs, so if they are bad, the input */ + case NTE_BAD_ALGID: /* data is bad */ + case NTE_BAD_HASH: + error = + CKR_DATA_INVALID; + break; + case ERROR_BUSY: + case NTE_FAIL: + case NTE_BAD_UID: + error = + CKR_DEVICE_ERROR; + break; + default: + error = + CKR_GENERAL_ERROR; + break; + } + } + if (hHash) { + CryptDestroyHash(hHash); + } + return error; +} + +NSS_IMPLEMENT_DATA const NSSCKMDCryptoOperation + ckcapi_mdCryptoOperationRSADecrypt_proto = { + NULL, /* etc */ + ckcapi_mdCryptoOperationRSAPriv_Destroy, + NULL, /* GetFinalLengh - not needed for one shot Decrypt/Encrypt */ + ckcapi_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 */ + ckcapi_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 + ckcapi_mdCryptoOperationRSASign_proto = { + NULL, /* etc */ + ckcapi_mdCryptoOperationRSAPriv_Destroy, + ckcapi_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 */ + ckcapi_mdCryptoOperationRSASign_UpdateFinal, + NULL, /* UpdateCombo - not needed for one shot operation */ + NULL, /* DigetKey - not needed for one shot operation */ + (void *)NULL /* null terminator */ + }; + +/********** NSSCKMDMechansim functions ***********************/ +/* + * ckcapi_mdMechanismRSA_Destroy + */ +static void +ckcapi_mdMechanismRSA_Destroy( + NSSCKMDMechanism *mdMechanism, + NSSCKFWMechanism *fwMechanism, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + nss_ZFreeIf(fwMechanism); +} + +/* + * ckcapi_mdMechanismRSA_GetMinKeySize + */ +static CK_ULONG +ckcapi_mdMechanismRSA_GetMinKeySize( + NSSCKMDMechanism *mdMechanism, + NSSCKFWMechanism *fwMechanism, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return 384; +} + +/* + * ckcapi_mdMechanismRSA_GetMaxKeySize + */ +static CK_ULONG +ckcapi_mdMechanismRSA_GetMaxKeySize( + NSSCKMDMechanism *mdMechanism, + NSSCKFWMechanism *fwMechanism, + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return 16384; +} + +/* + * ckcapi_mdMechanismRSA_DecryptInit + */ +static NSSCKMDCryptoOperation * +ckcapi_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 ckcapi_mdCryptoOperationRSAPriv_Create( + &ckcapi_mdCryptoOperationRSADecrypt_proto, + mdMechanism, mdKey, pError); +} + +/* + * ckcapi_mdMechanismRSA_SignInit + */ +static NSSCKMDCryptoOperation * +ckcapi_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 ckcapi_mdCryptoOperationRSAPriv_Create( + &ckcapi_mdCryptoOperationRSASign_proto, + mdMechanism, mdKey, pError); +} + +NSS_IMPLEMENT_DATA const NSSCKMDMechanism + nss_ckcapi_mdMechanismRSA = { + (void *)NULL, /* etc */ + ckcapi_mdMechanismRSA_Destroy, + ckcapi_mdMechanismRSA_GetMinKeySize, + ckcapi_mdMechanismRSA_GetMaxKeySize, + NULL, /* GetInHardware - default false */ + NULL, /* EncryptInit - default errs */ + ckcapi_mdMechanismRSA_DecryptInit, + NULL, /* DigestInit - default errs*/ + ckcapi_mdMechanismRSA_SignInit, + NULL, /* VerifyInit - default errs */ + ckcapi_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/capi/csession.c b/security/nss/lib/ckfw/capi/csession.c new file mode 100644 index 0000000000..5b268ead1e --- /dev/null +++ b/security/nss/lib/ckfw/capi/csession.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 "ckcapi.h" + +/* + * ckcapi/csession.c + * + * This file implements the NSSCKMDSession object for the + * "nss to capi" cryptoki module. + */ + +static NSSCKMDFindObjects * +ckcapi_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_ckcapi_FindObjectsInit(fwSession, pTemplate, ulAttributeCount, pError); +} + +static NSSCKMDObject * +ckcapi_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_ckcapi_CreateObject(fwSession, pTemplate, ulAttributeCount, pError); +} + +NSS_IMPLEMENT NSSCKMDSession * +nss_ckcapi_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 = ckcapi_mdSession_CreateObject; + /* rv->CopyObject */ + rv->FindObjectsInit = ckcapi_mdSession_FindObjectsInit; + /* rv->SeedRandom */ + /* rv->GetRandom */ + /* rv->null */ + + return rv; +} diff --git a/security/nss/lib/ckfw/capi/cslot.c b/security/nss/lib/ckfw/capi/cslot.c new file mode 100644 index 0000000000..8a39b7888f --- /dev/null +++ b/security/nss/lib/ckfw/capi/cslot.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 "ckcapi.h" + +/* + * ckcapi/cslot.c + * + * This file implements the NSSCKMDSlot object for the + * "nss to capi" cryptoki module. + */ + +static NSSUTF8 * +ckcapi_mdSlot_GetSlotDescription( + NSSCKMDSlot *mdSlot, + NSSCKFWSlot *fwSlot, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (NSSUTF8 *)nss_ckcapi_SlotDescription; +} + +static NSSUTF8 * +ckcapi_mdSlot_GetManufacturerID( + NSSCKMDSlot *mdSlot, + NSSCKFWSlot *fwSlot, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (NSSUTF8 *)nss_ckcapi_ManufacturerID; +} + +static CK_VERSION +ckcapi_mdSlot_GetHardwareVersion( + NSSCKMDSlot *mdSlot, + NSSCKFWSlot *fwSlot, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return nss_ckcapi_HardwareVersion; +} + +static CK_VERSION +ckcapi_mdSlot_GetFirmwareVersion( + NSSCKMDSlot *mdSlot, + NSSCKFWSlot *fwSlot, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return nss_ckcapi_FirmwareVersion; +} + +static NSSCKMDToken * +ckcapi_mdSlot_GetToken( + NSSCKMDSlot *mdSlot, + NSSCKFWSlot *fwSlot, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (NSSCKMDToken *)&nss_ckcapi_mdToken; +} + +NSS_IMPLEMENT_DATA const NSSCKMDSlot + nss_ckcapi_mdSlot = { + (void *)NULL, /* etc */ + NULL, /* Initialize */ + NULL, /* Destroy */ + ckcapi_mdSlot_GetSlotDescription, + ckcapi_mdSlot_GetManufacturerID, + NULL, /* GetTokenPresent -- defaults to true */ + NULL, /* GetRemovableDevice -- defaults to false */ + NULL, /* GetHardwareSlot -- defaults to false */ + ckcapi_mdSlot_GetHardwareVersion, + ckcapi_mdSlot_GetFirmwareVersion, + ckcapi_mdSlot_GetToken, + (void *)NULL /* null terminator */ + }; diff --git a/security/nss/lib/ckfw/capi/ctoken.c b/security/nss/lib/ckfw/capi/ctoken.c new file mode 100644 index 0000000000..cc95c17b68 --- /dev/null +++ b/security/nss/lib/ckfw/capi/ctoken.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 "ckcapi.h" + +/* + * ckcapi/ctoken.c + * + * This file implements the NSSCKMDToken object for the + * "nss to capi" cryptoki module. + */ + +static NSSUTF8 * +ckcapi_mdToken_GetLabel( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (NSSUTF8 *)nss_ckcapi_TokenLabel; +} + +static NSSUTF8 * +ckcapi_mdToken_GetManufacturerID( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (NSSUTF8 *)nss_ckcapi_ManufacturerID; +} + +static NSSUTF8 * +ckcapi_mdToken_GetModel( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (NSSUTF8 *)nss_ckcapi_TokenModel; +} + +static NSSUTF8 * +ckcapi_mdToken_GetSerialNumber( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_RV *pError) +{ + return (NSSUTF8 *)nss_ckcapi_TokenSerialNumber; +} + +static CK_BBOOL +ckcapi_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 +ckcapi_mdToken_GetUserPinInitialized( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return CK_TRUE; +} + +static CK_VERSION +ckcapi_mdToken_GetHardwareVersion( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return nss_ckcapi_HardwareVersion; +} + +static CK_VERSION +ckcapi_mdToken_GetFirmwareVersion( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return nss_ckcapi_FirmwareVersion; +} + +static NSSCKMDSession * +ckcapi_mdToken_OpenSession( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + NSSCKFWSession *fwSession, + CK_BBOOL rw, + CK_RV *pError) +{ + return nss_ckcapi_CreateSession(fwSession, pError); +} + +static CK_ULONG +ckcapi_mdToken_GetMechanismCount( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance) +{ + return (CK_ULONG)1; +} + +static CK_RV +ckcapi_mdToken_GetMechanismTypes( + NSSCKMDToken *mdToken, + NSSCKFWToken *fwToken, + NSSCKMDInstance *mdInstance, + NSSCKFWInstance *fwInstance, + CK_MECHANISM_TYPE types[]) +{ + types[0] = CKM_RSA_PKCS; + return CKR_OK; +} + +static NSSCKMDMechanism * +ckcapi_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_ckcapi_mdMechanismRSA; +} + +NSS_IMPLEMENT_DATA const NSSCKMDToken + nss_ckcapi_mdToken = { + (void *)NULL, /* etc */ + NULL, /* Setup */ + NULL, /* Invalidate */ + NULL, /* InitToken -- default errs */ + ckcapi_mdToken_GetLabel, + ckcapi_mdToken_GetManufacturerID, + ckcapi_mdToken_GetModel, + ckcapi_mdToken_GetSerialNumber, + NULL, /* GetHasRNG -- default is false */ + ckcapi_mdToken_GetIsWriteProtected, + NULL, /* GetLoginRequired -- default is false */ + ckcapi_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 */ + ckcapi_mdToken_GetHardwareVersion, + ckcapi_mdToken_GetFirmwareVersion, + NULL, /* GetUTCTime -- no clock */ + ckcapi_mdToken_OpenSession, + ckcapi_mdToken_GetMechanismCount, + ckcapi_mdToken_GetMechanismTypes, + ckcapi_mdToken_GetMechanism, + (void *)NULL /* null terminator */ + }; diff --git a/security/nss/lib/ckfw/capi/manifest.mn b/security/nss/lib/ckfw/capi/manifest.mn new file mode 100644 index 0000000000..c1003d00e0 --- /dev/null +++ b/security/nss/lib/ckfw/capi/manifest.mn @@ -0,0 +1,35 @@ +# +# 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 + +EXPORTS = \ + nsscapi.h \ + $(NULL) + +CSRCS = \ + anchor.c \ + constants.c \ + cfind.c \ + cinst.c \ + cobject.c \ + crsa.c \ + csession.c \ + cslot.c \ + ctoken.c \ + ckcapiver.c \ + staticobj.c \ + $(NULL) + +REQUIRES = nspr + +LIBRARY_NAME = nsscapi +MAPFILE = $(OBJDIR)/$(LIBRARY_NAME).def +LIBRARY = $(NULL) +IMPORT_LIBRARY = $(NULL) + +#EXTRA_SHARED_LIBS = -L$(DIST)/lib -lnssckfw -lnssb -lplc4 -lplds4 diff --git a/security/nss/lib/ckfw/capi/nsscapi.def b/security/nss/lib/ckfw/capi/nsscapi.def new file mode 100644 index 0000000000..d7e68c7f4f --- /dev/null +++ b/security/nss/lib/ckfw/capi/nsscapi.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 ";-" +;+ +;+NSS_3.1 { # NSS 3.1 release +;+ global: +LIBRARY nsscapi ;- +EXPORTS ;- +C_GetFunctionList; +;+ local: +;+*; +;+}; diff --git a/security/nss/lib/ckfw/capi/nsscapi.h b/security/nss/lib/ckfw/capi/nsscapi.h new file mode 100644 index 0000000000..78bf38b284 --- /dev/null +++ b/security/nss/lib/ckfw/capi/nsscapi.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 NSSCAPI_H +#define NSSCAPI_H + +/* + * NSS CKCAPI Version numbers. + * + * These are the version numbers for the capi 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_CKCAPI_CRYPTOKI_VERSION_MAJOR 2 +#define NSS_CKCAPI_CRYPTOKI_VERSION_MINOR 20 + +/* These version numbers detail the changes + * to the list of trusted certificates. + * + * NSS_CKCAPI_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_CKCAPI_LIBRARY_VERSION_MAJOR 1 +#define NSS_CKCAPI_LIBRARY_VERSION_MINOR 1 +#define NSS_CKCAPI_LIBRARY_VERSION "1.1" + +/* These version numbers detail the semantic changes to the ckfw engine. */ +#define NSS_CKCAPI_HARDWARE_VERSION_MAJOR 1 +#define NSS_CKCAPI_HARDWARE_VERSION_MINOR 0 + +/* These version numbers detail the semantic changes to ckbi itself + * (new PKCS #11 objects), etc. */ +#define NSS_CKCAPI_FIRMWARE_VERSION_MAJOR 1 +#define NSS_CKCAPI_FIRMWARE_VERSION_MINOR 0 + +#endif /* NSSCKBI_H */ diff --git a/security/nss/lib/ckfw/capi/nsscapi.rc b/security/nss/lib/ckfw/capi/nsscapi.rc new file mode 100644 index 0000000000..27912009b4 --- /dev/null +++ b/security/nss/lib/ckfw/capi/nsscapi.rc @@ -0,0 +1,64 @@ +/* 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 "nsscapi.h" +#include + +#define MY_LIBNAME "nsscapi" +#define MY_FILEDESCRIPTION "NSS Access to Microsoft CAPI" + +#ifdef _DEBUG +#define MY_DEBUG_STR " (debug)" +#define MY_FILEFLAGS_1 VS_FF_DEBUG +#else +#define MY_DEBUG_STR "" +#define MY_FILEFLAGS_1 0x0L +#endif +#if NSS_BETA +#define MY_FILEFLAGS_2 MY_FILEFLAGS_1|VS_FF_PRERELEASE +#else +#define MY_FILEFLAGS_2 MY_FILEFLAGS_1 +#endif + +#ifdef WINNT +#define MY_FILEOS VOS_NT_WINDOWS32 +#else +#define MY_FILEOS VOS__WINDOWS32 +#endif + +#define MY_INTERNAL_NAME MY_LIBNAME + +///////////////////////////////////////////////////////////////////////////// +// +// Version-information resource +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION NSS_CKCAPI_LIBRARY_VERSION_MAJOR,NSS_CKCAPI_LIBRARY_VERSION_MINOR,0,0 + PRODUCTVERSION NSS_CKCAPI_LIBRARY_VERSION_MAJOR,NSS_CKCAPI_LIBRARY_VERSION_MINOR,0,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS MY_FILEFLAGS_2 + FILEOS MY_FILEOS + FILETYPE VFT_DLL + FILESUBTYPE 0x0L // not used + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" // Lang=US English, CharSet=Unicode + BEGIN + VALUE "CompanyName", "Mozilla Foundation\0" + VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0" + VALUE "FileVersion", NSS_CKCAPI_LIBRARY_VERSION "\0" + VALUE "InternalName", MY_INTERNAL_NAME "\0" + VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0" + VALUE "ProductName", "Network Security Services\0" + VALUE "ProductVersion", NSS_CKCAPI_LIBRARY_VERSION "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/security/nss/lib/ckfw/capi/staticobj.c b/security/nss/lib/ckfw/capi/staticobj.c new file mode 100644 index 0000000000..2d67a34b3f --- /dev/null +++ b/security/nss/lib/ckfw/capi/staticobj.c @@ -0,0 +1,40 @@ +/* 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 CKCAPI_H +#include "ckcapi.h" +#endif /* CKCAPI_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_ckcapi_types_1[] = { + CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_MODIFIABLE, CKA_LABEL +}; + +static const NSSItem nss_ckcapi_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 CAPI Access", (PRUint32)20 } +}; + +ckcapiInternalObject nss_ckcapi_data[] = { + { + ckcapiRaw, + { 5, nss_ckcapi_types_1, nss_ckcapi_items_1 }, + }, + +}; + +const PRUint32 nss_ckcapi_nObjects = 1; -- cgit v1.2.3