security/nss/lib/pki/pkistore.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial