| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| #ifndef CKMK_H |
| #include "ckmk.h" |
| #endif /* CKMK_H */ |
| |
| /* |
| * nssmkey/mfind.c |
| * |
| * This file implements the NSSCKMDFindObjects object for the |
| * "nssmkey" cryptoki module. |
| */ |
| |
| struct ckmkFOStr { |
| NSSArena *arena; |
| CK_ULONG n; |
| CK_ULONG i; |
| ckmkInternalObject **objs; |
| }; |
| |
| static void |
| ckmk_mdFindObjects_Final( |
| NSSCKMDFindObjects *mdFindObjects, |
| NSSCKFWFindObjects *fwFindObjects, |
| NSSCKMDSession *mdSession, |
| NSSCKFWSession *fwSession, |
| NSSCKMDToken *mdToken, |
| NSSCKFWToken *fwToken, |
| NSSCKMDInstance *mdInstance, |
| NSSCKFWInstance *fwInstance) |
| { |
| struct ckmkFOStr *fo = (struct ckmkFOStr *)mdFindObjects->etc; |
| NSSArena *arena = fo->arena; |
| PRUint32 i; |
| |
| /* walk down an free the unused 'objs' */ |
| for (i = fo->i; i < fo->n; i++) { |
| nss_ckmk_DestroyInternalObject(fo->objs[i]); |
| } |
| |
| nss_ZFreeIf(fo->objs); |
| nss_ZFreeIf(fo); |
| nss_ZFreeIf(mdFindObjects); |
| if ((NSSArena *)NULL != arena) { |
| NSSArena_Destroy(arena); |
| } |
| |
| return; |
| } |
| |
| static NSSCKMDObject * |
| ckmk_mdFindObjects_Next( |
| NSSCKMDFindObjects *mdFindObjects, |
| NSSCKFWFindObjects *fwFindObjects, |
| NSSCKMDSession *mdSession, |
| NSSCKFWSession *fwSession, |
| NSSCKMDToken *mdToken, |
| NSSCKFWToken *fwToken, |
| NSSCKMDInstance *mdInstance, |
| NSSCKFWInstance *fwInstance, |
| NSSArena *arena, |
| CK_RV *pError) |
| { |
| struct ckmkFOStr *fo = (struct ckmkFOStr *)mdFindObjects->etc; |
| ckmkInternalObject *io; |
| |
| if (fo->i == fo->n) { |
| *pError = CKR_OK; |
| return (NSSCKMDObject *)NULL; |
| } |
| |
| io = fo->objs[fo->i]; |
| fo->i++; |
| |
| return nss_ckmk_CreateMDObject(arena, io, pError); |
| } |
| |
| static CK_BBOOL |
| ckmk_attrmatch( |
| CK_ATTRIBUTE_PTR a, |
| ckmkInternalObject *o) |
| { |
| PRBool prb; |
| const NSSItem *b; |
| CK_RV error; |
| |
| b = nss_ckmk_FetchAttribute(o, a->type, &error); |
| if (b == NULL) { |
| return CK_FALSE; |
| } |
| |
| if (a->ulValueLen != b->size) { |
| /* match a decoded serial number */ |
| if ((a->type == CKA_SERIAL_NUMBER) && (a->ulValueLen < b->size)) { |
| int len; |
| unsigned char *data; |
| |
| data = nss_ckmk_DERUnwrap(b->data, b->size, &len, NULL); |
| if ((len == a->ulValueLen) && |
| nsslibc_memequal(a->pValue, data, len, (PRStatus *)NULL)) { |
| return CK_TRUE; |
| } |
| } |
| return CK_FALSE; |
| } |
| |
| prb = nsslibc_memequal(a->pValue, b->data, b->size, (PRStatus *)NULL); |
| |
| if (PR_TRUE == prb) { |
| return CK_TRUE; |
| } else { |
| return CK_FALSE; |
| } |
| } |
| |
| static CK_BBOOL |
| ckmk_match( |
| CK_ATTRIBUTE_PTR pTemplate, |
| CK_ULONG ulAttributeCount, |
| ckmkInternalObject *o) |
| { |
| CK_ULONG i; |
| |
| for (i = 0; i < ulAttributeCount; i++) { |
| if (CK_FALSE == ckmk_attrmatch(&pTemplate[i], o)) { |
| return CK_FALSE; |
| } |
| } |
| |
| /* Every attribute passed */ |
| return CK_TRUE; |
| } |
| |
| #define CKMK_ITEM_CHUNK 20 |
| |
| #define PUT_OBJECT(obj, err, size, count, list) \ |
| { \ |
| if (count >= size) { \ |
| (list) = (list) ? nss_ZREALLOCARRAY(list, ckmkInternalObject *, \ |
| ((size) + \ |
| CKMK_ITEM_CHUNK)) \ |
| : nss_ZNEWARRAY(NULL, ckmkInternalObject *, \ |
| ((size) + \ |
| CKMK_ITEM_CHUNK)); \ |
| if ((ckmkInternalObject **)NULL == list) { \ |
| err = CKR_HOST_MEMORY; \ |
| goto loser; \ |
| } \ |
| (size) += CKMK_ITEM_CHUNK; \ |
| } \ |
| (list)[count] = (obj); \ |
| count++; \ |
| } |
| |
| /* find all the certs that represent the appropriate object (cert, priv key, or |
| * pub key) in the cert store. |
| */ |
| static PRUint32 |
| collect_class( |
| CK_OBJECT_CLASS objClass, |
| SecItemClass itemClass, |
| CK_ATTRIBUTE_PTR pTemplate, |
| CK_ULONG ulAttributeCount, |
| ckmkInternalObject ***listp, |
| PRUint32 *sizep, |
| PRUint32 count, |
| CK_RV *pError) |
| { |
| ckmkInternalObject *next = NULL; |
| SecKeychainSearchRef searchRef = 0; |
| SecKeychainItemRef itemRef = 0; |
| OSStatus error; |
| |
| /* future, build the attribute list based on the template |
| * so we can refine the search */ |
| error = SecKeychainSearchCreateFromAttributes( |
| NULL, itemClass, NULL, &searchRef); |
| |
| while (noErr == SecKeychainSearchCopyNext(searchRef, &itemRef)) { |
| /* if we don't have an internal object structure, get one */ |
| if ((ckmkInternalObject *)NULL == next) { |
| next = nss_ZNEW(NULL, ckmkInternalObject); |
| if ((ckmkInternalObject *)NULL == next) { |
| *pError = CKR_HOST_MEMORY; |
| goto loser; |
| } |
| } |
| /* fill in the relevant object data */ |
| next->type = ckmkItem; |
| next->objClass = objClass; |
| next->u.item.itemRef = itemRef; |
| next->u.item.itemClass = itemClass; |
| |
| /* see if this is one of the objects we are looking for */ |
| if (CK_TRUE == ckmk_match(pTemplate, ulAttributeCount, next)) { |
| /* yes, put it on the list */ |
| PUT_OBJECT(next, *pError, *sizep, count, *listp); |
| next = NULL; /* this one is on the list, need to allocate a new one now */ |
| } else { |
| /* no , release the current item and clear out the structure for reuse */ |
| CFRelease(itemRef); |
| /* don't cache the values we just loaded */ |
| nsslibc_memset(next, 0, sizeof(*next)); |
| } |
| } |
| loser: |
| if (searchRef) { |
| CFRelease(searchRef); |
| } |
| nss_ZFreeIf(next); |
| return count; |
| } |
| |
| static PRUint32 |
| collect_objects( |
| CK_ATTRIBUTE_PTR pTemplate, |
| CK_ULONG ulAttributeCount, |
| ckmkInternalObject ***listp, |
| CK_RV *pError) |
| { |
| PRUint32 i; |
| PRUint32 count = 0; |
| PRUint32 size = 0; |
| CK_OBJECT_CLASS objClass; |
| |
| /* |
| * first handle the static build in objects (if any) |
| */ |
| for (i = 0; i < nss_ckmk_nObjects; i++) { |
| ckmkInternalObject *o = (ckmkInternalObject *)&nss_ckmk_data[i]; |
| |
| if (CK_TRUE == ckmk_match(pTemplate, ulAttributeCount, o)) { |
| PUT_OBJECT(o, *pError, size, count, *listp); |
| } |
| } |
| |
| /* |
| * now handle the various object types |
| */ |
| objClass = nss_ckmk_GetULongAttribute(CKA_CLASS, |
| pTemplate, ulAttributeCount, pError); |
| if (CKR_OK != *pError) { |
| objClass = CK_INVALID_HANDLE; |
| } |
| *pError = CKR_OK; |
| switch (objClass) { |
| case CKO_CERTIFICATE: |
| count = collect_class(objClass, kSecCertificateItemClass, |
| pTemplate, ulAttributeCount, listp, |
| &size, count, pError); |
| break; |
| case CKO_PUBLIC_KEY: |
| count = collect_class(objClass, CSSM_DL_DB_RECORD_PUBLIC_KEY, |
| pTemplate, ulAttributeCount, listp, |
| &size, count, pError); |
| break; |
| case CKO_PRIVATE_KEY: |
| count = collect_class(objClass, CSSM_DL_DB_RECORD_PRIVATE_KEY, |
| pTemplate, ulAttributeCount, listp, |
| &size, count, pError); |
| break; |
| /* all of them */ |
| case CK_INVALID_HANDLE: |
| count = collect_class(CKO_CERTIFICATE, kSecCertificateItemClass, |
| pTemplate, ulAttributeCount, listp, |
| &size, count, pError); |
| count = collect_class(CKO_PUBLIC_KEY, CSSM_DL_DB_RECORD_PUBLIC_KEY, |
| pTemplate, ulAttributeCount, listp, |
| &size, count, pError); |
| count = collect_class(CKO_PUBLIC_KEY, CSSM_DL_DB_RECORD_PRIVATE_KEY, |
| pTemplate, ulAttributeCount, listp, |
| &size, count, pError); |
| break; |
| default: |
| break; |
| } |
| if (CKR_OK != *pError) { |
| goto loser; |
| } |
| |
| return count; |
| loser: |
| nss_ZFreeIf(*listp); |
| return 0; |
| } |
| |
| NSS_IMPLEMENT NSSCKMDFindObjects * |
| nss_ckmk_FindObjectsInit( |
| NSSCKFWSession *fwSession, |
| CK_ATTRIBUTE_PTR pTemplate, |
| CK_ULONG ulAttributeCount, |
| CK_RV *pError) |
| { |
| /* This could be made more efficient. I'm rather rushed. */ |
| NSSArena *arena; |
| NSSCKMDFindObjects *rv = (NSSCKMDFindObjects *)NULL; |
| struct ckmkFOStr *fo = (struct ckmkFOStr *)NULL; |
| ckmkInternalObject **temp = (ckmkInternalObject **)NULL; |
| |
| arena = NSSArena_Create(); |
| if ((NSSArena *)NULL == arena) { |
| goto loser; |
| } |
| |
| rv = nss_ZNEW(arena, NSSCKMDFindObjects); |
| if ((NSSCKMDFindObjects *)NULL == rv) { |
| *pError = CKR_HOST_MEMORY; |
| goto loser; |
| } |
| |
| fo = nss_ZNEW(arena, struct ckmkFOStr); |
| if ((struct ckmkFOStr *)NULL == fo) { |
| *pError = CKR_HOST_MEMORY; |
| goto loser; |
| } |
| |
| fo->arena = arena; |
| /* fo->n and fo->i are already zero */ |
| |
| rv->etc = (void *)fo; |
| rv->Final = ckmk_mdFindObjects_Final; |
| rv->Next = ckmk_mdFindObjects_Next; |
| rv->null = (void *)NULL; |
| |
| fo->n = collect_objects(pTemplate, ulAttributeCount, &temp, pError); |
| if (*pError != CKR_OK) { |
| goto loser; |
| } |
| |
| fo->objs = nss_ZNEWARRAY(arena, ckmkInternalObject *, fo->n); |
| if ((ckmkInternalObject **)NULL == fo->objs) { |
| *pError = CKR_HOST_MEMORY; |
| goto loser; |
| } |
| |
| (void)nsslibc_memcpy(fo->objs, temp, sizeof(ckmkInternalObject *) * fo->n); |
| nss_ZFreeIf(temp); |
| temp = (ckmkInternalObject **)NULL; |
| |
| return rv; |
| |
| loser: |
| nss_ZFreeIf(temp); |
| nss_ZFreeIf(fo); |
| nss_ZFreeIf(rv); |
| if ((NSSArena *)NULL != arena) { |
| NSSArena_Destroy(arena); |
| } |
| return (NSSCKMDFindObjects *)NULL; |
| } |