michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef CKCAPI_H michael@0: #include "ckcapi.h" michael@0: #endif /* CKCAPI_H */ michael@0: michael@0: /* michael@0: * ckcapi/cfind.c michael@0: * michael@0: * This file implements the NSSCKMDFindObjects object for the michael@0: * "capi" cryptoki module. michael@0: */ michael@0: michael@0: struct ckcapiFOStr { michael@0: NSSArena *arena; michael@0: CK_ULONG n; michael@0: CK_ULONG i; michael@0: ckcapiInternalObject **objs; michael@0: }; michael@0: michael@0: static void michael@0: ckcapi_mdFindObjects_Final michael@0: ( michael@0: NSSCKMDFindObjects *mdFindObjects, michael@0: NSSCKFWFindObjects *fwFindObjects, michael@0: NSSCKMDSession *mdSession, michael@0: NSSCKFWSession *fwSession, michael@0: NSSCKMDToken *mdToken, michael@0: NSSCKFWToken *fwToken, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance michael@0: ) michael@0: { michael@0: struct ckcapiFOStr *fo = (struct ckcapiFOStr *)mdFindObjects->etc; michael@0: NSSArena *arena = fo->arena; michael@0: PRUint32 i; michael@0: michael@0: /* walk down an free the unused 'objs' */ michael@0: for (i=fo->i; i < fo->n ; i++) { michael@0: nss_ckcapi_DestroyInternalObject(fo->objs[i]); michael@0: } michael@0: michael@0: nss_ZFreeIf(fo->objs); michael@0: nss_ZFreeIf(fo); michael@0: nss_ZFreeIf(mdFindObjects); michael@0: if ((NSSArena *)NULL != arena) { michael@0: NSSArena_Destroy(arena); michael@0: } michael@0: michael@0: return; michael@0: } michael@0: michael@0: static NSSCKMDObject * michael@0: ckcapi_mdFindObjects_Next michael@0: ( michael@0: NSSCKMDFindObjects *mdFindObjects, michael@0: NSSCKFWFindObjects *fwFindObjects, michael@0: NSSCKMDSession *mdSession, michael@0: NSSCKFWSession *fwSession, michael@0: NSSCKMDToken *mdToken, michael@0: NSSCKFWToken *fwToken, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance, michael@0: NSSArena *arena, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: struct ckcapiFOStr *fo = (struct ckcapiFOStr *)mdFindObjects->etc; michael@0: ckcapiInternalObject *io; michael@0: michael@0: if( fo->i == fo->n ) { michael@0: *pError = CKR_OK; michael@0: return (NSSCKMDObject *)NULL; michael@0: } michael@0: michael@0: io = fo->objs[ fo->i ]; michael@0: fo->i++; michael@0: michael@0: return nss_ckcapi_CreateMDObject(arena, io, pError); michael@0: } michael@0: michael@0: static CK_BBOOL michael@0: ckcapi_attrmatch michael@0: ( michael@0: CK_ATTRIBUTE_PTR a, michael@0: ckcapiInternalObject *o michael@0: ) michael@0: { michael@0: PRBool prb; michael@0: const NSSItem *b; michael@0: michael@0: b = nss_ckcapi_FetchAttribute(o, a->type); michael@0: if (b == NULL) { michael@0: return CK_FALSE; michael@0: } michael@0: michael@0: if( a->ulValueLen != b->size ) { michael@0: /* match a decoded serial number */ michael@0: if ((a->type == CKA_SERIAL_NUMBER) && (a->ulValueLen < b->size)) { michael@0: unsigned int len; michael@0: unsigned char *data; michael@0: michael@0: data = nss_ckcapi_DERUnwrap(b->data, b->size, &len, NULL); michael@0: if ((len == a->ulValueLen) && michael@0: nsslibc_memequal(a->pValue, data, len, (PRStatus *)NULL)) { michael@0: return CK_TRUE; michael@0: } michael@0: } michael@0: return CK_FALSE; michael@0: } michael@0: michael@0: prb = nsslibc_memequal(a->pValue, b->data, b->size, (PRStatus *)NULL); michael@0: michael@0: if( PR_TRUE == prb ) { michael@0: return CK_TRUE; michael@0: } else { michael@0: return CK_FALSE; michael@0: } michael@0: } michael@0: michael@0: michael@0: static CK_BBOOL michael@0: ckcapi_match michael@0: ( michael@0: CK_ATTRIBUTE_PTR pTemplate, michael@0: CK_ULONG ulAttributeCount, michael@0: ckcapiInternalObject *o michael@0: ) michael@0: { michael@0: CK_ULONG i; michael@0: michael@0: for( i = 0; i < ulAttributeCount; i++ ) { michael@0: if (CK_FALSE == ckcapi_attrmatch(&pTemplate[i], o)) { michael@0: return CK_FALSE; michael@0: } michael@0: } michael@0: michael@0: /* Every attribute passed */ michael@0: return CK_TRUE; michael@0: } michael@0: michael@0: #define CKAPI_ITEM_CHUNK 20 michael@0: michael@0: #define PUT_Object(obj,err) \ michael@0: { \ michael@0: if (count >= size) { \ michael@0: *listp = *listp ? \ michael@0: nss_ZREALLOCARRAY(*listp, ckcapiInternalObject *, \ michael@0: (size+CKAPI_ITEM_CHUNK) ) : \ michael@0: nss_ZNEWARRAY(NULL, ckcapiInternalObject *, \ michael@0: (size+CKAPI_ITEM_CHUNK) ) ; \ michael@0: if ((ckcapiInternalObject **)NULL == *listp) { \ michael@0: err = CKR_HOST_MEMORY; \ michael@0: goto loser; \ michael@0: } \ michael@0: size += CKAPI_ITEM_CHUNK; \ michael@0: } \ michael@0: (*listp)[ count ] = (obj); \ michael@0: count++; \ michael@0: } michael@0: michael@0: michael@0: /* michael@0: * pass parameters back through the callback. michael@0: */ michael@0: typedef struct BareCollectParamsStr { michael@0: CK_OBJECT_CLASS objClass; michael@0: CK_ATTRIBUTE_PTR pTemplate; michael@0: CK_ULONG ulAttributeCount; michael@0: ckcapiInternalObject ***listp; michael@0: PRUint32 size; michael@0: PRUint32 count; michael@0: } BareCollectParams; michael@0: michael@0: /* collect_bare's callback. Called for each object that michael@0: * supposedly has a PROVINDER_INFO property */ michael@0: static BOOL WINAPI michael@0: doBareCollect michael@0: ( michael@0: const CRYPT_HASH_BLOB *msKeyID, michael@0: DWORD flags, michael@0: void *reserved, michael@0: void *args, michael@0: DWORD cProp, michael@0: DWORD *propID, michael@0: void **propData, michael@0: DWORD *propSize michael@0: ) michael@0: { michael@0: BareCollectParams *bcp = (BareCollectParams *) args; michael@0: PRUint32 size = bcp->size; michael@0: PRUint32 count = bcp->count; michael@0: ckcapiInternalObject ***listp = bcp->listp; michael@0: ckcapiInternalObject *io = NULL; michael@0: DWORD i; michael@0: CRYPT_KEY_PROV_INFO *keyProvInfo = NULL; michael@0: void *idData; michael@0: CK_RV error; michael@0: michael@0: /* make sure there is a Key Provider Info property */ michael@0: for (i=0; i < cProp; i++) { michael@0: if (CERT_KEY_PROV_INFO_PROP_ID == propID[i]) { michael@0: keyProvInfo = (CRYPT_KEY_PROV_INFO *)propData[i]; michael@0: break; michael@0: } michael@0: } michael@0: if ((CRYPT_KEY_PROV_INFO *)NULL == keyProvInfo) { michael@0: return 1; michael@0: } michael@0: michael@0: /* copy the key ID */ michael@0: idData = nss_ZNEWARRAY(NULL, char, msKeyID->cbData); michael@0: if ((void *)NULL == idData) { michael@0: goto loser; michael@0: } michael@0: nsslibc_memcpy(idData, msKeyID->pbData, msKeyID->cbData); michael@0: michael@0: /* build a bare internal object */ michael@0: io = nss_ZNEW(NULL, ckcapiInternalObject); michael@0: if ((ckcapiInternalObject *)NULL == io) { michael@0: goto loser; michael@0: } michael@0: io->type = ckcapiBareKey; michael@0: io->objClass = bcp->objClass; michael@0: io->u.key.provInfo = *keyProvInfo; michael@0: io->u.key.provInfo.pwszContainerName = michael@0: nss_ckcapi_WideDup(keyProvInfo->pwszContainerName); michael@0: io->u.key.provInfo.pwszProvName = michael@0: nss_ckcapi_WideDup(keyProvInfo->pwszProvName); michael@0: io->u.key.provName = nss_ckcapi_WideToUTF8(keyProvInfo->pwszProvName); michael@0: io->u.key.containerName = michael@0: nss_ckcapi_WideToUTF8(keyProvInfo->pwszContainerName); michael@0: io->u.key.hProv = 0; michael@0: io->idData = idData; michael@0: io->id.data = idData; michael@0: io->id.size = msKeyID->cbData; michael@0: idData = NULL; michael@0: michael@0: /* see if it matches */ michael@0: if( CK_FALSE == ckcapi_match(bcp->pTemplate, bcp->ulAttributeCount, io) ) { michael@0: goto loser; michael@0: } michael@0: PUT_Object(io, error); michael@0: bcp->size = size; michael@0: bcp->count = count; michael@0: return 1; michael@0: michael@0: loser: michael@0: if (io) { michael@0: nss_ckcapi_DestroyInternalObject(io); michael@0: } michael@0: nss_ZFreeIf(idData); michael@0: return 1; michael@0: } michael@0: michael@0: /* michael@0: * collect the bare keys running around michael@0: */ michael@0: static PRUint32 michael@0: collect_bare( michael@0: CK_OBJECT_CLASS objClass, michael@0: CK_ATTRIBUTE_PTR pTemplate, michael@0: CK_ULONG ulAttributeCount, michael@0: ckcapiInternalObject ***listp, michael@0: PRUint32 *sizep, michael@0: PRUint32 count, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: BOOL rc; michael@0: BareCollectParams bareCollectParams; michael@0: michael@0: bareCollectParams.objClass = objClass; michael@0: bareCollectParams.pTemplate = pTemplate; michael@0: bareCollectParams.ulAttributeCount = ulAttributeCount; michael@0: bareCollectParams.listp = listp; michael@0: bareCollectParams.size = *sizep; michael@0: bareCollectParams.count = count; michael@0: michael@0: rc = CryptEnumKeyIdentifierProperties(NULL, CERT_KEY_PROV_INFO_PROP_ID, 0, michael@0: NULL, NULL, &bareCollectParams, doBareCollect); michael@0: michael@0: *sizep = bareCollectParams.size; michael@0: return bareCollectParams.count; michael@0: } michael@0: michael@0: /* find all the certs that represent the appropriate object (cert, priv key, or michael@0: * pub key) in the cert store. michael@0: */ michael@0: static PRUint32 michael@0: collect_class( michael@0: CK_OBJECT_CLASS objClass, michael@0: LPCSTR storeStr, michael@0: PRBool hasID, michael@0: CK_ATTRIBUTE_PTR pTemplate, michael@0: CK_ULONG ulAttributeCount, michael@0: ckcapiInternalObject ***listp, michael@0: PRUint32 *sizep, michael@0: PRUint32 count, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: PRUint32 size = *sizep; michael@0: ckcapiInternalObject *next = NULL; michael@0: HCERTSTORE hStore; michael@0: PCCERT_CONTEXT certContext = NULL; michael@0: PRBool isKey = michael@0: (objClass == CKO_PUBLIC_KEY) | (objClass == CKO_PRIVATE_KEY); michael@0: michael@0: hStore = CertOpenSystemStore((HCRYPTPROV)NULL, storeStr); michael@0: if (NULL == hStore) { michael@0: return count; /* none found does not imply an error */ michael@0: } michael@0: michael@0: /* FUTURE: use CertFindCertificateInStore to filter better -- so we don't michael@0: * have to enumerate all the certificates */ michael@0: while ((PCERT_CONTEXT) NULL != michael@0: (certContext= CertEnumCertificatesInStore(hStore, certContext))) { michael@0: /* first filter out non user certs if we are looking for keys */ michael@0: if (isKey) { michael@0: /* make sure there is a Key Provider Info property */ michael@0: CRYPT_KEY_PROV_INFO *keyProvInfo; michael@0: DWORD size = 0; michael@0: BOOL rv; michael@0: rv =CertGetCertificateContextProperty(certContext, michael@0: CERT_KEY_PROV_INFO_PROP_ID, NULL, &size); michael@0: if (!rv) { michael@0: int reason = GetLastError(); michael@0: /* we only care if it exists, we don't really need to fetch it yet */ michael@0: if (reason == CRYPT_E_NOT_FOUND) { michael@0: continue; michael@0: } michael@0: } michael@0: /* filter out the non-microsoft providers */ michael@0: keyProvInfo = (CRYPT_KEY_PROV_INFO *)nss_ZAlloc(NULL, size); michael@0: if (keyProvInfo) { michael@0: rv =CertGetCertificateContextProperty(certContext, michael@0: CERT_KEY_PROV_INFO_PROP_ID, keyProvInfo, &size); michael@0: if (rv) { michael@0: char *provName = nss_ckcapi_WideToUTF8(keyProvInfo->pwszProvName); michael@0: nss_ZFreeIf(keyProvInfo); michael@0: michael@0: if (provName && michael@0: (strncmp(provName, "Microsoft", sizeof("Microsoft")-1) != 0)) { michael@0: continue; michael@0: } michael@0: } else { michael@0: int reason = GetLastError(); michael@0: /* we only care if it exists, we don't really need to fetch it yet */ michael@0: nss_ZFreeIf(keyProvInfo); michael@0: if (reason == CRYPT_E_NOT_FOUND) { michael@0: continue; michael@0: } michael@0: michael@0: } michael@0: } michael@0: } michael@0: michael@0: if ((ckcapiInternalObject *)NULL == next) { michael@0: next = nss_ZNEW(NULL, ckcapiInternalObject); michael@0: if ((ckcapiInternalObject *)NULL == next) { michael@0: *pError = CKR_HOST_MEMORY; michael@0: goto loser; michael@0: } michael@0: } michael@0: next->type = ckcapiCert; michael@0: next->objClass = objClass; michael@0: next->u.cert.certContext = certContext; michael@0: next->u.cert.hasID = hasID; michael@0: next->u.cert.certStore = storeStr; michael@0: if( CK_TRUE == ckcapi_match(pTemplate, ulAttributeCount, next) ) { michael@0: /* clear cached values that may be dependent on our old certContext */ michael@0: memset(&next->u.cert, 0, sizeof(next->u.cert)); michael@0: /* get a 'permanent' context */ michael@0: next->u.cert.certContext = CertDuplicateCertificateContext(certContext); michael@0: next->objClass = objClass; michael@0: next->u.cert.certContext = certContext; michael@0: next->u.cert.hasID = hasID; michael@0: next->u.cert.certStore = storeStr; michael@0: PUT_Object(next, *pError); michael@0: next = NULL; /* need to allocate a new one now */ michael@0: } else { michael@0: /* don't cache the values we just loaded */ michael@0: memset(&next->u.cert, 0, sizeof(next->u.cert)); michael@0: } michael@0: } michael@0: loser: michael@0: CertCloseStore(hStore, 0); michael@0: nss_ZFreeIf(next); michael@0: *sizep = size; michael@0: return count; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRUint32 michael@0: nss_ckcapi_collect_all_certs( michael@0: CK_ATTRIBUTE_PTR pTemplate, michael@0: CK_ULONG ulAttributeCount, michael@0: ckcapiInternalObject ***listp, michael@0: PRUint32 *sizep, michael@0: PRUint32 count, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: count = collect_class(CKO_CERTIFICATE, "My", PR_TRUE, pTemplate, michael@0: ulAttributeCount, listp, sizep, count, pError); michael@0: /*count = collect_class(CKO_CERTIFICATE, "AddressBook", PR_FALSE, pTemplate, michael@0: ulAttributeCount, listp, sizep, count, pError); */ michael@0: count = collect_class(CKO_CERTIFICATE, "CA", PR_FALSE, pTemplate, michael@0: ulAttributeCount, listp, sizep, count, pError); michael@0: count = collect_class(CKO_CERTIFICATE, "Root", PR_FALSE, pTemplate, michael@0: ulAttributeCount, listp, sizep, count, pError); michael@0: count = collect_class(CKO_CERTIFICATE, "Trust", PR_FALSE, pTemplate, michael@0: ulAttributeCount, listp, sizep, count, pError); michael@0: count = collect_class(CKO_CERTIFICATE, "TrustedPeople", PR_FALSE, pTemplate, michael@0: ulAttributeCount, listp, sizep, count, pError); michael@0: count = collect_class(CKO_CERTIFICATE, "AuthRoot", PR_FALSE, pTemplate, michael@0: ulAttributeCount, listp, sizep, count, pError); michael@0: return count; michael@0: } michael@0: michael@0: CK_OBJECT_CLASS michael@0: ckcapi_GetObjectClass(CK_ATTRIBUTE_PTR pTemplate, michael@0: CK_ULONG ulAttributeCount) michael@0: { michael@0: CK_ULONG i; michael@0: michael@0: for (i=0; i < ulAttributeCount; i++) michael@0: { michael@0: if (pTemplate[i].type == CKA_CLASS) { michael@0: return *(CK_OBJECT_CLASS *) pTemplate[i].pValue; michael@0: } michael@0: } michael@0: /* need to return a value that says 'fetch them all' */ michael@0: return CK_INVALID_HANDLE; michael@0: } michael@0: michael@0: static PRUint32 michael@0: collect_objects( michael@0: CK_ATTRIBUTE_PTR pTemplate, michael@0: CK_ULONG ulAttributeCount, michael@0: ckcapiInternalObject ***listp, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: PRUint32 i; michael@0: PRUint32 count = 0; michael@0: PRUint32 size = 0; michael@0: CK_OBJECT_CLASS objClass; michael@0: michael@0: /* michael@0: * first handle the static build in objects (if any) michael@0: */ michael@0: for( i = 0; i < nss_ckcapi_nObjects; i++ ) { michael@0: ckcapiInternalObject *o = (ckcapiInternalObject *)&nss_ckcapi_data[i]; michael@0: michael@0: if( CK_TRUE == ckcapi_match(pTemplate, ulAttributeCount, o) ) { michael@0: PUT_Object(o, *pError); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * now handle the various object types michael@0: */ michael@0: objClass = ckcapi_GetObjectClass(pTemplate, ulAttributeCount); michael@0: *pError = CKR_OK; michael@0: switch (objClass) { michael@0: case CKO_CERTIFICATE: michael@0: count = nss_ckcapi_collect_all_certs(pTemplate, ulAttributeCount, listp, michael@0: &size, count, pError); michael@0: break; michael@0: case CKO_PUBLIC_KEY: michael@0: count = collect_class(objClass, "My", PR_TRUE, pTemplate, michael@0: ulAttributeCount, listp, &size, count, pError); michael@0: count = collect_bare(objClass, pTemplate, ulAttributeCount, listp, michael@0: &size, count, pError); michael@0: break; michael@0: case CKO_PRIVATE_KEY: michael@0: count = collect_class(objClass, "My", PR_TRUE, pTemplate, michael@0: ulAttributeCount, listp, &size, count, pError); michael@0: count = collect_bare(objClass, pTemplate, ulAttributeCount, listp, michael@0: &size, count, pError); michael@0: break; michael@0: /* all of them */ michael@0: case CK_INVALID_HANDLE: michael@0: count = nss_ckcapi_collect_all_certs(pTemplate, ulAttributeCount, listp, michael@0: &size, count, pError); michael@0: count = collect_class(CKO_PUBLIC_KEY, "My", PR_TRUE, pTemplate, michael@0: ulAttributeCount, listp, &size, count, pError); michael@0: count = collect_bare(CKO_PUBLIC_KEY, pTemplate, ulAttributeCount, listp, michael@0: &size, count, pError); michael@0: count = collect_class(CKO_PRIVATE_KEY, "My", PR_TRUE, pTemplate, michael@0: ulAttributeCount, listp, &size, count, pError); michael@0: count = collect_bare(CKO_PRIVATE_KEY, pTemplate, ulAttributeCount, listp, michael@0: &size, count, pError); michael@0: break; michael@0: default: michael@0: goto done; /* no other object types we understand in this module */ michael@0: } michael@0: if (CKR_OK != *pError) { michael@0: goto loser; michael@0: } michael@0: michael@0: michael@0: done: michael@0: return count; michael@0: loser: michael@0: nss_ZFreeIf(*listp); michael@0: return 0; michael@0: } michael@0: michael@0: michael@0: michael@0: NSS_IMPLEMENT NSSCKMDFindObjects * michael@0: nss_ckcapi_FindObjectsInit michael@0: ( michael@0: NSSCKFWSession *fwSession, michael@0: CK_ATTRIBUTE_PTR pTemplate, michael@0: CK_ULONG ulAttributeCount, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: /* This could be made more efficient. I'm rather rushed. */ michael@0: NSSArena *arena; michael@0: NSSCKMDFindObjects *rv = (NSSCKMDFindObjects *)NULL; michael@0: struct ckcapiFOStr *fo = (struct ckcapiFOStr *)NULL; michael@0: ckcapiInternalObject **temp = (ckcapiInternalObject **)NULL; michael@0: michael@0: arena = NSSArena_Create(); michael@0: if( (NSSArena *)NULL == arena ) { michael@0: goto loser; michael@0: } michael@0: michael@0: rv = nss_ZNEW(arena, NSSCKMDFindObjects); michael@0: if( (NSSCKMDFindObjects *)NULL == rv ) { michael@0: *pError = CKR_HOST_MEMORY; michael@0: goto loser; michael@0: } michael@0: michael@0: fo = nss_ZNEW(arena, struct ckcapiFOStr); michael@0: if( (struct ckcapiFOStr *)NULL == fo ) { michael@0: *pError = CKR_HOST_MEMORY; michael@0: goto loser; michael@0: } michael@0: michael@0: fo->arena = arena; michael@0: /* fo->n and fo->i are already zero */ michael@0: michael@0: rv->etc = (void *)fo; michael@0: rv->Final = ckcapi_mdFindObjects_Final; michael@0: rv->Next = ckcapi_mdFindObjects_Next; michael@0: rv->null = (void *)NULL; michael@0: michael@0: fo->n = collect_objects(pTemplate, ulAttributeCount, &temp, pError); michael@0: if (*pError != CKR_OK) { michael@0: goto loser; michael@0: } michael@0: michael@0: fo->objs = nss_ZNEWARRAY(arena, ckcapiInternalObject *, fo->n); michael@0: if( (ckcapiInternalObject **)NULL == fo->objs ) { michael@0: *pError = CKR_HOST_MEMORY; michael@0: goto loser; michael@0: } michael@0: michael@0: (void)nsslibc_memcpy(fo->objs, temp, sizeof(ckcapiInternalObject *) * fo->n); michael@0: nss_ZFreeIf(temp); michael@0: temp = (ckcapiInternalObject **)NULL; michael@0: michael@0: return rv; michael@0: michael@0: loser: michael@0: nss_ZFreeIf(temp); michael@0: nss_ZFreeIf(fo); michael@0: nss_ZFreeIf(rv); michael@0: if ((NSSArena *)NULL != arena) { michael@0: NSSArena_Destroy(arena); michael@0: } michael@0: return (NSSCKMDFindObjects *)NULL; michael@0: } michael@0: