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