1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/ckfw/capi/cfind.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,581 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#ifndef CKCAPI_H 1.9 +#include "ckcapi.h" 1.10 +#endif /* CKCAPI_H */ 1.11 + 1.12 +/* 1.13 + * ckcapi/cfind.c 1.14 + * 1.15 + * This file implements the NSSCKMDFindObjects object for the 1.16 + * "capi" cryptoki module. 1.17 + */ 1.18 + 1.19 +struct ckcapiFOStr { 1.20 + NSSArena *arena; 1.21 + CK_ULONG n; 1.22 + CK_ULONG i; 1.23 + ckcapiInternalObject **objs; 1.24 +}; 1.25 + 1.26 +static void 1.27 +ckcapi_mdFindObjects_Final 1.28 +( 1.29 + NSSCKMDFindObjects *mdFindObjects, 1.30 + NSSCKFWFindObjects *fwFindObjects, 1.31 + NSSCKMDSession *mdSession, 1.32 + NSSCKFWSession *fwSession, 1.33 + NSSCKMDToken *mdToken, 1.34 + NSSCKFWToken *fwToken, 1.35 + NSSCKMDInstance *mdInstance, 1.36 + NSSCKFWInstance *fwInstance 1.37 +) 1.38 +{ 1.39 + struct ckcapiFOStr *fo = (struct ckcapiFOStr *)mdFindObjects->etc; 1.40 + NSSArena *arena = fo->arena; 1.41 + PRUint32 i; 1.42 + 1.43 + /* walk down an free the unused 'objs' */ 1.44 + for (i=fo->i; i < fo->n ; i++) { 1.45 + nss_ckcapi_DestroyInternalObject(fo->objs[i]); 1.46 + } 1.47 + 1.48 + nss_ZFreeIf(fo->objs); 1.49 + nss_ZFreeIf(fo); 1.50 + nss_ZFreeIf(mdFindObjects); 1.51 + if ((NSSArena *)NULL != arena) { 1.52 + NSSArena_Destroy(arena); 1.53 + } 1.54 + 1.55 + return; 1.56 +} 1.57 + 1.58 +static NSSCKMDObject * 1.59 +ckcapi_mdFindObjects_Next 1.60 +( 1.61 + NSSCKMDFindObjects *mdFindObjects, 1.62 + NSSCKFWFindObjects *fwFindObjects, 1.63 + NSSCKMDSession *mdSession, 1.64 + NSSCKFWSession *fwSession, 1.65 + NSSCKMDToken *mdToken, 1.66 + NSSCKFWToken *fwToken, 1.67 + NSSCKMDInstance *mdInstance, 1.68 + NSSCKFWInstance *fwInstance, 1.69 + NSSArena *arena, 1.70 + CK_RV *pError 1.71 +) 1.72 +{ 1.73 + struct ckcapiFOStr *fo = (struct ckcapiFOStr *)mdFindObjects->etc; 1.74 + ckcapiInternalObject *io; 1.75 + 1.76 + if( fo->i == fo->n ) { 1.77 + *pError = CKR_OK; 1.78 + return (NSSCKMDObject *)NULL; 1.79 + } 1.80 + 1.81 + io = fo->objs[ fo->i ]; 1.82 + fo->i++; 1.83 + 1.84 + return nss_ckcapi_CreateMDObject(arena, io, pError); 1.85 +} 1.86 + 1.87 +static CK_BBOOL 1.88 +ckcapi_attrmatch 1.89 +( 1.90 + CK_ATTRIBUTE_PTR a, 1.91 + ckcapiInternalObject *o 1.92 +) 1.93 +{ 1.94 + PRBool prb; 1.95 + const NSSItem *b; 1.96 + 1.97 + b = nss_ckcapi_FetchAttribute(o, a->type); 1.98 + if (b == NULL) { 1.99 + return CK_FALSE; 1.100 + } 1.101 + 1.102 + if( a->ulValueLen != b->size ) { 1.103 + /* match a decoded serial number */ 1.104 + if ((a->type == CKA_SERIAL_NUMBER) && (a->ulValueLen < b->size)) { 1.105 + unsigned int len; 1.106 + unsigned char *data; 1.107 + 1.108 + data = nss_ckcapi_DERUnwrap(b->data, b->size, &len, NULL); 1.109 + if ((len == a->ulValueLen) && 1.110 + nsslibc_memequal(a->pValue, data, len, (PRStatus *)NULL)) { 1.111 + return CK_TRUE; 1.112 + } 1.113 + } 1.114 + return CK_FALSE; 1.115 + } 1.116 + 1.117 + prb = nsslibc_memequal(a->pValue, b->data, b->size, (PRStatus *)NULL); 1.118 + 1.119 + if( PR_TRUE == prb ) { 1.120 + return CK_TRUE; 1.121 + } else { 1.122 + return CK_FALSE; 1.123 + } 1.124 +} 1.125 + 1.126 + 1.127 +static CK_BBOOL 1.128 +ckcapi_match 1.129 +( 1.130 + CK_ATTRIBUTE_PTR pTemplate, 1.131 + CK_ULONG ulAttributeCount, 1.132 + ckcapiInternalObject *o 1.133 +) 1.134 +{ 1.135 + CK_ULONG i; 1.136 + 1.137 + for( i = 0; i < ulAttributeCount; i++ ) { 1.138 + if (CK_FALSE == ckcapi_attrmatch(&pTemplate[i], o)) { 1.139 + return CK_FALSE; 1.140 + } 1.141 + } 1.142 + 1.143 + /* Every attribute passed */ 1.144 + return CK_TRUE; 1.145 +} 1.146 + 1.147 +#define CKAPI_ITEM_CHUNK 20 1.148 + 1.149 +#define PUT_Object(obj,err) \ 1.150 + { \ 1.151 + if (count >= size) { \ 1.152 + *listp = *listp ? \ 1.153 + nss_ZREALLOCARRAY(*listp, ckcapiInternalObject *, \ 1.154 + (size+CKAPI_ITEM_CHUNK) ) : \ 1.155 + nss_ZNEWARRAY(NULL, ckcapiInternalObject *, \ 1.156 + (size+CKAPI_ITEM_CHUNK) ) ; \ 1.157 + if ((ckcapiInternalObject **)NULL == *listp) { \ 1.158 + err = CKR_HOST_MEMORY; \ 1.159 + goto loser; \ 1.160 + } \ 1.161 + size += CKAPI_ITEM_CHUNK; \ 1.162 + } \ 1.163 + (*listp)[ count ] = (obj); \ 1.164 + count++; \ 1.165 + } 1.166 + 1.167 + 1.168 +/* 1.169 + * pass parameters back through the callback. 1.170 + */ 1.171 +typedef struct BareCollectParamsStr { 1.172 + CK_OBJECT_CLASS objClass; 1.173 + CK_ATTRIBUTE_PTR pTemplate; 1.174 + CK_ULONG ulAttributeCount; 1.175 + ckcapiInternalObject ***listp; 1.176 + PRUint32 size; 1.177 + PRUint32 count; 1.178 +} BareCollectParams; 1.179 + 1.180 +/* collect_bare's callback. Called for each object that 1.181 + * supposedly has a PROVINDER_INFO property */ 1.182 +static BOOL WINAPI 1.183 +doBareCollect 1.184 +( 1.185 + const CRYPT_HASH_BLOB *msKeyID, 1.186 + DWORD flags, 1.187 + void *reserved, 1.188 + void *args, 1.189 + DWORD cProp, 1.190 + DWORD *propID, 1.191 + void **propData, 1.192 + DWORD *propSize 1.193 +) 1.194 +{ 1.195 + BareCollectParams *bcp = (BareCollectParams *) args; 1.196 + PRUint32 size = bcp->size; 1.197 + PRUint32 count = bcp->count; 1.198 + ckcapiInternalObject ***listp = bcp->listp; 1.199 + ckcapiInternalObject *io = NULL; 1.200 + DWORD i; 1.201 + CRYPT_KEY_PROV_INFO *keyProvInfo = NULL; 1.202 + void *idData; 1.203 + CK_RV error; 1.204 + 1.205 + /* make sure there is a Key Provider Info property */ 1.206 + for (i=0; i < cProp; i++) { 1.207 + if (CERT_KEY_PROV_INFO_PROP_ID == propID[i]) { 1.208 + keyProvInfo = (CRYPT_KEY_PROV_INFO *)propData[i]; 1.209 + break; 1.210 + } 1.211 + } 1.212 + if ((CRYPT_KEY_PROV_INFO *)NULL == keyProvInfo) { 1.213 + return 1; 1.214 + } 1.215 + 1.216 + /* copy the key ID */ 1.217 + idData = nss_ZNEWARRAY(NULL, char, msKeyID->cbData); 1.218 + if ((void *)NULL == idData) { 1.219 + goto loser; 1.220 + } 1.221 + nsslibc_memcpy(idData, msKeyID->pbData, msKeyID->cbData); 1.222 + 1.223 + /* build a bare internal object */ 1.224 + io = nss_ZNEW(NULL, ckcapiInternalObject); 1.225 + if ((ckcapiInternalObject *)NULL == io) { 1.226 + goto loser; 1.227 + } 1.228 + io->type = ckcapiBareKey; 1.229 + io->objClass = bcp->objClass; 1.230 + io->u.key.provInfo = *keyProvInfo; 1.231 + io->u.key.provInfo.pwszContainerName = 1.232 + nss_ckcapi_WideDup(keyProvInfo->pwszContainerName); 1.233 + io->u.key.provInfo.pwszProvName = 1.234 + nss_ckcapi_WideDup(keyProvInfo->pwszProvName); 1.235 + io->u.key.provName = nss_ckcapi_WideToUTF8(keyProvInfo->pwszProvName); 1.236 + io->u.key.containerName = 1.237 + nss_ckcapi_WideToUTF8(keyProvInfo->pwszContainerName); 1.238 + io->u.key.hProv = 0; 1.239 + io->idData = idData; 1.240 + io->id.data = idData; 1.241 + io->id.size = msKeyID->cbData; 1.242 + idData = NULL; 1.243 + 1.244 + /* see if it matches */ 1.245 + if( CK_FALSE == ckcapi_match(bcp->pTemplate, bcp->ulAttributeCount, io) ) { 1.246 + goto loser; 1.247 + } 1.248 + PUT_Object(io, error); 1.249 + bcp->size = size; 1.250 + bcp->count = count; 1.251 + return 1; 1.252 + 1.253 +loser: 1.254 + if (io) { 1.255 + nss_ckcapi_DestroyInternalObject(io); 1.256 + } 1.257 + nss_ZFreeIf(idData); 1.258 + return 1; 1.259 +} 1.260 + 1.261 +/* 1.262 + * collect the bare keys running around 1.263 + */ 1.264 +static PRUint32 1.265 +collect_bare( 1.266 + CK_OBJECT_CLASS objClass, 1.267 + CK_ATTRIBUTE_PTR pTemplate, 1.268 + CK_ULONG ulAttributeCount, 1.269 + ckcapiInternalObject ***listp, 1.270 + PRUint32 *sizep, 1.271 + PRUint32 count, 1.272 + CK_RV *pError 1.273 +) 1.274 +{ 1.275 + BOOL rc; 1.276 + BareCollectParams bareCollectParams; 1.277 + 1.278 + bareCollectParams.objClass = objClass; 1.279 + bareCollectParams.pTemplate = pTemplate; 1.280 + bareCollectParams.ulAttributeCount = ulAttributeCount; 1.281 + bareCollectParams.listp = listp; 1.282 + bareCollectParams.size = *sizep; 1.283 + bareCollectParams.count = count; 1.284 + 1.285 + rc = CryptEnumKeyIdentifierProperties(NULL, CERT_KEY_PROV_INFO_PROP_ID, 0, 1.286 + NULL, NULL, &bareCollectParams, doBareCollect); 1.287 + 1.288 + *sizep = bareCollectParams.size; 1.289 + return bareCollectParams.count; 1.290 +} 1.291 + 1.292 +/* find all the certs that represent the appropriate object (cert, priv key, or 1.293 + * pub key) in the cert store. 1.294 + */ 1.295 +static PRUint32 1.296 +collect_class( 1.297 + CK_OBJECT_CLASS objClass, 1.298 + LPCSTR storeStr, 1.299 + PRBool hasID, 1.300 + CK_ATTRIBUTE_PTR pTemplate, 1.301 + CK_ULONG ulAttributeCount, 1.302 + ckcapiInternalObject ***listp, 1.303 + PRUint32 *sizep, 1.304 + PRUint32 count, 1.305 + CK_RV *pError 1.306 +) 1.307 +{ 1.308 + PRUint32 size = *sizep; 1.309 + ckcapiInternalObject *next = NULL; 1.310 + HCERTSTORE hStore; 1.311 + PCCERT_CONTEXT certContext = NULL; 1.312 + PRBool isKey = 1.313 + (objClass == CKO_PUBLIC_KEY) | (objClass == CKO_PRIVATE_KEY); 1.314 + 1.315 + hStore = CertOpenSystemStore((HCRYPTPROV)NULL, storeStr); 1.316 + if (NULL == hStore) { 1.317 + return count; /* none found does not imply an error */ 1.318 + } 1.319 + 1.320 + /* FUTURE: use CertFindCertificateInStore to filter better -- so we don't 1.321 + * have to enumerate all the certificates */ 1.322 + while ((PCERT_CONTEXT) NULL != 1.323 + (certContext= CertEnumCertificatesInStore(hStore, certContext))) { 1.324 + /* first filter out non user certs if we are looking for keys */ 1.325 + if (isKey) { 1.326 + /* make sure there is a Key Provider Info property */ 1.327 + CRYPT_KEY_PROV_INFO *keyProvInfo; 1.328 + DWORD size = 0; 1.329 + BOOL rv; 1.330 + rv =CertGetCertificateContextProperty(certContext, 1.331 + CERT_KEY_PROV_INFO_PROP_ID, NULL, &size); 1.332 + if (!rv) { 1.333 + int reason = GetLastError(); 1.334 + /* we only care if it exists, we don't really need to fetch it yet */ 1.335 + if (reason == CRYPT_E_NOT_FOUND) { 1.336 + continue; 1.337 + } 1.338 + } 1.339 + /* filter out the non-microsoft providers */ 1.340 + keyProvInfo = (CRYPT_KEY_PROV_INFO *)nss_ZAlloc(NULL, size); 1.341 + if (keyProvInfo) { 1.342 + rv =CertGetCertificateContextProperty(certContext, 1.343 + CERT_KEY_PROV_INFO_PROP_ID, keyProvInfo, &size); 1.344 + if (rv) { 1.345 + char *provName = nss_ckcapi_WideToUTF8(keyProvInfo->pwszProvName); 1.346 + nss_ZFreeIf(keyProvInfo); 1.347 + 1.348 + if (provName && 1.349 + (strncmp(provName, "Microsoft", sizeof("Microsoft")-1) != 0)) { 1.350 + continue; 1.351 + } 1.352 + } else { 1.353 + int reason = GetLastError(); 1.354 + /* we only care if it exists, we don't really need to fetch it yet */ 1.355 + nss_ZFreeIf(keyProvInfo); 1.356 + if (reason == CRYPT_E_NOT_FOUND) { 1.357 + continue; 1.358 + } 1.359 + 1.360 + } 1.361 + } 1.362 + } 1.363 + 1.364 + if ((ckcapiInternalObject *)NULL == next) { 1.365 + next = nss_ZNEW(NULL, ckcapiInternalObject); 1.366 + if ((ckcapiInternalObject *)NULL == next) { 1.367 + *pError = CKR_HOST_MEMORY; 1.368 + goto loser; 1.369 + } 1.370 + } 1.371 + next->type = ckcapiCert; 1.372 + next->objClass = objClass; 1.373 + next->u.cert.certContext = certContext; 1.374 + next->u.cert.hasID = hasID; 1.375 + next->u.cert.certStore = storeStr; 1.376 + if( CK_TRUE == ckcapi_match(pTemplate, ulAttributeCount, next) ) { 1.377 + /* clear cached values that may be dependent on our old certContext */ 1.378 + memset(&next->u.cert, 0, sizeof(next->u.cert)); 1.379 + /* get a 'permanent' context */ 1.380 + next->u.cert.certContext = CertDuplicateCertificateContext(certContext); 1.381 + next->objClass = objClass; 1.382 + next->u.cert.certContext = certContext; 1.383 + next->u.cert.hasID = hasID; 1.384 + next->u.cert.certStore = storeStr; 1.385 + PUT_Object(next, *pError); 1.386 + next = NULL; /* need to allocate a new one now */ 1.387 + } else { 1.388 + /* don't cache the values we just loaded */ 1.389 + memset(&next->u.cert, 0, sizeof(next->u.cert)); 1.390 + } 1.391 + } 1.392 +loser: 1.393 + CertCloseStore(hStore, 0); 1.394 + nss_ZFreeIf(next); 1.395 + *sizep = size; 1.396 + return count; 1.397 +} 1.398 + 1.399 +NSS_IMPLEMENT PRUint32 1.400 +nss_ckcapi_collect_all_certs( 1.401 + CK_ATTRIBUTE_PTR pTemplate, 1.402 + CK_ULONG ulAttributeCount, 1.403 + ckcapiInternalObject ***listp, 1.404 + PRUint32 *sizep, 1.405 + PRUint32 count, 1.406 + CK_RV *pError 1.407 +) 1.408 +{ 1.409 + count = collect_class(CKO_CERTIFICATE, "My", PR_TRUE, pTemplate, 1.410 + ulAttributeCount, listp, sizep, count, pError); 1.411 + /*count = collect_class(CKO_CERTIFICATE, "AddressBook", PR_FALSE, pTemplate, 1.412 + ulAttributeCount, listp, sizep, count, pError); */ 1.413 + count = collect_class(CKO_CERTIFICATE, "CA", PR_FALSE, pTemplate, 1.414 + ulAttributeCount, listp, sizep, count, pError); 1.415 + count = collect_class(CKO_CERTIFICATE, "Root", PR_FALSE, pTemplate, 1.416 + ulAttributeCount, listp, sizep, count, pError); 1.417 + count = collect_class(CKO_CERTIFICATE, "Trust", PR_FALSE, pTemplate, 1.418 + ulAttributeCount, listp, sizep, count, pError); 1.419 + count = collect_class(CKO_CERTIFICATE, "TrustedPeople", PR_FALSE, pTemplate, 1.420 + ulAttributeCount, listp, sizep, count, pError); 1.421 + count = collect_class(CKO_CERTIFICATE, "AuthRoot", PR_FALSE, pTemplate, 1.422 + ulAttributeCount, listp, sizep, count, pError); 1.423 + return count; 1.424 +} 1.425 + 1.426 +CK_OBJECT_CLASS 1.427 +ckcapi_GetObjectClass(CK_ATTRIBUTE_PTR pTemplate, 1.428 + CK_ULONG ulAttributeCount) 1.429 +{ 1.430 + CK_ULONG i; 1.431 + 1.432 + for (i=0; i < ulAttributeCount; i++) 1.433 + { 1.434 + if (pTemplate[i].type == CKA_CLASS) { 1.435 + return *(CK_OBJECT_CLASS *) pTemplate[i].pValue; 1.436 + } 1.437 + } 1.438 + /* need to return a value that says 'fetch them all' */ 1.439 + return CK_INVALID_HANDLE; 1.440 +} 1.441 + 1.442 +static PRUint32 1.443 +collect_objects( 1.444 + CK_ATTRIBUTE_PTR pTemplate, 1.445 + CK_ULONG ulAttributeCount, 1.446 + ckcapiInternalObject ***listp, 1.447 + CK_RV *pError 1.448 +) 1.449 +{ 1.450 + PRUint32 i; 1.451 + PRUint32 count = 0; 1.452 + PRUint32 size = 0; 1.453 + CK_OBJECT_CLASS objClass; 1.454 + 1.455 + /* 1.456 + * first handle the static build in objects (if any) 1.457 + */ 1.458 + for( i = 0; i < nss_ckcapi_nObjects; i++ ) { 1.459 + ckcapiInternalObject *o = (ckcapiInternalObject *)&nss_ckcapi_data[i]; 1.460 + 1.461 + if( CK_TRUE == ckcapi_match(pTemplate, ulAttributeCount, o) ) { 1.462 + PUT_Object(o, *pError); 1.463 + } 1.464 + } 1.465 + 1.466 + /* 1.467 + * now handle the various object types 1.468 + */ 1.469 + objClass = ckcapi_GetObjectClass(pTemplate, ulAttributeCount); 1.470 + *pError = CKR_OK; 1.471 + switch (objClass) { 1.472 + case CKO_CERTIFICATE: 1.473 + count = nss_ckcapi_collect_all_certs(pTemplate, ulAttributeCount, listp, 1.474 + &size, count, pError); 1.475 + break; 1.476 + case CKO_PUBLIC_KEY: 1.477 + count = collect_class(objClass, "My", PR_TRUE, pTemplate, 1.478 + ulAttributeCount, listp, &size, count, pError); 1.479 + count = collect_bare(objClass, pTemplate, ulAttributeCount, listp, 1.480 + &size, count, pError); 1.481 + break; 1.482 + case CKO_PRIVATE_KEY: 1.483 + count = collect_class(objClass, "My", PR_TRUE, pTemplate, 1.484 + ulAttributeCount, listp, &size, count, pError); 1.485 + count = collect_bare(objClass, pTemplate, ulAttributeCount, listp, 1.486 + &size, count, pError); 1.487 + break; 1.488 + /* all of them */ 1.489 + case CK_INVALID_HANDLE: 1.490 + count = nss_ckcapi_collect_all_certs(pTemplate, ulAttributeCount, listp, 1.491 + &size, count, pError); 1.492 + count = collect_class(CKO_PUBLIC_KEY, "My", PR_TRUE, pTemplate, 1.493 + ulAttributeCount, listp, &size, count, pError); 1.494 + count = collect_bare(CKO_PUBLIC_KEY, pTemplate, ulAttributeCount, listp, 1.495 + &size, count, pError); 1.496 + count = collect_class(CKO_PRIVATE_KEY, "My", PR_TRUE, pTemplate, 1.497 + ulAttributeCount, listp, &size, count, pError); 1.498 + count = collect_bare(CKO_PRIVATE_KEY, pTemplate, ulAttributeCount, listp, 1.499 + &size, count, pError); 1.500 + break; 1.501 + default: 1.502 + goto done; /* no other object types we understand in this module */ 1.503 + } 1.504 + if (CKR_OK != *pError) { 1.505 + goto loser; 1.506 + } 1.507 + 1.508 + 1.509 +done: 1.510 + return count; 1.511 +loser: 1.512 + nss_ZFreeIf(*listp); 1.513 + return 0; 1.514 +} 1.515 + 1.516 + 1.517 + 1.518 +NSS_IMPLEMENT NSSCKMDFindObjects * 1.519 +nss_ckcapi_FindObjectsInit 1.520 +( 1.521 + NSSCKFWSession *fwSession, 1.522 + CK_ATTRIBUTE_PTR pTemplate, 1.523 + CK_ULONG ulAttributeCount, 1.524 + CK_RV *pError 1.525 +) 1.526 +{ 1.527 + /* This could be made more efficient. I'm rather rushed. */ 1.528 + NSSArena *arena; 1.529 + NSSCKMDFindObjects *rv = (NSSCKMDFindObjects *)NULL; 1.530 + struct ckcapiFOStr *fo = (struct ckcapiFOStr *)NULL; 1.531 + ckcapiInternalObject **temp = (ckcapiInternalObject **)NULL; 1.532 + 1.533 + arena = NSSArena_Create(); 1.534 + if( (NSSArena *)NULL == arena ) { 1.535 + goto loser; 1.536 + } 1.537 + 1.538 + rv = nss_ZNEW(arena, NSSCKMDFindObjects); 1.539 + if( (NSSCKMDFindObjects *)NULL == rv ) { 1.540 + *pError = CKR_HOST_MEMORY; 1.541 + goto loser; 1.542 + } 1.543 + 1.544 + fo = nss_ZNEW(arena, struct ckcapiFOStr); 1.545 + if( (struct ckcapiFOStr *)NULL == fo ) { 1.546 + *pError = CKR_HOST_MEMORY; 1.547 + goto loser; 1.548 + } 1.549 + 1.550 + fo->arena = arena; 1.551 + /* fo->n and fo->i are already zero */ 1.552 + 1.553 + rv->etc = (void *)fo; 1.554 + rv->Final = ckcapi_mdFindObjects_Final; 1.555 + rv->Next = ckcapi_mdFindObjects_Next; 1.556 + rv->null = (void *)NULL; 1.557 + 1.558 + fo->n = collect_objects(pTemplate, ulAttributeCount, &temp, pError); 1.559 + if (*pError != CKR_OK) { 1.560 + goto loser; 1.561 + } 1.562 + 1.563 + fo->objs = nss_ZNEWARRAY(arena, ckcapiInternalObject *, fo->n); 1.564 + if( (ckcapiInternalObject **)NULL == fo->objs ) { 1.565 + *pError = CKR_HOST_MEMORY; 1.566 + goto loser; 1.567 + } 1.568 + 1.569 + (void)nsslibc_memcpy(fo->objs, temp, sizeof(ckcapiInternalObject *) * fo->n); 1.570 + nss_ZFreeIf(temp); 1.571 + temp = (ckcapiInternalObject **)NULL; 1.572 + 1.573 + return rv; 1.574 + 1.575 + loser: 1.576 + nss_ZFreeIf(temp); 1.577 + nss_ZFreeIf(fo); 1.578 + nss_ZFreeIf(rv); 1.579 + if ((NSSArena *)NULL != arena) { 1.580 + NSSArena_Destroy(arena); 1.581 + } 1.582 + return (NSSCKMDFindObjects *)NULL; 1.583 +} 1.584 +