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: pkistore.c,v $ $Revision: 1.36 $ $D
ate: 2012/05/17 21:39:40 $"; | |
7 #endif /* DEBUG */ | |
8 | |
9 #ifndef PKIM_H | |
10 #include "pkim.h" | |
11 #endif /* PKIM_H */ | |
12 | |
13 #ifndef PKI_H | |
14 #include "pki.h" | |
15 #endif /* PKI_H */ | |
16 | |
17 #ifndef NSSPKI_H | |
18 #include "nsspki.h" | |
19 #endif /* NSSPKI_H */ | |
20 | |
21 #ifndef BASE_H | |
22 #include "base.h" | |
23 #endif /* BASE_H */ | |
24 | |
25 #ifndef PKISTORE_H | |
26 #include "pkistore.h" | |
27 #endif /* PKISTORE_H */ | |
28 | |
29 #include "cert.h" | |
30 | |
31 #include "prbit.h" | |
32 | |
33 /* | |
34 * Certificate Store | |
35 * | |
36 * This differs from the cache in that it is a true storage facility. Items | |
37 * stay in until they are explicitly removed. It is only used by crypto | |
38 * contexts at this time, but may be more generally useful... | |
39 * | |
40 */ | |
41 | |
42 struct nssCertificateStoreStr | |
43 { | |
44 PRBool i_alloced_arena; | |
45 NSSArena *arena; | |
46 PZLock *lock; | |
47 nssHash *subject; | |
48 nssHash *issuer_and_serial; | |
49 }; | |
50 | |
51 typedef struct certificate_hash_entry_str certificate_hash_entry; | |
52 | |
53 struct certificate_hash_entry_str | |
54 { | |
55 NSSCertificate *cert; | |
56 NSSTrust *trust; | |
57 nssSMIMEProfile *profile; | |
58 }; | |
59 | |
60 /* forward static declarations */ | |
61 static NSSCertificate * | |
62 nssCertStore_FindCertByIssuerAndSerialNumberLocked ( | |
63 nssCertificateStore *store, | |
64 NSSDER *issuer, | |
65 NSSDER *serial | |
66 ); | |
67 | |
68 NSS_IMPLEMENT nssCertificateStore * | |
69 nssCertificateStore_Create ( | |
70 NSSArena *arenaOpt | |
71 ) | |
72 { | |
73 NSSArena *arena; | |
74 nssCertificateStore *store; | |
75 PRBool i_alloced_arena; | |
76 if (arenaOpt) { | |
77 arena = arenaOpt; | |
78 i_alloced_arena = PR_FALSE; | |
79 } else { | |
80 arena = nssArena_Create(); | |
81 if (!arena) { | |
82 return NULL; | |
83 } | |
84 i_alloced_arena = PR_TRUE; | |
85 } | |
86 store = nss_ZNEW(arena, nssCertificateStore); | |
87 if (!store) { | |
88 goto loser; | |
89 } | |
90 store->lock = PZ_NewLock(nssILockOther); | |
91 if (!store->lock) { | |
92 goto loser; | |
93 } | |
94 /* Create the issuer/serial --> {cert, trust, S/MIME profile } hash */ | |
95 store->issuer_and_serial = nssHash_CreateCertificate(arena, 0); | |
96 if (!store->issuer_and_serial) { | |
97 goto loser; | |
98 } | |
99 /* Create the subject DER --> subject list hash */ | |
100 store->subject = nssHash_CreateItem(arena, 0); | |
101 if (!store->subject) { | |
102 goto loser; | |
103 } | |
104 store->arena = arena; | |
105 store->i_alloced_arena = i_alloced_arena; | |
106 return store; | |
107 loser: | |
108 if (store) { | |
109 if (store->lock) { | |
110 PZ_DestroyLock(store->lock); | |
111 } | |
112 if (store->issuer_and_serial) { | |
113 nssHash_Destroy(store->issuer_and_serial); | |
114 } | |
115 if (store->subject) { | |
116 nssHash_Destroy(store->subject); | |
117 } | |
118 } | |
119 if (i_alloced_arena) { | |
120 nssArena_Destroy(arena); | |
121 } | |
122 return NULL; | |
123 } | |
124 | |
125 extern const NSSError NSS_ERROR_BUSY; | |
126 | |
127 NSS_IMPLEMENT PRStatus | |
128 nssCertificateStore_Destroy ( | |
129 nssCertificateStore *store | |
130 ) | |
131 { | |
132 if (nssHash_Count(store->issuer_and_serial) > 0) { | |
133 nss_SetError(NSS_ERROR_BUSY); | |
134 return PR_FAILURE; | |
135 } | |
136 PZ_DestroyLock(store->lock); | |
137 nssHash_Destroy(store->issuer_and_serial); | |
138 nssHash_Destroy(store->subject); | |
139 if (store->i_alloced_arena) { | |
140 nssArena_Destroy(store->arena); | |
141 } else { | |
142 nss_ZFreeIf(store); | |
143 } | |
144 return PR_SUCCESS; | |
145 } | |
146 | |
147 static PRStatus | |
148 add_certificate_entry ( | |
149 nssCertificateStore *store, | |
150 NSSCertificate *cert | |
151 ) | |
152 { | |
153 PRStatus nssrv; | |
154 certificate_hash_entry *entry; | |
155 entry = nss_ZNEW(cert->object.arena, certificate_hash_entry); | |
156 if (!entry) { | |
157 return PR_FAILURE; | |
158 } | |
159 entry->cert = cert; | |
160 nssrv = nssHash_Add(store->issuer_and_serial, cert, entry); | |
161 if (nssrv != PR_SUCCESS) { | |
162 nss_ZFreeIf(entry); | |
163 } | |
164 return nssrv; | |
165 } | |
166 | |
167 static PRStatus | |
168 add_subject_entry ( | |
169 nssCertificateStore *store, | |
170 NSSCertificate *cert | |
171 ) | |
172 { | |
173 PRStatus nssrv; | |
174 nssList *subjectList; | |
175 subjectList = (nssList *)nssHash_Lookup(store->subject, &cert->subject); | |
176 if (subjectList) { | |
177 /* The subject is already in, add this cert to the list */ | |
178 nssrv = nssList_AddUnique(subjectList, cert); | |
179 } else { | |
180 /* Create a new subject list for the subject */ | |
181 subjectList = nssList_Create(NULL, PR_FALSE); | |
182 if (!subjectList) { | |
183 return PR_FAILURE; | |
184 } | |
185 nssList_SetSortFunction(subjectList, nssCertificate_SubjectListSort); | |
186 /* Add the cert entry to this list of subjects */ | |
187 nssrv = nssList_Add(subjectList, cert); | |
188 if (nssrv != PR_SUCCESS) { | |
189 return nssrv; | |
190 } | |
191 /* Add the subject list to the cache */ | |
192 nssrv = nssHash_Add(store->subject, &cert->subject, subjectList); | |
193 } | |
194 return nssrv; | |
195 } | |
196 | |
197 /* declared below */ | |
198 static void | |
199 remove_certificate_entry ( | |
200 nssCertificateStore *store, | |
201 NSSCertificate *cert | |
202 ); | |
203 | |
204 /* Caller must hold store->lock */ | |
205 static PRStatus | |
206 nssCertificateStore_AddLocked ( | |
207 nssCertificateStore *store, | |
208 NSSCertificate *cert | |
209 ) | |
210 { | |
211 PRStatus nssrv = add_certificate_entry(store, cert); | |
212 if (nssrv == PR_SUCCESS) { | |
213 nssrv = add_subject_entry(store, cert); | |
214 if (nssrv == PR_FAILURE) { | |
215 remove_certificate_entry(store, cert); | |
216 } | |
217 } | |
218 return nssrv; | |
219 } | |
220 | |
221 | |
222 NSS_IMPLEMENT NSSCertificate * | |
223 nssCertificateStore_FindOrAdd ( | |
224 nssCertificateStore *store, | |
225 NSSCertificate *c | |
226 ) | |
227 { | |
228 PRStatus nssrv; | |
229 NSSCertificate *rvCert = NULL; | |
230 | |
231 PZ_Lock(store->lock); | |
232 rvCert = nssCertStore_FindCertByIssuerAndSerialNumberLocked( | |
233 store, &c->issuer, &c->serial); | |
234 if (!rvCert) { | |
235 nssrv = nssCertificateStore_AddLocked(store, c); | |
236 if (PR_SUCCESS == nssrv) { | |
237 rvCert = nssCertificate_AddRef(c); | |
238 } | |
239 } | |
240 PZ_Unlock(store->lock); | |
241 return rvCert; | |
242 } | |
243 | |
244 static void | |
245 remove_certificate_entry ( | |
246 nssCertificateStore *store, | |
247 NSSCertificate *cert | |
248 ) | |
249 { | |
250 certificate_hash_entry *entry; | |
251 entry = (certificate_hash_entry *) | |
252 nssHash_Lookup(store->issuer_and_serial, cert); | |
253 if (entry) { | |
254 nssHash_Remove(store->issuer_and_serial, cert); | |
255 if (entry->trust) { | |
256 nssTrust_Destroy(entry->trust); | |
257 } | |
258 if (entry->profile) { | |
259 nssSMIMEProfile_Destroy(entry->profile); | |
260 } | |
261 nss_ZFreeIf(entry); | |
262 } | |
263 } | |
264 | |
265 static void | |
266 remove_subject_entry ( | |
267 nssCertificateStore *store, | |
268 NSSCertificate *cert | |
269 ) | |
270 { | |
271 nssList *subjectList; | |
272 /* Get the subject list for the cert's subject */ | |
273 subjectList = (nssList *)nssHash_Lookup(store->subject, &cert->subject); | |
274 if (subjectList) { | |
275 /* Remove the cert from the subject hash */ | |
276 nssList_Remove(subjectList, cert); | |
277 nssHash_Remove(store->subject, &cert->subject); | |
278 if (nssList_Count(subjectList) == 0) { | |
279 nssList_Destroy(subjectList); | |
280 } else { | |
281 /* The cert being released may have keyed the subject entry. | |
282 * Since there are still subject certs around, get another and | |
283 * rekey the entry just in case. | |
284 */ | |
285 NSSCertificate *subjectCert; | |
286 (void)nssList_GetArray(subjectList, (void **)&subjectCert, 1); | |
287 nssHash_Add(store->subject, &subjectCert->subject, subjectList); | |
288 } | |
289 } | |
290 } | |
291 | |
292 NSS_IMPLEMENT void | |
293 nssCertificateStore_RemoveCertLOCKED ( | |
294 nssCertificateStore *store, | |
295 NSSCertificate *cert | |
296 ) | |
297 { | |
298 certificate_hash_entry *entry; | |
299 entry = (certificate_hash_entry *) | |
300 nssHash_Lookup(store->issuer_and_serial, cert); | |
301 if (entry && entry->cert == cert) { | |
302 remove_certificate_entry(store, cert); | |
303 remove_subject_entry(store, cert); | |
304 } | |
305 } | |
306 | |
307 NSS_IMPLEMENT void | |
308 nssCertificateStore_Lock ( | |
309 nssCertificateStore *store, nssCertificateStoreTrace* out | |
310 ) | |
311 { | |
312 #ifdef DEBUG | |
313 PORT_Assert(out); | |
314 out->store = store; | |
315 out->lock = store->lock; | |
316 out->locked = PR_TRUE; | |
317 PZ_Lock(out->lock); | |
318 #else | |
319 PZ_Lock(store->lock); | |
320 #endif | |
321 } | |
322 | |
323 NSS_IMPLEMENT void | |
324 nssCertificateStore_Unlock ( | |
325 nssCertificateStore *store, const nssCertificateStoreTrace* in, | |
326 nssCertificateStoreTrace* out | |
327 ) | |
328 { | |
329 #ifdef DEBUG | |
330 PORT_Assert(in); | |
331 PORT_Assert(out); | |
332 out->store = store; | |
333 out->lock = store->lock; | |
334 PORT_Assert(!out->locked); | |
335 out->unlocked = PR_TRUE; | |
336 | |
337 PORT_Assert(in->store == out->store); | |
338 PORT_Assert(in->lock == out->lock); | |
339 PORT_Assert(in->locked); | |
340 PORT_Assert(!in->unlocked); | |
341 | |
342 PZ_Unlock(out->lock); | |
343 #else | |
344 PZ_Unlock(store->lock); | |
345 #endif | |
346 } | |
347 | |
348 static NSSCertificate ** | |
349 get_array_from_list ( | |
350 nssList *certList, | |
351 NSSCertificate *rvOpt[], | |
352 PRUint32 maximumOpt, | |
353 NSSArena *arenaOpt | |
354 ) | |
355 { | |
356 PRUint32 count; | |
357 NSSCertificate **rvArray = NULL; | |
358 count = nssList_Count(certList); | |
359 if (count == 0) { | |
360 return NULL; | |
361 } | |
362 if (maximumOpt > 0) { | |
363 count = PR_MIN(maximumOpt, count); | |
364 } | |
365 if (rvOpt) { | |
366 nssList_GetArray(certList, (void **)rvOpt, count); | |
367 } else { | |
368 rvArray = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, count + 1); | |
369 if (rvArray) { | |
370 nssList_GetArray(certList, (void **)rvArray, count); | |
371 } | |
372 } | |
373 return rvArray; | |
374 } | |
375 | |
376 NSS_IMPLEMENT NSSCertificate ** | |
377 nssCertificateStore_FindCertificatesBySubject ( | |
378 nssCertificateStore *store, | |
379 NSSDER *subject, | |
380 NSSCertificate *rvOpt[], | |
381 PRUint32 maximumOpt, | |
382 NSSArena *arenaOpt | |
383 ) | |
384 { | |
385 NSSCertificate **rvArray = NULL; | |
386 nssList *subjectList; | |
387 PZ_Lock(store->lock); | |
388 subjectList = (nssList *)nssHash_Lookup(store->subject, subject); | |
389 if (subjectList) { | |
390 nssCertificateList_AddReferences(subjectList); | |
391 rvArray = get_array_from_list(subjectList, | |
392 rvOpt, maximumOpt, arenaOpt); | |
393 } | |
394 PZ_Unlock(store->lock); | |
395 return rvArray; | |
396 } | |
397 | |
398 /* Because only subject indexing is implemented, all other lookups require | |
399 * full traversal (unfortunately, PLHashTable doesn't allow you to exit | |
400 * early from the enumeration). The assumptions are that 1) lookups by | |
401 * fields other than subject will be rare, and 2) the hash will not have | |
402 * a large number of entries. These assumptions will be tested. | |
403 * | |
404 * XXX | |
405 * For NSS 3.4, it is worth consideration to do all forms of indexing, | |
406 * because the only crypto context is global and persistent. | |
407 */ | |
408 | |
409 struct nickname_template_str | |
410 { | |
411 NSSUTF8 *nickname; | |
412 nssList *subjectList; | |
413 }; | |
414 | |
415 static void match_nickname(const void *k, void *v, void *a) | |
416 { | |
417 PRStatus nssrv; | |
418 NSSCertificate *c; | |
419 NSSUTF8 *nickname; | |
420 nssList *subjectList = (nssList *)v; | |
421 struct nickname_template_str *nt = (struct nickname_template_str *)a; | |
422 nssrv = nssList_GetArray(subjectList, (void **)&c, 1); | |
423 nickname = nssCertificate_GetNickname(c, NULL); | |
424 if (nssrv == PR_SUCCESS && nickname && | |
425 nssUTF8_Equal(nickname, nt->nickname, &nssrv)) | |
426 { | |
427 nt->subjectList = subjectList; | |
428 } | |
429 nss_ZFreeIf(nickname); | |
430 } | |
431 | |
432 /* | |
433 * Find all cached certs with this label. | |
434 */ | |
435 NSS_IMPLEMENT NSSCertificate ** | |
436 nssCertificateStore_FindCertificatesByNickname ( | |
437 nssCertificateStore *store, | |
438 const NSSUTF8 *nickname, | |
439 NSSCertificate *rvOpt[], | |
440 PRUint32 maximumOpt, | |
441 NSSArena *arenaOpt | |
442 ) | |
443 { | |
444 NSSCertificate **rvArray = NULL; | |
445 struct nickname_template_str nt; | |
446 nt.nickname = (char*) nickname; | |
447 nt.subjectList = NULL; | |
448 PZ_Lock(store->lock); | |
449 nssHash_Iterate(store->subject, match_nickname, &nt); | |
450 if (nt.subjectList) { | |
451 nssCertificateList_AddReferences(nt.subjectList); | |
452 rvArray = get_array_from_list(nt.subjectList, | |
453 rvOpt, maximumOpt, arenaOpt); | |
454 } | |
455 PZ_Unlock(store->lock); | |
456 return rvArray; | |
457 } | |
458 | |
459 struct email_template_str | |
460 { | |
461 NSSASCII7 *email; | |
462 nssList *emailList; | |
463 }; | |
464 | |
465 static void match_email(const void *k, void *v, void *a) | |
466 { | |
467 PRStatus nssrv; | |
468 NSSCertificate *c; | |
469 nssList *subjectList = (nssList *)v; | |
470 struct email_template_str *et = (struct email_template_str *)a; | |
471 nssrv = nssList_GetArray(subjectList, (void **)&c, 1); | |
472 if (nssrv == PR_SUCCESS && | |
473 nssUTF8_Equal(c->email, et->email, &nssrv)) | |
474 { | |
475 nssListIterator *iter = nssList_CreateIterator(subjectList); | |
476 if (iter) { | |
477 for (c = (NSSCertificate *)nssListIterator_Start(iter); | |
478 c != (NSSCertificate *)NULL; | |
479 c = (NSSCertificate *)nssListIterator_Next(iter)) | |
480 { | |
481 nssList_Add(et->emailList, c); | |
482 } | |
483 nssListIterator_Finish(iter); | |
484 nssListIterator_Destroy(iter); | |
485 } | |
486 } | |
487 } | |
488 | |
489 /* | |
490 * Find all cached certs with this email address. | |
491 */ | |
492 NSS_IMPLEMENT NSSCertificate ** | |
493 nssCertificateStore_FindCertificatesByEmail ( | |
494 nssCertificateStore *store, | |
495 NSSASCII7 *email, | |
496 NSSCertificate *rvOpt[], | |
497 PRUint32 maximumOpt, | |
498 NSSArena *arenaOpt | |
499 ) | |
500 { | |
501 NSSCertificate **rvArray = NULL; | |
502 struct email_template_str et; | |
503 et.email = email; | |
504 et.emailList = nssList_Create(NULL, PR_FALSE); | |
505 if (!et.emailList) { | |
506 return NULL; | |
507 } | |
508 PZ_Lock(store->lock); | |
509 nssHash_Iterate(store->subject, match_email, &et); | |
510 if (et.emailList) { | |
511 /* get references before leaving the store's lock protection */ | |
512 nssCertificateList_AddReferences(et.emailList); | |
513 } | |
514 PZ_Unlock(store->lock); | |
515 if (et.emailList) { | |
516 rvArray = get_array_from_list(et.emailList, | |
517 rvOpt, maximumOpt, arenaOpt); | |
518 nssList_Destroy(et.emailList); | |
519 } | |
520 return rvArray; | |
521 } | |
522 | |
523 /* Caller holds store->lock */ | |
524 static NSSCertificate * | |
525 nssCertStore_FindCertByIssuerAndSerialNumberLocked ( | |
526 nssCertificateStore *store, | |
527 NSSDER *issuer, | |
528 NSSDER *serial | |
529 ) | |
530 { | |
531 certificate_hash_entry *entry; | |
532 NSSCertificate *rvCert = NULL; | |
533 NSSCertificate index; | |
534 | |
535 index.issuer = *issuer; | |
536 index.serial = *serial; | |
537 entry = (certificate_hash_entry *) | |
538 nssHash_Lookup(store->issuer_and_serial, &index); | |
539 if (entry) { | |
540 rvCert = nssCertificate_AddRef(entry->cert); | |
541 } | |
542 return rvCert; | |
543 } | |
544 | |
545 NSS_IMPLEMENT NSSCertificate * | |
546 nssCertificateStore_FindCertificateByIssuerAndSerialNumber ( | |
547 nssCertificateStore *store, | |
548 NSSDER *issuer, | |
549 NSSDER *serial | |
550 ) | |
551 { | |
552 NSSCertificate *rvCert = NULL; | |
553 | |
554 PZ_Lock(store->lock); | |
555 rvCert = nssCertStore_FindCertByIssuerAndSerialNumberLocked ( | |
556 store, issuer, serial); | |
557 PZ_Unlock(store->lock); | |
558 return rvCert; | |
559 } | |
560 | |
561 static PRStatus | |
562 issuer_and_serial_from_encoding ( | |
563 NSSBER *encoding, | |
564 NSSDER *issuer, | |
565 NSSDER *serial | |
566 ) | |
567 { | |
568 SECItem derCert, derIssuer, derSerial; | |
569 SECStatus secrv; | |
570 derCert.data = (unsigned char *)encoding->data; | |
571 derCert.len = encoding->size; | |
572 secrv = CERT_IssuerNameFromDERCert(&derCert, &derIssuer); | |
573 if (secrv != SECSuccess) { | |
574 return PR_FAILURE; | |
575 } | |
576 secrv = CERT_SerialNumberFromDERCert(&derCert, &derSerial); | |
577 if (secrv != SECSuccess) { | |
578 PORT_Free(derIssuer.data); | |
579 return PR_FAILURE; | |
580 } | |
581 issuer->data = derIssuer.data; | |
582 issuer->size = derIssuer.len; | |
583 serial->data = derSerial.data; | |
584 serial->size = derSerial.len; | |
585 return PR_SUCCESS; | |
586 } | |
587 | |
588 NSS_IMPLEMENT NSSCertificate * | |
589 nssCertificateStore_FindCertificateByEncodedCertificate ( | |
590 nssCertificateStore *store, | |
591 NSSDER *encoding | |
592 ) | |
593 { | |
594 PRStatus nssrv = PR_FAILURE; | |
595 NSSDER issuer, serial; | |
596 NSSCertificate *rvCert = NULL; | |
597 nssrv = issuer_and_serial_from_encoding(encoding, &issuer, &serial); | |
598 if (nssrv != PR_SUCCESS) { | |
599 return NULL; | |
600 } | |
601 rvCert = nssCertificateStore_FindCertificateByIssuerAndSerialNumber(store, | |
602 &issuer, | |
603 &serial); | |
604 PORT_Free(issuer.data); | |
605 PORT_Free(serial.data); | |
606 return rvCert; | |
607 } | |
608 | |
609 NSS_EXTERN PRStatus | |
610 nssCertificateStore_AddTrust ( | |
611 nssCertificateStore *store, | |
612 NSSTrust *trust | |
613 ) | |
614 { | |
615 NSSCertificate *cert; | |
616 certificate_hash_entry *entry; | |
617 cert = trust->certificate; | |
618 PZ_Lock(store->lock); | |
619 entry = (certificate_hash_entry *) | |
620 nssHash_Lookup(store->issuer_and_serial, cert); | |
621 if (entry) { | |
622 NSSTrust* newTrust = nssTrust_AddRef(trust); | |
623 if (entry->trust) { | |
624 nssTrust_Destroy(entry->trust); | |
625 } | |
626 entry->trust = newTrust; | |
627 } | |
628 PZ_Unlock(store->lock); | |
629 return (entry) ? PR_SUCCESS : PR_FAILURE; | |
630 } | |
631 | |
632 NSS_IMPLEMENT NSSTrust * | |
633 nssCertificateStore_FindTrustForCertificate ( | |
634 nssCertificateStore *store, | |
635 NSSCertificate *cert | |
636 ) | |
637 { | |
638 certificate_hash_entry *entry; | |
639 NSSTrust *rvTrust = NULL; | |
640 PZ_Lock(store->lock); | |
641 entry = (certificate_hash_entry *) | |
642 nssHash_Lookup(store->issuer_and_serial, cert); | |
643 if (entry && entry->trust) { | |
644 rvTrust = nssTrust_AddRef(entry->trust); | |
645 } | |
646 PZ_Unlock(store->lock); | |
647 return rvTrust; | |
648 } | |
649 | |
650 NSS_EXTERN PRStatus | |
651 nssCertificateStore_AddSMIMEProfile ( | |
652 nssCertificateStore *store, | |
653 nssSMIMEProfile *profile | |
654 ) | |
655 { | |
656 NSSCertificate *cert; | |
657 certificate_hash_entry *entry; | |
658 cert = profile->certificate; | |
659 PZ_Lock(store->lock); | |
660 entry = (certificate_hash_entry *) | |
661 nssHash_Lookup(store->issuer_and_serial, cert); | |
662 if (entry) { | |
663 nssSMIMEProfile* newProfile = nssSMIMEProfile_AddRef(profile); | |
664 if (entry->profile) { | |
665 nssSMIMEProfile_Destroy(entry->profile); | |
666 } | |
667 entry->profile = newProfile; | |
668 } | |
669 PZ_Unlock(store->lock); | |
670 return (entry) ? PR_SUCCESS : PR_FAILURE; | |
671 } | |
672 | |
673 NSS_IMPLEMENT nssSMIMEProfile * | |
674 nssCertificateStore_FindSMIMEProfileForCertificate ( | |
675 nssCertificateStore *store, | |
676 NSSCertificate *cert | |
677 ) | |
678 { | |
679 certificate_hash_entry *entry; | |
680 nssSMIMEProfile *rvProfile = NULL; | |
681 PZ_Lock(store->lock); | |
682 entry = (certificate_hash_entry *) | |
683 nssHash_Lookup(store->issuer_and_serial, cert); | |
684 if (entry && entry->profile) { | |
685 rvProfile = nssSMIMEProfile_AddRef(entry->profile); | |
686 } | |
687 PZ_Unlock(store->lock); | |
688 return rvProfile; | |
689 } | |
690 | |
691 /* XXX this is also used by cache and should be somewhere else */ | |
692 | |
693 static PLHashNumber | |
694 nss_certificate_hash ( | |
695 const void *key | |
696 ) | |
697 { | |
698 unsigned int i; | |
699 PLHashNumber h; | |
700 NSSCertificate *c = (NSSCertificate *)key; | |
701 h = 0; | |
702 for (i=0; i<c->issuer.size; i++) | |
703 h = PR_ROTATE_LEFT32(h, 4) ^ ((unsigned char *)c->issuer.data)[i]; | |
704 for (i=0; i<c->serial.size; i++) | |
705 h = PR_ROTATE_LEFT32(h, 4) ^ ((unsigned char *)c->serial.data)[i]; | |
706 return h; | |
707 } | |
708 | |
709 static int | |
710 nss_compare_certs(const void *v1, const void *v2) | |
711 { | |
712 PRStatus ignore; | |
713 NSSCertificate *c1 = (NSSCertificate *)v1; | |
714 NSSCertificate *c2 = (NSSCertificate *)v2; | |
715 return (int)(nssItem_Equal(&c1->issuer, &c2->issuer, &ignore) && | |
716 nssItem_Equal(&c1->serial, &c2->serial, &ignore)); | |
717 } | |
718 | |
719 NSS_IMPLEMENT nssHash * | |
720 nssHash_CreateCertificate ( | |
721 NSSArena *arenaOpt, | |
722 PRUint32 numBuckets | |
723 ) | |
724 { | |
725 return nssHash_Create(arenaOpt, | |
726 numBuckets, | |
727 nss_certificate_hash, | |
728 nss_compare_certs, | |
729 PL_CompareValues); | |
730 } | |
731 | |
732 NSS_IMPLEMENT void | |
733 nssCertificateStore_DumpStoreInfo ( | |
734 nssCertificateStore *store, | |
735 void (* cert_dump_iter)(const void *, void *, void *), | |
736 void *arg | |
737 ) | |
738 { | |
739 PZ_Lock(store->lock); | |
740 nssHash_Iterate(store->issuer_and_serial, cert_dump_iter, arg); | |
741 PZ_Unlock(store->lock); | |
742 } | |
743 | |
OLD | NEW |