comparison nss/lib/pki/pkistore.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e5118fa0cb1
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
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)