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 CKMK_H michael@0: #include "ckmk.h" michael@0: #endif /* CKMK_H */ michael@0: michael@0: /* michael@0: * nssmkey/mfind.c michael@0: * michael@0: * This file implements the NSSCKMDFindObjects object for the michael@0: * "nssmkey" cryptoki module. michael@0: */ michael@0: michael@0: struct ckmkFOStr { michael@0: NSSArena *arena; michael@0: CK_ULONG n; michael@0: CK_ULONG i; michael@0: ckmkInternalObject **objs; michael@0: }; michael@0: michael@0: static void michael@0: ckmk_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 ckmkFOStr *fo = (struct ckmkFOStr *)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_ckmk_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: ckmk_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 ckmkFOStr *fo = (struct ckmkFOStr *)mdFindObjects->etc; michael@0: ckmkInternalObject *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_ckmk_CreateMDObject(arena, io, pError); michael@0: } michael@0: michael@0: static CK_BBOOL michael@0: ckmk_attrmatch michael@0: ( michael@0: CK_ATTRIBUTE_PTR a, michael@0: ckmkInternalObject *o michael@0: ) michael@0: { michael@0: PRBool prb; michael@0: const NSSItem *b; michael@0: CK_RV error; michael@0: michael@0: b = nss_ckmk_FetchAttribute(o, a->type, &error); 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: int len; michael@0: unsigned char *data; michael@0: michael@0: data = nss_ckmk_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: ckmk_match michael@0: ( michael@0: CK_ATTRIBUTE_PTR pTemplate, michael@0: CK_ULONG ulAttributeCount, michael@0: ckmkInternalObject *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 == ckmk_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 CKMK_ITEM_CHUNK 20 michael@0: michael@0: #define PUT_OBJECT(obj, err, size, count, list) \ michael@0: { \ michael@0: if (count >= size) { \ michael@0: (list) = (list) ? \ michael@0: nss_ZREALLOCARRAY(list, ckmkInternalObject *, \ michael@0: ((size)+CKMK_ITEM_CHUNK) ) : \ michael@0: nss_ZNEWARRAY(NULL, ckmkInternalObject *, \ michael@0: ((size)+CKMK_ITEM_CHUNK) ) ; \ michael@0: if ((ckmkInternalObject **)NULL == list) { \ michael@0: err = CKR_HOST_MEMORY; \ michael@0: goto loser; \ michael@0: } \ michael@0: (size) += CKMK_ITEM_CHUNK; \ michael@0: } \ michael@0: (list)[ count ] = (obj); \ michael@0: count++; \ michael@0: } 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: SecItemClass itemClass, michael@0: CK_ATTRIBUTE_PTR pTemplate, michael@0: CK_ULONG ulAttributeCount, michael@0: ckmkInternalObject ***listp, michael@0: PRUint32 *sizep, michael@0: PRUint32 count, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: ckmkInternalObject *next = NULL; michael@0: SecKeychainSearchRef searchRef = 0; michael@0: SecKeychainItemRef itemRef = 0; michael@0: OSStatus error; michael@0: michael@0: /* future, build the attribute list based on the template michael@0: * so we can refine the search */ michael@0: error = SecKeychainSearchCreateFromAttributes( michael@0: NULL, itemClass, NULL, &searchRef); michael@0: michael@0: while (noErr == SecKeychainSearchCopyNext(searchRef, &itemRef)) { michael@0: /* if we don't have an internal object structure, get one */ michael@0: if ((ckmkInternalObject *)NULL == next) { michael@0: next = nss_ZNEW(NULL, ckmkInternalObject); michael@0: if ((ckmkInternalObject *)NULL == next) { michael@0: *pError = CKR_HOST_MEMORY; michael@0: goto loser; michael@0: } michael@0: } michael@0: /* fill in the relevant object data */ michael@0: next->type = ckmkItem; michael@0: next->objClass = objClass; michael@0: next->u.item.itemRef = itemRef; michael@0: next->u.item.itemClass = itemClass; michael@0: michael@0: /* see if this is one of the objects we are looking for */ michael@0: if( CK_TRUE == ckmk_match(pTemplate, ulAttributeCount, next) ) { michael@0: /* yes, put it on the list */ michael@0: PUT_OBJECT(next, *pError, *sizep, count, *listp); michael@0: next = NULL; /* this one is on the list, need to allocate a new one now */ michael@0: } else { michael@0: /* no , release the current item and clear out the structure for reuse */ michael@0: CFRelease(itemRef); michael@0: /* don't cache the values we just loaded */ michael@0: nsslibc_memset(next, 0, sizeof(*next)); michael@0: } michael@0: } michael@0: loser: michael@0: if (searchRef) { michael@0: CFRelease(searchRef); michael@0: } michael@0: nss_ZFreeIf(next); michael@0: return count; 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: ckmkInternalObject ***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_ckmk_nObjects; i++ ) { michael@0: ckmkInternalObject *o = (ckmkInternalObject *)&nss_ckmk_data[i]; michael@0: michael@0: if( CK_TRUE == ckmk_match(pTemplate, ulAttributeCount, o) ) { michael@0: PUT_OBJECT(o, *pError, size, count, *listp); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * now handle the various object types michael@0: */ michael@0: objClass = nss_ckmk_GetULongAttribute(CKA_CLASS, michael@0: pTemplate, ulAttributeCount, pError); michael@0: if (CKR_OK != *pError) { michael@0: objClass = CK_INVALID_HANDLE; michael@0: } michael@0: *pError = CKR_OK; michael@0: switch (objClass) { michael@0: case CKO_CERTIFICATE: michael@0: count = collect_class(objClass, kSecCertificateItemClass, michael@0: pTemplate, ulAttributeCount, listp, michael@0: &size, count, pError); michael@0: break; michael@0: case CKO_PUBLIC_KEY: michael@0: count = collect_class(objClass, CSSM_DL_DB_RECORD_PUBLIC_KEY, michael@0: pTemplate, ulAttributeCount, listp, michael@0: &size, count, pError); michael@0: break; michael@0: case CKO_PRIVATE_KEY: michael@0: count = collect_class(objClass, CSSM_DL_DB_RECORD_PRIVATE_KEY, michael@0: 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 = collect_class(CKO_CERTIFICATE, kSecCertificateItemClass, michael@0: pTemplate, ulAttributeCount, listp, michael@0: &size, count, pError); michael@0: count = collect_class(CKO_PUBLIC_KEY, CSSM_DL_DB_RECORD_PUBLIC_KEY, michael@0: pTemplate, ulAttributeCount, listp, michael@0: &size, count, pError); michael@0: count = collect_class(CKO_PUBLIC_KEY, CSSM_DL_DB_RECORD_PRIVATE_KEY, michael@0: pTemplate, ulAttributeCount, listp, michael@0: &size, count, pError); michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: if (CKR_OK != *pError) { michael@0: goto loser; michael@0: } michael@0: michael@0: return count; michael@0: loser: michael@0: nss_ZFreeIf(*listp); michael@0: return 0; michael@0: } michael@0: michael@0: michael@0: NSS_IMPLEMENT NSSCKMDFindObjects * michael@0: nss_ckmk_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 ckmkFOStr *fo = (struct ckmkFOStr *)NULL; michael@0: ckmkInternalObject **temp = (ckmkInternalObject **)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 ckmkFOStr); michael@0: if( (struct ckmkFOStr *)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 = ckmk_mdFindObjects_Final; michael@0: rv->Next = ckmk_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, ckmkInternalObject *, fo->n); michael@0: if( (ckmkInternalObject **)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(ckmkInternalObject *) * fo->n); michael@0: nss_ZFreeIf(temp); michael@0: temp = (ckmkInternalObject **)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: