OLD | NEW |
| (Empty) |
1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
4 | |
5 #ifndef DEVM_H | |
6 #include "devm.h" | |
7 #endif /* DEVM_H */ | |
8 | |
9 #ifndef CKHELPER_H | |
10 #include "ckhelper.h" | |
11 #endif /* CKHELPER_H */ | |
12 | |
13 NSS_IMPLEMENT nssCryptokiObject * | |
14 nssCryptokiObject_Create( | |
15 NSSToken *t, | |
16 nssSession *session, | |
17 CK_OBJECT_HANDLE h) | |
18 { | |
19 PRStatus status; | |
20 NSSSlot *slot; | |
21 nssCryptokiObject *object; | |
22 CK_BBOOL *isTokenObject; | |
23 CK_ATTRIBUTE cert_template[] = { | |
24 { CKA_TOKEN, NULL, 0 }, | |
25 { CKA_LABEL, NULL, 0 } | |
26 }; | |
27 slot = nssToken_GetSlot(t); | |
28 status = nssCKObject_GetAttributes(h, cert_template, 2, | |
29 NULL, session, slot); | |
30 nssSlot_Destroy(slot); | |
31 if (status != PR_SUCCESS) { | |
32 /* a failure here indicates a device error */ | |
33 return (nssCryptokiObject *)NULL; | |
34 } | |
35 object = nss_ZNEW(NULL, nssCryptokiObject); | |
36 if (!object) { | |
37 return (nssCryptokiObject *)NULL; | |
38 } | |
39 object->handle = h; | |
40 object->token = nssToken_AddRef(t); | |
41 isTokenObject = (CK_BBOOL *)cert_template[0].pValue; | |
42 object->isTokenObject = *isTokenObject; | |
43 nss_ZFreeIf(isTokenObject); | |
44 NSS_CK_ATTRIBUTE_TO_UTF8(&cert_template[1], object->label); | |
45 return object; | |
46 } | |
47 | |
48 NSS_IMPLEMENT void | |
49 nssCryptokiObject_Destroy( | |
50 nssCryptokiObject *object) | |
51 { | |
52 if (object) { | |
53 nssToken_Destroy(object->token); | |
54 nss_ZFreeIf(object->label); | |
55 nss_ZFreeIf(object); | |
56 } | |
57 } | |
58 | |
59 NSS_IMPLEMENT nssCryptokiObject * | |
60 nssCryptokiObject_Clone( | |
61 nssCryptokiObject *object) | |
62 { | |
63 nssCryptokiObject *rvObject; | |
64 rvObject = nss_ZNEW(NULL, nssCryptokiObject); | |
65 if (rvObject) { | |
66 rvObject->handle = object->handle; | |
67 rvObject->token = nssToken_AddRef(object->token); | |
68 rvObject->isTokenObject = object->isTokenObject; | |
69 if (object->label) { | |
70 rvObject->label = nssUTF8_Duplicate(object->label, NULL); | |
71 } | |
72 } | |
73 return rvObject; | |
74 } | |
75 | |
76 NSS_EXTERN PRBool | |
77 nssCryptokiObject_Equal( | |
78 nssCryptokiObject *o1, | |
79 nssCryptokiObject *o2) | |
80 { | |
81 return (o1->token == o2->token && o1->handle == o2->handle); | |
82 } | |
83 | |
84 NSS_IMPLEMENT PRUint32 | |
85 nssPKCS11String_Length(CK_CHAR *pkcs11Str, PRUint32 bufLen) | |
86 { | |
87 PRInt32 i; | |
88 for (i = bufLen - 1; i >= 0;) { | |
89 if (pkcs11Str[i] != ' ' && pkcs11Str[i] != '\0') | |
90 break; | |
91 --i; | |
92 } | |
93 return (PRUint32)(i + 1); | |
94 } | |
95 | |
96 /* | |
97 * Slot arrays | |
98 */ | |
99 | |
100 NSS_IMPLEMENT NSSSlot ** | |
101 nssSlotArray_Clone( | |
102 NSSSlot **slots) | |
103 { | |
104 NSSSlot **rvSlots = NULL; | |
105 NSSSlot **sp = slots; | |
106 PRUint32 count = 0; | |
107 while (sp && *sp) | |
108 count++; | |
109 if (count > 0) { | |
110 rvSlots = nss_ZNEWARRAY(NULL, NSSSlot *, count + 1); | |
111 if (rvSlots) { | |
112 for (sp = slots, count = 0; *sp; sp++) { | |
113 rvSlots[count++] = nssSlot_AddRef(*sp); | |
114 } | |
115 } | |
116 } | |
117 return rvSlots; | |
118 } | |
119 | |
120 NSS_IMPLEMENT void | |
121 nssSlotArray_Destroy( | |
122 NSSSlot **slots) | |
123 { | |
124 if (slots) { | |
125 NSSSlot **slotp; | |
126 for (slotp = slots; *slotp; slotp++) { | |
127 nssSlot_Destroy(*slotp); | |
128 } | |
129 nss_ZFreeIf(slots); | |
130 } | |
131 } | |
132 | |
133 NSS_IMPLEMENT void | |
134 NSSSlotArray_Destroy( | |
135 NSSSlot **slots) | |
136 { | |
137 nssSlotArray_Destroy(slots); | |
138 } | |
139 | |
140 NSS_IMPLEMENT void | |
141 nssTokenArray_Destroy( | |
142 NSSToken **tokens) | |
143 { | |
144 if (tokens) { | |
145 NSSToken **tokenp; | |
146 for (tokenp = tokens; *tokenp; tokenp++) { | |
147 nssToken_Destroy(*tokenp); | |
148 } | |
149 nss_ZFreeIf(tokens); | |
150 } | |
151 } | |
152 | |
153 NSS_IMPLEMENT void | |
154 NSSTokenArray_Destroy( | |
155 NSSToken **tokens) | |
156 { | |
157 nssTokenArray_Destroy(tokens); | |
158 } | |
159 | |
160 NSS_IMPLEMENT void | |
161 nssCryptokiObjectArray_Destroy( | |
162 nssCryptokiObject **objects) | |
163 { | |
164 if (objects) { | |
165 nssCryptokiObject **op; | |
166 for (op = objects; *op; op++) { | |
167 nssCryptokiObject_Destroy(*op); | |
168 } | |
169 nss_ZFreeIf(objects); | |
170 } | |
171 } | |
172 | |
173 /* object cache for token */ | |
174 | |
175 typedef struct | |
176 { | |
177 NSSArena *arena; | |
178 nssCryptokiObject *object; | |
179 CK_ATTRIBUTE_PTR attributes; | |
180 CK_ULONG numAttributes; | |
181 } nssCryptokiObjectAndAttributes; | |
182 | |
183 enum { | |
184 cachedCerts = 0, | |
185 cachedTrust = 1, | |
186 cachedCRLs = 2 | |
187 } cachedObjectType; | |
188 | |
189 struct nssTokenObjectCacheStr { | |
190 NSSToken *token; | |
191 PZLock *lock; | |
192 PRBool loggedIn; | |
193 PRBool doObjectType[3]; | |
194 PRBool searchedObjectType[3]; | |
195 nssCryptokiObjectAndAttributes **objects[3]; | |
196 }; | |
197 | |
198 NSS_IMPLEMENT nssTokenObjectCache * | |
199 nssTokenObjectCache_Create( | |
200 NSSToken *token, | |
201 PRBool cacheCerts, | |
202 PRBool cacheTrust, | |
203 PRBool cacheCRLs) | |
204 { | |
205 nssTokenObjectCache *rvCache; | |
206 rvCache = nss_ZNEW(NULL, nssTokenObjectCache); | |
207 if (!rvCache) { | |
208 goto loser; | |
209 } | |
210 rvCache->lock = PZ_NewLock(nssILockOther); /* XXX */ | |
211 if (!rvCache->lock) { | |
212 goto loser; | |
213 } | |
214 rvCache->doObjectType[cachedCerts] = cacheCerts; | |
215 rvCache->doObjectType[cachedTrust] = cacheTrust; | |
216 rvCache->doObjectType[cachedCRLs] = cacheCRLs; | |
217 rvCache->token = token; /* cache goes away with token */ | |
218 return rvCache; | |
219 loser: | |
220 nssTokenObjectCache_Destroy(rvCache); | |
221 return (nssTokenObjectCache *)NULL; | |
222 } | |
223 | |
224 static void | |
225 clear_cache( | |
226 nssTokenObjectCache *cache) | |
227 { | |
228 nssCryptokiObjectAndAttributes **oa; | |
229 PRUint32 objectType; | |
230 for (objectType = cachedCerts; objectType <= cachedCRLs; objectType++) { | |
231 cache->searchedObjectType[objectType] = PR_FALSE; | |
232 if (!cache->objects[objectType]) { | |
233 continue; | |
234 } | |
235 for (oa = cache->objects[objectType]; *oa; oa++) { | |
236 /* prevent the token from being destroyed */ | |
237 (*oa)->object->token = NULL; | |
238 nssCryptokiObject_Destroy((*oa)->object); | |
239 nssArena_Destroy((*oa)->arena); | |
240 } | |
241 nss_ZFreeIf(cache->objects[objectType]); | |
242 cache->objects[objectType] = NULL; | |
243 } | |
244 } | |
245 | |
246 NSS_IMPLEMENT void | |
247 nssTokenObjectCache_Clear( | |
248 nssTokenObjectCache *cache) | |
249 { | |
250 if (cache) { | |
251 PZ_Lock(cache->lock); | |
252 clear_cache(cache); | |
253 PZ_Unlock(cache->lock); | |
254 } | |
255 } | |
256 | |
257 NSS_IMPLEMENT void | |
258 nssTokenObjectCache_Destroy( | |
259 nssTokenObjectCache *cache) | |
260 { | |
261 if (cache) { | |
262 clear_cache(cache); | |
263 if (cache->lock) { | |
264 PZ_DestroyLock(cache->lock); | |
265 } | |
266 nss_ZFreeIf(cache); | |
267 } | |
268 } | |
269 | |
270 NSS_IMPLEMENT PRBool | |
271 nssTokenObjectCache_HaveObjectClass( | |
272 nssTokenObjectCache *cache, | |
273 CK_OBJECT_CLASS objclass) | |
274 { | |
275 PRBool haveIt; | |
276 PZ_Lock(cache->lock); | |
277 switch (objclass) { | |
278 case CKO_CERTIFICATE: | |
279 haveIt = cache->doObjectType[cachedCerts]; | |
280 break; | |
281 case CKO_NETSCAPE_TRUST: | |
282 haveIt = cache->doObjectType[cachedTrust]; | |
283 break; | |
284 case CKO_NETSCAPE_CRL: | |
285 haveIt = cache->doObjectType[cachedCRLs]; | |
286 break; | |
287 default: | |
288 haveIt = PR_FALSE; | |
289 } | |
290 PZ_Unlock(cache->lock); | |
291 return haveIt; | |
292 } | |
293 | |
294 static nssCryptokiObjectAndAttributes ** | |
295 create_object_array( | |
296 nssCryptokiObject **objects, | |
297 PRBool *doObjects, | |
298 PRUint32 *numObjects, | |
299 PRStatus *status) | |
300 { | |
301 nssCryptokiObjectAndAttributes **rvOandA = NULL; | |
302 *numObjects = 0; | |
303 /* There are no objects for this type */ | |
304 if (!objects || !*objects) { | |
305 *status = PR_SUCCESS; | |
306 return rvOandA; | |
307 } | |
308 while (*objects++) | |
309 (*numObjects)++; | |
310 if (*numObjects >= MAX_LOCAL_CACHE_OBJECTS) { | |
311 /* Hit the maximum allowed, so don't use a cache (there are | |
312 * too many objects to make caching worthwhile, presumably, if | |
313 * the token can handle that many objects, it can handle searching. | |
314 */ | |
315 *doObjects = PR_FALSE; | |
316 *status = PR_FAILURE; | |
317 *numObjects = 0; | |
318 } else { | |
319 rvOandA = nss_ZNEWARRAY(NULL, | |
320 nssCryptokiObjectAndAttributes *, | |
321 *numObjects + 1); | |
322 *status = rvOandA ? PR_SUCCESS : PR_FAILURE; | |
323 } | |
324 return rvOandA; | |
325 } | |
326 | |
327 static nssCryptokiObjectAndAttributes * | |
328 create_object( | |
329 nssCryptokiObject *object, | |
330 const CK_ATTRIBUTE_TYPE *types, | |
331 PRUint32 numTypes, | |
332 PRStatus *status) | |
333 { | |
334 PRUint32 j; | |
335 NSSArena *arena = NULL; | |
336 NSSSlot *slot = NULL; | |
337 nssSession *session = NULL; | |
338 nssCryptokiObjectAndAttributes *rvCachedObject = NULL; | |
339 | |
340 slot = nssToken_GetSlot(object->token); | |
341 if (!slot) { | |
342 nss_SetError(NSS_ERROR_INVALID_POINTER); | |
343 goto loser; | |
344 } | |
345 session = nssToken_GetDefaultSession(object->token); | |
346 if (!session) { | |
347 nss_SetError(NSS_ERROR_INVALID_POINTER); | |
348 goto loser; | |
349 } | |
350 arena = nssArena_Create(); | |
351 if (!arena) { | |
352 goto loser; | |
353 } | |
354 rvCachedObject = nss_ZNEW(arena, nssCryptokiObjectAndAttributes); | |
355 if (!rvCachedObject) { | |
356 goto loser; | |
357 } | |
358 rvCachedObject->arena = arena; | |
359 /* The cache is tied to the token, and therefore the objects | |
360 * in it should not hold references to the token. | |
361 */ | |
362 nssToken_Destroy(object->token); | |
363 rvCachedObject->object = object; | |
364 rvCachedObject->attributes = nss_ZNEWARRAY(arena, CK_ATTRIBUTE, numTypes); | |
365 if (!rvCachedObject->attributes) { | |
366 goto loser; | |
367 } | |
368 for (j = 0; j < numTypes; j++) { | |
369 rvCachedObject->attributes[j].type = types[j]; | |
370 } | |
371 *status = nssCKObject_GetAttributes(object->handle, | |
372 rvCachedObject->attributes, | |
373 numTypes, | |
374 arena, | |
375 session, | |
376 slot); | |
377 if (*status != PR_SUCCESS) { | |
378 goto loser; | |
379 } | |
380 rvCachedObject->numAttributes = numTypes; | |
381 *status = PR_SUCCESS; | |
382 nssSlot_Destroy(slot); | |
383 | |
384 return rvCachedObject; | |
385 loser: | |
386 *status = PR_FAILURE; | |
387 if (slot) { | |
388 nssSlot_Destroy(slot); | |
389 } | |
390 if (arena) | |
391 nssArena_Destroy(arena); | |
392 return (nssCryptokiObjectAndAttributes *)NULL; | |
393 } | |
394 | |
395 /* | |
396 * | |
397 * State diagram for cache: | |
398 * | |
399 * token !present token removed | |
400 * +-------------------------+<----------------------+ | |
401 * | ^ | | |
402 * v | | | |
403 * +----------+ slot friendly | token present +----------+ | |
404 * | cache | -----------------> % ---------------> | cache | | |
405 * | unloaded | | loaded | | |
406 * +----------+ +----------+ | |
407 * ^ | ^ | | |
408 * | | slot !friendly slot logged in | | | |
409 * | +-----------------------> % ----------------------+ | | |
410 * | | | | |
411 * | slot logged out v slot !friendly | | |
412 * +-----------------------------+<--------------------------+ | |
413 * | |
414 */ | |
415 | |
416 /* This function must not be called with cache->lock locked. */ | |
417 static PRBool | |
418 token_is_present( | |
419 nssTokenObjectCache *cache) | |
420 { | |
421 NSSSlot *slot = nssToken_GetSlot(cache->token); | |
422 PRBool tokenPresent = nssSlot_IsTokenPresent(slot); | |
423 nssSlot_Destroy(slot); | |
424 return tokenPresent; | |
425 } | |
426 | |
427 static PRBool | |
428 search_for_objects( | |
429 nssTokenObjectCache *cache) | |
430 { | |
431 PRBool doSearch = PR_FALSE; | |
432 NSSSlot *slot = nssToken_GetSlot(cache->token); | |
433 /* Handle non-friendly slots (slots which require login for objects) */ | |
434 if (!nssSlot_IsFriendly(slot)) { | |
435 if (nssSlot_IsLoggedIn(slot)) { | |
436 /* Either no state change, or went from !logged in -> logged in */ | |
437 cache->loggedIn = PR_TRUE; | |
438 doSearch = PR_TRUE; | |
439 } else { | |
440 if (cache->loggedIn) { | |
441 /* went from logged in -> !logged in, destroy cached objects */ | |
442 clear_cache(cache); | |
443 cache->loggedIn = PR_FALSE; | |
444 } /* else no state change, still not logged in, so exit */ | |
445 } | |
446 } else { | |
447 /* slot is friendly, thus always available for search */ | |
448 doSearch = PR_TRUE; | |
449 } | |
450 nssSlot_Destroy(slot); | |
451 return doSearch; | |
452 } | |
453 | |
454 static nssCryptokiObjectAndAttributes * | |
455 create_cert( | |
456 nssCryptokiObject *object, | |
457 PRStatus *status) | |
458 { | |
459 static const CK_ATTRIBUTE_TYPE certAttr[] = { | |
460 CKA_CLASS, | |
461 CKA_TOKEN, | |
462 CKA_LABEL, | |
463 CKA_CERTIFICATE_TYPE, | |
464 CKA_ID, | |
465 CKA_VALUE, | |
466 CKA_ISSUER, | |
467 CKA_SERIAL_NUMBER, | |
468 CKA_SUBJECT, | |
469 CKA_NETSCAPE_EMAIL | |
470 }; | |
471 static const PRUint32 numCertAttr = sizeof(certAttr) / sizeof(certAttr[0]); | |
472 return create_object(object, certAttr, numCertAttr, status); | |
473 } | |
474 | |
475 static nssCryptokiObjectAndAttributes * | |
476 create_trust( | |
477 nssCryptokiObject *object, | |
478 PRStatus *status) | |
479 { | |
480 static const CK_ATTRIBUTE_TYPE trustAttr[] = { | |
481 CKA_CLASS, | |
482 CKA_TOKEN, | |
483 CKA_LABEL, | |
484 CKA_CERT_SHA1_HASH, | |
485 CKA_CERT_MD5_HASH, | |
486 CKA_ISSUER, | |
487 CKA_SUBJECT, | |
488 CKA_TRUST_SERVER_AUTH, | |
489 CKA_TRUST_CLIENT_AUTH, | |
490 CKA_TRUST_EMAIL_PROTECTION, | |
491 CKA_TRUST_CODE_SIGNING | |
492 }; | |
493 static const PRUint32 numTrustAttr = sizeof(trustAttr) / sizeof(trustAttr[0]
); | |
494 return create_object(object, trustAttr, numTrustAttr, status); | |
495 } | |
496 | |
497 static nssCryptokiObjectAndAttributes * | |
498 create_crl( | |
499 nssCryptokiObject *object, | |
500 PRStatus *status) | |
501 { | |
502 static const CK_ATTRIBUTE_TYPE crlAttr[] = { | |
503 CKA_CLASS, | |
504 CKA_TOKEN, | |
505 CKA_LABEL, | |
506 CKA_VALUE, | |
507 CKA_SUBJECT, | |
508 CKA_NETSCAPE_KRL, | |
509 CKA_NETSCAPE_URL | |
510 }; | |
511 static const PRUint32 numCRLAttr = sizeof(crlAttr) / sizeof(crlAttr[0]); | |
512 return create_object(object, crlAttr, numCRLAttr, status); | |
513 } | |
514 | |
515 /* Dispatch to the create function for the object type */ | |
516 static nssCryptokiObjectAndAttributes * | |
517 create_object_of_type( | |
518 nssCryptokiObject *object, | |
519 PRUint32 objectType, | |
520 PRStatus *status) | |
521 { | |
522 if (objectType == cachedCerts) { | |
523 return create_cert(object, status); | |
524 } | |
525 if (objectType == cachedTrust) { | |
526 return create_trust(object, status); | |
527 } | |
528 if (objectType == cachedCRLs) { | |
529 return create_crl(object, status); | |
530 } | |
531 return (nssCryptokiObjectAndAttributes *)NULL; | |
532 } | |
533 | |
534 static PRStatus | |
535 get_token_objects_for_cache( | |
536 nssTokenObjectCache *cache, | |
537 PRUint32 objectType, | |
538 CK_OBJECT_CLASS objclass) | |
539 { | |
540 PRStatus status; | |
541 nssCryptokiObject **objects; | |
542 PRBool *doIt = &cache->doObjectType[objectType]; | |
543 PRUint32 i, numObjects; | |
544 | |
545 if (!search_for_objects(cache) || | |
546 cache->searchedObjectType[objectType] || | |
547 !cache->doObjectType[objectType]) { | |
548 /* Either there was a state change that prevents a search | |
549 * (token logged out), or the search was already done, | |
550 * or objects of this type are not being cached. | |
551 */ | |
552 return PR_SUCCESS; | |
553 } | |
554 objects = nssToken_FindObjects(cache->token, NULL, objclass, | |
555 nssTokenSearchType_TokenForced, | |
556 MAX_LOCAL_CACHE_OBJECTS, &status); | |
557 if (status != PR_SUCCESS) { | |
558 return status; | |
559 } | |
560 cache->objects[objectType] = create_object_array(objects, | |
561 doIt, | |
562 &numObjects, | |
563 &status); | |
564 if (status != PR_SUCCESS) { | |
565 nss_ZFreeIf(objects); | |
566 return status; | |
567 } | |
568 for (i = 0; i < numObjects; i++) { | |
569 cache->objects[objectType][i] = create_object_of_type(objects[i], | |
570 objectType, | |
571 &status); | |
572 if (status != PR_SUCCESS) { | |
573 break; | |
574 } | |
575 } | |
576 if (status == PR_SUCCESS) { | |
577 nss_ZFreeIf(objects); | |
578 } else { | |
579 PRUint32 j; | |
580 for (j = 0; j < i; j++) { | |
581 /* sigh */ | |
582 nssToken_AddRef(cache->objects[objectType][j]->object->token); | |
583 nssArena_Destroy(cache->objects[objectType][j]->arena); | |
584 } | |
585 nss_ZFreeIf(cache->objects[objectType]); | |
586 cache->objects[objectType] = NULL; | |
587 nssCryptokiObjectArray_Destroy(objects); | |
588 } | |
589 cache->searchedObjectType[objectType] = PR_TRUE; | |
590 return status; | |
591 } | |
592 | |
593 static CK_ATTRIBUTE_PTR | |
594 find_attribute_in_object( | |
595 nssCryptokiObjectAndAttributes *obj, | |
596 CK_ATTRIBUTE_TYPE attrType) | |
597 { | |
598 PRUint32 j; | |
599 for (j = 0; j < obj->numAttributes; j++) { | |
600 if (attrType == obj->attributes[j].type) { | |
601 return &obj->attributes[j]; | |
602 } | |
603 } | |
604 return (CK_ATTRIBUTE_PTR)NULL; | |
605 } | |
606 | |
607 /* Find all objects in the array that match the supplied template */ | |
608 static nssCryptokiObject ** | |
609 find_objects_in_array( | |
610 nssCryptokiObjectAndAttributes **objArray, | |
611 CK_ATTRIBUTE_PTR ot, | |
612 CK_ULONG otlen, | |
613 PRUint32 maximumOpt) | |
614 { | |
615 PRIntn oi = 0; | |
616 PRUint32 i; | |
617 NSSArena *arena; | |
618 PRUint32 size = 8; | |
619 PRUint32 numMatches = 0; | |
620 nssCryptokiObject **objects = NULL; | |
621 nssCryptokiObjectAndAttributes **matches = NULL; | |
622 CK_ATTRIBUTE_PTR attr; | |
623 | |
624 if (!objArray) { | |
625 return (nssCryptokiObject **)NULL; | |
626 } | |
627 arena = nssArena_Create(); | |
628 if (!arena) { | |
629 return (nssCryptokiObject **)NULL; | |
630 } | |
631 matches = nss_ZNEWARRAY(arena, nssCryptokiObjectAndAttributes *, size); | |
632 if (!matches) { | |
633 goto loser; | |
634 } | |
635 if (maximumOpt == 0) | |
636 maximumOpt = ~0; | |
637 /* loop over the cached objects */ | |
638 for (; *objArray && numMatches < maximumOpt; objArray++) { | |
639 nssCryptokiObjectAndAttributes *obj = *objArray; | |
640 /* loop over the test template */ | |
641 for (i = 0; i < otlen; i++) { | |
642 /* see if the object has the attribute */ | |
643 attr = find_attribute_in_object(obj, ot[i].type); | |
644 if (!attr) { | |
645 /* nope, match failed */ | |
646 break; | |
647 } | |
648 /* compare the attribute against the test value */ | |
649 if (ot[i].ulValueLen != attr->ulValueLen || | |
650 !nsslibc_memequal(ot[i].pValue, | |
651 attr->pValue, | |
652 attr->ulValueLen, NULL)) { | |
653 /* nope, match failed */ | |
654 break; | |
655 } | |
656 } | |
657 if (i == otlen) { | |
658 /* all of the attributes in the test template were found | |
659 * in the object's template, and they all matched | |
660 */ | |
661 matches[numMatches++] = obj; | |
662 if (numMatches == size) { | |
663 size *= 2; | |
664 matches = nss_ZREALLOCARRAY(matches, | |
665 nssCryptokiObjectAndAttributes *, | |
666 size); | |
667 if (!matches) { | |
668 goto loser; | |
669 } | |
670 } | |
671 } | |
672 } | |
673 if (numMatches > 0) { | |
674 objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numMatches + 1); | |
675 if (!objects) { | |
676 goto loser; | |
677 } | |
678 for (oi = 0; oi < (PRIntn)numMatches; oi++) { | |
679 objects[oi] = nssCryptokiObject_Clone(matches[oi]->object); | |
680 if (!objects[oi]) { | |
681 goto loser; | |
682 } | |
683 } | |
684 } | |
685 nssArena_Destroy(arena); | |
686 return objects; | |
687 loser: | |
688 nssCryptokiObjectArray_Destroy(objects); | |
689 nssArena_Destroy(arena); | |
690 return (nssCryptokiObject **)NULL; | |
691 } | |
692 | |
693 NSS_IMPLEMENT nssCryptokiObject ** | |
694 nssTokenObjectCache_FindObjectsByTemplate( | |
695 nssTokenObjectCache *cache, | |
696 CK_OBJECT_CLASS objclass, | |
697 CK_ATTRIBUTE_PTR otemplate, | |
698 CK_ULONG otlen, | |
699 PRUint32 maximumOpt, | |
700 PRStatus *statusOpt) | |
701 { | |
702 PRStatus status = PR_FAILURE; | |
703 nssCryptokiObject **rvObjects = NULL; | |
704 PRUint32 objectType; | |
705 if (!token_is_present(cache)) { | |
706 status = PR_SUCCESS; | |
707 goto finish; | |
708 } | |
709 switch (objclass) { | |
710 case CKO_CERTIFICATE: | |
711 objectType = cachedCerts; | |
712 break; | |
713 case CKO_NETSCAPE_TRUST: | |
714 objectType = cachedTrust; | |
715 break; | |
716 case CKO_NETSCAPE_CRL: | |
717 objectType = cachedCRLs; | |
718 break; | |
719 default: | |
720 goto finish; | |
721 } | |
722 PZ_Lock(cache->lock); | |
723 if (cache->doObjectType[objectType]) { | |
724 status = get_token_objects_for_cache(cache, objectType, objclass); | |
725 if (status == PR_SUCCESS) { | |
726 rvObjects = find_objects_in_array(cache->objects[objectType], | |
727 otemplate, otlen, maximumOpt); | |
728 } | |
729 } | |
730 PZ_Unlock(cache->lock); | |
731 finish: | |
732 if (statusOpt) { | |
733 *statusOpt = status; | |
734 } | |
735 return rvObjects; | |
736 } | |
737 | |
738 static PRBool | |
739 cache_available_for_object_type( | |
740 nssTokenObjectCache *cache, | |
741 PRUint32 objectType) | |
742 { | |
743 if (!cache->doObjectType[objectType]) { | |
744 /* not caching this object kind */ | |
745 return PR_FALSE; | |
746 } | |
747 if (!cache->searchedObjectType[objectType]) { | |
748 /* objects are not cached yet */ | |
749 return PR_FALSE; | |
750 } | |
751 if (!search_for_objects(cache)) { | |
752 /* not logged in */ | |
753 return PR_FALSE; | |
754 } | |
755 return PR_TRUE; | |
756 } | |
757 | |
758 NSS_IMPLEMENT PRStatus | |
759 nssTokenObjectCache_GetObjectAttributes( | |
760 nssTokenObjectCache *cache, | |
761 NSSArena *arenaOpt, | |
762 nssCryptokiObject *object, | |
763 CK_OBJECT_CLASS objclass, | |
764 CK_ATTRIBUTE_PTR atemplate, | |
765 CK_ULONG atlen) | |
766 { | |
767 PRUint32 i, j; | |
768 NSSArena *arena = NULL; | |
769 nssArenaMark *mark = NULL; | |
770 nssCryptokiObjectAndAttributes *cachedOA = NULL; | |
771 nssCryptokiObjectAndAttributes **oa = NULL; | |
772 PRUint32 objectType; | |
773 if (!token_is_present(cache)) { | |
774 return PR_FAILURE; | |
775 } | |
776 PZ_Lock(cache->lock); | |
777 switch (objclass) { | |
778 case CKO_CERTIFICATE: | |
779 objectType = cachedCerts; | |
780 break; | |
781 case CKO_NETSCAPE_TRUST: | |
782 objectType = cachedTrust; | |
783 break; | |
784 case CKO_NETSCAPE_CRL: | |
785 objectType = cachedCRLs; | |
786 break; | |
787 default: | |
788 goto loser; | |
789 } | |
790 if (!cache_available_for_object_type(cache, objectType)) { | |
791 goto loser; | |
792 } | |
793 oa = cache->objects[objectType]; | |
794 if (!oa) { | |
795 goto loser; | |
796 } | |
797 for (; *oa; oa++) { | |
798 if (nssCryptokiObject_Equal((*oa)->object, object)) { | |
799 cachedOA = *oa; | |
800 break; | |
801 } | |
802 } | |
803 if (!cachedOA) { | |
804 goto loser; /* don't have this object */ | |
805 } | |
806 if (arenaOpt) { | |
807 arena = arenaOpt; | |
808 mark = nssArena_Mark(arena); | |
809 } | |
810 for (i = 0; i < atlen; i++) { | |
811 for (j = 0; j < cachedOA->numAttributes; j++) { | |
812 if (atemplate[i].type == cachedOA->attributes[j].type) { | |
813 CK_ATTRIBUTE_PTR attr = &cachedOA->attributes[j]; | |
814 if (cachedOA->attributes[j].ulValueLen == 0 || | |
815 cachedOA->attributes[j].ulValueLen == (CK_ULONG)-1) { | |
816 break; /* invalid attribute */ | |
817 } | |
818 if (atemplate[i].ulValueLen > 0) { | |
819 if (atemplate[i].pValue == NULL || | |
820 atemplate[i].ulValueLen < attr->ulValueLen) { | |
821 goto loser; | |
822 } | |
823 } else { | |
824 atemplate[i].pValue = nss_ZAlloc(arena, attr->ulValueLen); | |
825 if (!atemplate[i].pValue) { | |
826 goto loser; | |
827 } | |
828 } | |
829 nsslibc_memcpy(atemplate[i].pValue, | |
830 attr->pValue, attr->ulValueLen); | |
831 atemplate[i].ulValueLen = attr->ulValueLen; | |
832 break; | |
833 } | |
834 } | |
835 if (j == cachedOA->numAttributes) { | |
836 atemplate[i].ulValueLen = (CK_ULONG)-1; | |
837 } | |
838 } | |
839 PZ_Unlock(cache->lock); | |
840 if (mark) { | |
841 nssArena_Unmark(arena, mark); | |
842 } | |
843 return PR_SUCCESS; | |
844 loser: | |
845 PZ_Unlock(cache->lock); | |
846 if (mark) { | |
847 nssArena_Release(arena, mark); | |
848 } | |
849 return PR_FAILURE; | |
850 } | |
851 | |
852 NSS_IMPLEMENT PRStatus | |
853 nssTokenObjectCache_ImportObject( | |
854 nssTokenObjectCache *cache, | |
855 nssCryptokiObject *object, | |
856 CK_OBJECT_CLASS objclass, | |
857 CK_ATTRIBUTE_PTR ot, | |
858 CK_ULONG otlen) | |
859 { | |
860 PRStatus status = PR_SUCCESS; | |
861 PRUint32 count; | |
862 nssCryptokiObjectAndAttributes **oa, ***otype; | |
863 PRUint32 objectType; | |
864 PRBool haveIt = PR_FALSE; | |
865 | |
866 if (!token_is_present(cache)) { | |
867 return PR_SUCCESS; /* cache not active, ignored */ | |
868 } | |
869 PZ_Lock(cache->lock); | |
870 switch (objclass) { | |
871 case CKO_CERTIFICATE: | |
872 objectType = cachedCerts; | |
873 break; | |
874 case CKO_NETSCAPE_TRUST: | |
875 objectType = cachedTrust; | |
876 break; | |
877 case CKO_NETSCAPE_CRL: | |
878 objectType = cachedCRLs; | |
879 break; | |
880 default: | |
881 PZ_Unlock(cache->lock); | |
882 return PR_SUCCESS; /* don't need to import it here */ | |
883 } | |
884 if (!cache_available_for_object_type(cache, objectType)) { | |
885 PZ_Unlock(cache->lock); | |
886 return PR_SUCCESS; /* cache not active, ignored */ | |
887 } | |
888 count = 0; | |
889 otype = &cache->objects[objectType]; /* index into array of types */ | |
890 oa = *otype; /* the array of objects for this type *
/ | |
891 while (oa && *oa) { | |
892 if (nssCryptokiObject_Equal((*oa)->object, object)) { | |
893 haveIt = PR_TRUE; | |
894 break; | |
895 } | |
896 count++; | |
897 oa++; | |
898 } | |
899 if (haveIt) { | |
900 /* Destroy the old entry */ | |
901 (*oa)->object->token = NULL; | |
902 nssCryptokiObject_Destroy((*oa)->object); | |
903 nssArena_Destroy((*oa)->arena); | |
904 } else { | |
905 /* Create space for a new entry */ | |
906 if (count > 0) { | |
907 *otype = nss_ZREALLOCARRAY(*otype, | |
908 nssCryptokiObjectAndAttributes *, | |
909 count + 2); | |
910 } else { | |
911 *otype = nss_ZNEWARRAY(NULL, nssCryptokiObjectAndAttributes *, 2); | |
912 } | |
913 } | |
914 if (*otype) { | |
915 nssCryptokiObject *copyObject = nssCryptokiObject_Clone(object); | |
916 (*otype)[count] = create_object_of_type(copyObject, objectType, | |
917 &status); | |
918 } else { | |
919 status = PR_FAILURE; | |
920 } | |
921 PZ_Unlock(cache->lock); | |
922 return status; | |
923 } | |
924 | |
925 NSS_IMPLEMENT void | |
926 nssTokenObjectCache_RemoveObject( | |
927 nssTokenObjectCache *cache, | |
928 nssCryptokiObject *object) | |
929 { | |
930 PRUint32 oType; | |
931 nssCryptokiObjectAndAttributes **oa, **swp = NULL; | |
932 if (!token_is_present(cache)) { | |
933 return; | |
934 } | |
935 PZ_Lock(cache->lock); | |
936 for (oType = 0; oType < 3; oType++) { | |
937 if (!cache_available_for_object_type(cache, oType) || | |
938 !cache->objects[oType]) { | |
939 continue; | |
940 } | |
941 for (oa = cache->objects[oType]; *oa; oa++) { | |
942 if (nssCryptokiObject_Equal((*oa)->object, object)) { | |
943 swp = oa; /* the entry to remove */ | |
944 while (oa[1]) | |
945 oa++; /* go to the tail */ | |
946 (*swp)->object->token = NULL; | |
947 nssCryptokiObject_Destroy((*swp)->object); | |
948 nssArena_Destroy((*swp)->arena); /* destroy it */ | |
949 *swp = *oa; /* swap the last with the remov
ed */ | |
950 *oa = NULL; /* null-terminate the array */ | |
951 break; | |
952 } | |
953 } | |
954 if (swp) { | |
955 break; | |
956 } | |
957 } | |
958 if ((oType < 3) && | |
959 cache->objects[oType] && cache->objects[oType][0] == NULL) { | |
960 nss_ZFreeIf(cache->objects[oType]); /* no entries remaining */ | |
961 cache->objects[oType] = NULL; | |
962 } | |
963 PZ_Unlock(cache->lock); | |
964 } | |
965 | |
966 /* These two hash algorithms are presently sufficient. | |
967 ** They are used for fingerprints of certs which are stored as the | |
968 ** CKA_CERT_SHA1_HASH and CKA_CERT_MD5_HASH attributes. | |
969 ** We don't need to add SHAxxx to these now. | |
970 */ | |
971 /* XXX of course this doesn't belong here */ | |
972 NSS_IMPLEMENT NSSAlgorithmAndParameters * | |
973 NSSAlgorithmAndParameters_CreateSHA1Digest( | |
974 NSSArena *arenaOpt) | |
975 { | |
976 NSSAlgorithmAndParameters *rvAP = NULL; | |
977 rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters); | |
978 if (rvAP) { | |
979 rvAP->mechanism.mechanism = CKM_SHA_1; | |
980 rvAP->mechanism.pParameter = NULL; | |
981 rvAP->mechanism.ulParameterLen = 0; | |
982 } | |
983 return rvAP; | |
984 } | |
985 | |
986 NSS_IMPLEMENT NSSAlgorithmAndParameters * | |
987 NSSAlgorithmAndParameters_CreateMD5Digest( | |
988 NSSArena *arenaOpt) | |
989 { | |
990 NSSAlgorithmAndParameters *rvAP = NULL; | |
991 rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters); | |
992 if (rvAP) { | |
993 rvAP->mechanism.mechanism = CKM_MD5; | |
994 rvAP->mechanism.pParameter = NULL; | |
995 rvAP->mechanism.ulParameterLen = 0; | |
996 } | |
997 return rvAP; | |
998 } | |
OLD | NEW |