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